Index: TXM/trunk/bundles/org.txm.ahc.rcp/.project
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/.project	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/.project	(revision 3653)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.txm.ahc.rcp</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/.project
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/messages/messages_fr.properties
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/messages/messages_fr.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/messages/messages_fr.properties	(revision 3653)
@@ -0,0 +1,11 @@
+#TXM messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+common_metric=Métrique
+computeColumns=Classer les colonnes
+computeRows=Classer les lignes
+computingClassificationWithP0=Calcul de la classification de {0}.
+displayChartsIn2D=Afficher les graphiques en 2D
+error_canNotComputeAHCWith=** Impossible de calculer la classification avec seulement {0} parties (le minimum est de 4 parties).
+method=Méthode
+numberOfClusters=Nombre de classes
+numberOfClustersColon=Nombre de classes \:

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/messages/messages_fr.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/messages/AHCUIMessages.java
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/messages/AHCUIMessages.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/messages/AHCUIMessages.java	(revision 3653)
@@ -0,0 +1,41 @@
+package org.txm.ahc.rcp.messages;
+
+import org.eclipse.osgi.util.NLS;
+import org.txm.utils.messages.Utf8NLS;
+
+/**
+ * AHC UI messages.
+ * 
+ * @author mdecorde
+ * @author sjacquot
+ *
+ */
+public class AHCUIMessages extends NLS {
+	
+	
+	private static final String BUNDLE_NAME = "org.txm.ahc.rcp.messages.messages"; //$NON-NLS-1$
+	
+	public static String displayChartsIn2D;
+	
+	public static String numberOfClusters;
+	
+	public static String method;
+	
+	public static String common_metric;
+	
+	public static String computingClassificationWithP0;
+	
+	public static String computeColumns;
+	
+	public static String computeRows;
+	
+	public static String numberOfClustersColon;
+	
+	public static String error_canNotComputeAHCWith;
+	
+	static {
+		Utf8NLS.initializeMessages(BUNDLE_NAME, AHCUIMessages.class);
+	}
+	
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/messages/AHCUIMessages.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/messages/messages.properties
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/messages/messages.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/messages/messages.properties	(revision 3653)
@@ -0,0 +1,11 @@
+#TXM messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+common_metric=Metric
+computeColumns=Cluster columns
+computeRows=Cluster rows
+computingClassificationWithP0=Computing clusters of {0}.
+displayChartsIn2D=Display charts in 2D
+error_canNotComputeAHCWith=** Can not compute clusters with only {0} parts (the minimum is 4 parts).
+method=Method
+numberOfClusters=Number of clusters
+numberOfClustersColon=Number of clusters\:

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/messages/messages.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/editors/AHCEditor.java
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/editors/AHCEditor.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/editors/AHCEditor.java	(revision 3653)
@@ -0,0 +1,216 @@
+package org.txm.ahc.rcp.editors;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Spinner;
+import org.eclipse.swt.widgets.ToolItem;
+import org.txm.ahc.core.functions.AHC;
+import org.txm.ahc.core.preferences.AHCPreferences;
+import org.txm.ahc.rcp.messages.AHCUIMessages;
+import org.txm.ca.core.functions.CA;
+import org.txm.chartsengine.rcp.editors.ChartEditor;
+import org.txm.core.messages.TXMCoreMessages;
+import org.txm.core.preferences.TXMPreferences;
+import org.txm.core.results.Parameter;
+import org.txm.core.results.TXMResult;
+import org.txm.index.core.functions.PartitionIndex;
+import org.txm.lexicaltable.core.functions.LexicalTable;
+import org.txm.rcp.IImageKeys;
+import org.txm.rcp.editors.listeners.ComputeKeyListener;
+import org.txm.rcp.editors.listeners.ComputeSelectionListener;
+import org.txm.rcp.swt.GLComposite;
+import org.txm.rcp.swt.widget.LabeledSpinner;
+import org.txm.rcp.swt.widget.ThresholdsGroup;
+import org.txm.rcp.swt.widget.structures.PropertiesComboViewer;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.corpus.CQPCorpus;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.searchengine.cqp.corpus.Partition;
+
+/**
+ * AHC chart editor.
+ * 
+ * @author mdecorde
+ * @author sjacquot
+ *
+ */
+public class AHCEditor extends ChartEditor<AHC> {
+	
+	
+	/**
+	 * Rows computing button.
+	 */
+	protected ToolItem rowsComputing;
+	
+	/**
+	 * Unit property.
+	 */
+	@Parameter(key = TXMPreferences.UNIT_PROPERTY)
+	protected PropertiesComboViewer unitPropertyComboViewer;
+	
+	/**
+	 * Minimum frequency filtering spinner.
+	 */
+	@Parameter(key = TXMPreferences.F_MIN)
+	protected Spinner fMinSpinner;
+	
+	/**
+	 * Minimum frequency filtering spinner.
+	 */
+	@Parameter(key = TXMPreferences.F_MAX)
+	protected Spinner fMaxSpinner;
+	
+	/**
+	 * Maximum number of lines filtering.
+	 */
+	@Parameter(key = TXMPreferences.V_MAX)
+	protected Spinner vMaxSpinner;
+	
+	
+	/**
+	 * The metric (euclidean, manhattan).
+	 */
+	@Parameter(key = AHCPreferences.METRIC)
+	protected String metric;
+	
+	/**
+	 * The method (METHODS <- c("average", "single", "complete", "ward", "weighted", "flexible")).
+	 */
+	@Parameter(key = AHCPreferences.METHOD)
+	protected String method;
+	
+	/**
+	 * The number of clusters.
+	 */
+	@Parameter(key = AHCPreferences.N_CLUSTERS)
+	protected Spinner numberOfClusters;
+	
+	/**
+	 * To compute the columns or the rows.
+	 */
+	@Parameter(key = AHCPreferences.COLUMNS_COMPUTING)
+	protected ToolItem columnsComputing;
+	
+	/**
+	 * To render in 2D or 3D.
+	 */
+	@Parameter(key = AHCPreferences.RENDERING_2D)
+	protected ToolItem rendering2D;
+	
+	
+	@Override
+	public void __createPartControl() throws Exception {
+		
+		GLComposite mainParametersArea = this.getMainParametersComposite();
+		mainParametersArea.getLayout().numColumns = 4;
+		// parent parameters
+		
+		CA ca = this.getResult().getParent();
+		if (ca.isVisible()) {
+			// ok the CA shows the unitPropertyComboViewer
+		} else {
+			LexicalTable lt = ca.getParent();
+			if (lt.isVisible()) {
+				// ok the LT shows the unitPropertyComboViewer
+			} else {
+				TXMResult parent = lt.getParent();
+				if (parent instanceof PartitionIndex) {
+					// ok the LT shows the unitPropertyComboViewer
+				} else if (parent instanceof Partition) {
+					new Label(mainParametersArea, SWT.NONE).setText(TXMCoreMessages.common_property);
+					this.unitPropertyComboViewer = new PropertiesComboViewer(mainParametersArea, this, false,
+							CQPCorpus.getFirstParentCorpus(this.getResult()).getOrderedProperties(),
+							this.getResult().getUnitProperty(), false);
+				}
+			}
+		}
+//		if (!this.getResult().getParent().isVisible() // CA parent parent is not visible
+//				&& !(this.getResult().getParent().getParent().getParent() instanceof PartitionIndex)) { // and its 2x parent is not a PartitionIndex
+//			// unit property
+//			
+//		}
+		
+		// Extend the chart editor tool bar
+		new ToolItem(this.chartToolBar, SWT.SEPARATOR);
+		
+		
+		// Computing listeners
+		ComputeSelectionListener computeSelectionListener = new ComputeSelectionListener(this, true);
+		// ComputeKeyListener computeKeyListener = new ComputeKeyListener(this);
+		
+		// Number of clusters
+		LabeledSpinner clusters = new LabeledSpinner(mainParametersArea, this, AHCUIMessages.numberOfClustersColon);
+		this.numberOfClusters = clusters.getSpinner();
+		this.numberOfClusters.setMinimum(2);
+		
+		// CLabel clustersLabel = new CLabel(this.chartToolBar, SWT.CENTER);
+		// clustersLabel.setText(AHCUIMessages.numberOfClustersColon);
+		// this.chartToolBar.addControl(clustersLabel);
+		//
+		// this.numberOfClusters = new Spinner(this.chartToolBar, SWT.BORDER);
+		// this.numberOfClusters.setMinimum(2);
+		// this.numberOfClusters.setIncrement(1);
+		// this.chartToolBar.addControl(this.numberOfClusters);
+		// this.numberOfClusters.addKeyListener(computeKeyListener);
+		// this.numberOfClusters.addModifyListener(computeKeyListener);
+		
+		
+		// Columns
+		this.columnsComputing = new ToolItem(this.chartToolBar, SWT.RADIO);
+		this.columnsComputing.setToolTipText(AHCUIMessages.computeColumns);
+		this.columnsComputing.setImage(IImageKeys.getImage(AHCEditor.class, "icons/compute_columns.png")); //$NON-NLS-1$
+		this.columnsComputing.addSelectionListener(computeSelectionListener);
+		
+		// Rows
+		this.rowsComputing = new ToolItem(this.chartToolBar, SWT.RADIO);
+		this.rowsComputing.setToolTipText(AHCUIMessages.computeRows);
+		this.rowsComputing.setImage(IImageKeys.getImage(AHCEditor.class, "icons/compute_rows.png")); //$NON-NLS-1$
+		
+		
+		// 2D/3D rendering
+		this.rendering2D = new ToolItem(this.chartToolBar, SWT.CHECK);
+		this.rendering2D.setText("2D -> 3D"); //$NON-NLS-1$
+		this.rendering2D.addSelectionListener(computeSelectionListener);
+		
+		// FIXME: temporary fix, later must enable the font, rendering mode, etc. in R calls
+		// disable all component of the rendering tool bar
+		this.advancedChartToolBar.setEnabled(false);
+		
+		if (!this.getResult().getParent().isVisible() // CA parent parent is not visible
+				&& !(this.getResult().getParent().getParent().getParent() instanceof PartitionIndex)) { // and its 2x parent is not a PartitionIndex
+			ThresholdsGroup thresholdsGroup = new ThresholdsGroup(this.getExtendedParametersGroup(), SWT.NONE, this, true, true);
+			this.fMinSpinner = thresholdsGroup.getFMinSpinner();
+			this.fMaxSpinner = thresholdsGroup.getFMaxSpinner();
+			this.vMaxSpinner = thresholdsGroup.getVMaxSpinner();
+			this.vMaxSpinner.setMinimum(2);
+			CQPCorpus corpus = getResult().getFirstParent(MainCorpus.class);
+			if (corpus != null) {
+				this.vMaxSpinner.setMaximum(corpus.getSize());
+				this.fMaxSpinner.setMaximum(corpus.getSize());
+				this.fMinSpinner.setMaximum(corpus.getSize());
+			}
+		}
+	}
+	
+	
+	@Override
+	public void updateEditorFromChart(boolean update) {
+		AHC ahc = this.getResult();
+		
+		// Update the maximum value of the number of clusters spinner according to the new AHC configuration
+		this.numberOfClusters.setMaximum(ahc.getMaxClustersCount());
+		
+		// Updates the current value of the number of clusters spinner
+		this.numberOfClusters.setSelection(ahc.getNumberOfClusters());
+		
+		this.rowsComputing.setSelection(!ahc.isColumnsComputing());
+		
+		if (this.getResult().isRendering2D())
+			this.rendering2D.setText("2D -> 3D"); //$NON-NLS-1$
+		else 
+			this.rendering2D.setText("3D -> 2D"); //$NON-NLS-1$
+	}
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/editors/AHCEditor.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/handlers/ComputeAHC.java
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/handlers/ComputeAHC.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/handlers/ComputeAHC.java	(revision 3653)
@@ -0,0 +1,145 @@
+// Copyright © 2010-2020 ENS de Lyon., University of Franche-Comté
+// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
+// Lyon 2, University of Franche-Comté, University of Nice
+// Sophia Antipolis, University of Paris 3.
+//
+// The TXM platform 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 2 of the License, or (at your option) any
+// later version.
+//
+// The TXM platform 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 the TXM platform. If not, see
+// http://www.gnu.org/licenses.
+//
+//
+//
+// $LastChangedDate:$
+// $LastChangedRevision:$
+// $LastChangedBy:$
+//
+package org.txm.ahc.rcp.handlers;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.ahc.core.functions.AHC;
+import org.txm.ahc.core.messages.AHCCoreMessages;
+import org.txm.ahc.rcp.messages.AHCUIMessages;
+import org.txm.ca.core.functions.CA;
+import org.txm.chartsengine.rcp.editors.ChartEditor;
+import org.txm.core.messages.TXMCoreMessages;
+import org.txm.index.core.functions.PartitionIndex;
+import org.txm.lexicaltable.core.functions.LexicalTable;
+import org.txm.rcp.handlers.BaseAbstractHandler;
+import org.txm.searchengine.cqp.corpus.Partition;
+import org.txm.searchengine.cqp.corpus.Property;
+import org.txm.utils.logger.Log;
+
+/**
+ * Opens an AHC editor.
+ * Computes the result if it contains all required parameters.
+ * 
+ * @author mdecorde
+ * @author sjacquot
+ * 
+ */
+public class ComputeAHC extends BaseAbstractHandler {
+	
+	
+	@Override
+	public AHC execute(ExecutionEvent event) throws ExecutionException {
+		
+		if (!this.checkStatsEngine()) {
+			return null;
+		}
+		
+		Object selection = this.getCorporaViewSelectedObject(event);
+		AHC ahc = null;
+		
+		final IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
+		try {
+			// reopening an existing result
+			if (selection instanceof AHC) {
+				ahc = (AHC) selection;
+			}
+			// Creating from CA
+			else if (selection instanceof CA) { // Creating
+				
+				CA ca = (CA) selection;
+				ahc = new AHC(ca);
+			}
+			// Creating from Partition Index
+			else if (selection instanceof PartitionIndex) {
+				
+				PartitionIndex index = (PartitionIndex) selection;
+				LexicalTable lexicalTable = new LexicalTable(index);
+				lexicalTable.setVisible(false);
+				CA ca = new CA(lexicalTable);
+				ca.setVisible(false);
+				ahc = new AHC(ca);
+			}
+			// Creating from Lexical Table
+			else if (selection instanceof LexicalTable) {
+				
+				LexicalTable lexicalTable = (LexicalTable) selection;
+				
+				lexicalTable = (LexicalTable) selection;
+				Property property = lexicalTable.getProperty();
+				
+				// FIXME: SJ: problem here because we need the LT to be computed to make this check
+				if (lexicalTable.hasBeenComputedOnce() && lexicalTable.getNColumns() < 4) {
+					MessageDialog.openError(window.getShell(), AHCCoreMessages.Error, AHCCoreMessages.error_canNotComputeAHCOnLexicalTableWithLessThan4Columns);
+					return null;
+				}
+				// FIXME: SJ: problem here because we need the LT has been computed to make this check
+				if (lexicalTable.hasBeenComputedOnce() && lexicalTable.getNRows() < 4) {
+					MessageDialog.openError(window.getShell(), AHCCoreMessages.Error, AHCCoreMessages.error_canNotComputeAHCWithLessThan4RowsInTheTable);
+					return null;
+				}
+				
+				
+				
+				CA ca = new CA(lexicalTable);
+				ca.setVisible(false);
+				ahc = new AHC(ca);
+			}
+			// Creating from Partition
+			else if (selection instanceof Partition) {
+				
+				Partition partition = (Partition) selection;
+				if (partition.getPartsCount() < 4) {
+					MessageDialog d = new MessageDialog(window.getShell(), TXMCoreMessages.error_error2, null,
+							NLS.bind(AHCUIMessages.error_canNotComputeAHCWith, partition.getPartsCount()), 0, new String[] { TXMCoreMessages.common_ok }, 0);
+					d.open();
+					return null;
+				}
+				
+				
+				LexicalTable lexicalTable = new LexicalTable(partition); // use the CAPreferencePage Fmin
+				lexicalTable.setVisible(false);
+				CA ca = new CA(lexicalTable);
+				ca.setVisible(false);
+				ahc = new AHC(ca);
+			}
+			
+			ChartEditor.openEditor(ahc);
+		}
+		catch (Exception e) {
+			Log.printStackTrace(e);
+			Log.severe(AHCCoreMessages.bind(AHCCoreMessages.failToBuildTheAHCForSelectionP0DbldotP1, selection, e.getMessage()));
+			return null;
+		}
+		return ahc;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/handlers/ComputeAHC.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/handlers/package.html
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/handlers/package.html	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/handlers/package.html	(revision 3653)
@@ -0,0 +1,5 @@
+<html>
+<body>
+	<p>Commands which call textometry functions</p>
+</body>
+</html>
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/handlers/package.html
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/preferences/AHCPreferencePage.java
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/preferences/AHCPreferencePage.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/preferences/AHCPreferencePage.java	(revision 3653)
@@ -0,0 +1,97 @@
+// Copyright © 2010-2020 ENS de Lyon., University of Franche-Comté
+// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
+// Lyon 2, University of Franche-Comté, University of Nice
+// Sophia Antipolis, University of Paris 3.
+// 
+// The TXM platform 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 2 of the License, or (at your option) any
+// later version.
+// 
+// The TXM platform 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 the TXM platform. If not, see
+// http://www.gnu.org/licenses.
+// 
+// 
+// 
+// $LastChangedDate:$
+// $LastChangedRevision:$
+// $LastChangedBy:$ 
+//
+package org.txm.ahc.rcp.preferences;
+
+import org.eclipse.jface.preference.ComboFieldEditor;
+import org.eclipse.jface.preference.IntegerFieldEditor;
+import org.eclipse.jface.preference.RadioGroupFieldEditor;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkbench;
+import org.txm.ahc.core.functions.AHC;
+import org.txm.ahc.core.messages.AHCCoreMessages;
+import org.txm.ahc.core.preferences.AHCPreferences;
+import org.txm.ahc.rcp.adapters.AHCAdapterFactory;
+import org.txm.ahc.rcp.messages.AHCUIMessages;
+import org.txm.chartsengine.rcp.SWTChartsComponentsProvider;
+import org.txm.rcp.preferences.TXMPreferencePage;
+import org.txm.rcp.preferences.TXMPreferenceStore;
+
+/**
+ * CAH preferences page.
+ * 
+ * @author mdecorde
+ * @author sjacquot
+ */
+public class AHCPreferencePage extends TXMPreferencePage {
+	
+	
+	
+	@Override
+	public void createFieldEditors() {
+		
+		IntegerFieldEditor nClusters = new IntegerFieldEditor(AHCPreferences.N_CLUSTERS, AHCUIMessages.numberOfClusters, getFieldEditorParent());
+		addField(nClusters);
+		
+		String list[] = AHC.getMethods();
+		String methods[][] = new String[list.length][2];
+		for (int i = 0; i < list.length; i++)
+			methods[i][0] = methods[i][1] = list[i];
+		
+		ComboFieldEditor method = new ComboFieldEditor(AHCPreferences.METHOD, AHCUIMessages.method, methods, getFieldEditorParent());
+		addField(method);
+		
+		list = AHC.getMetrics();
+		String metrics[][] = new String[list.length][2];
+		for (int i = 0; i < list.length; i++)
+			metrics[i][0] = metrics[i][1] = list[i];
+		
+		ComboFieldEditor metric = new ComboFieldEditor(AHCPreferences.METRIC, AHCUIMessages.common_metric, metrics, getFieldEditorParent());
+		addField(metric);
+		
+		
+		// Charts
+		Composite chartsTab = SWTChartsComponentsProvider.createChartsRenderingPreferencesTabFolderComposite(getFieldEditorParent());
+		
+		String[][] labelAndValues = { { "2D", "true" }, { "3D", "false" } }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+		RadioGroupFieldEditor default2D3Ddisplay = new RadioGroupFieldEditor(AHCPreferences.RENDERING_2D, AHCUIMessages.displayChartsIn2D, 2, labelAndValues, chartsTab);
+		addField(default2D3Ddisplay);
+		
+		
+		// other shared preferences
+		SWTChartsComponentsProvider.createChartsRenderingPreferencesFields(this, chartsTab);
+	}
+	
+	@Override
+	public void init(IWorkbench workbench) {
+		this.setPreferenceStore(new TXMPreferenceStore(AHCPreferences.getInstance().getPreferencesNodeQualifier()));
+		// setDescription("AHC");
+		this.setTitle(AHCCoreMessages.RESULT_TYPE);
+		this.setImageDescriptor(AHCAdapterFactory.ICON);
+	}
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/preferences/AHCPreferencePage.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/adapters/AHCAdapterFactory.java
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/adapters/AHCAdapterFactory.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/adapters/AHCAdapterFactory.java	(revision 3653)
@@ -0,0 +1,46 @@
+// Copyright © 2010-2020 ENS de Lyon., University of Franche-Comté
+package org.txm.ahc.rcp.adapters;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.FrameworkUtil;
+import org.txm.ahc.core.functions.AHC;
+import org.txm.rcp.adapters.TXMResultAdapter;
+import org.txm.rcp.adapters.TXMResultAdapterFactory;
+
+/**
+ * A factory for creating Adapter objects.
+ * 
+ * @author mdecorde
+ * @author sjacquot
+ */
+public class AHCAdapterFactory extends TXMResultAdapterFactory {
+	
+	
+	public static final ImageDescriptor ICON = AbstractUIPlugin.imageDescriptorFromPlugin(FrameworkUtil.getBundle(AHCAdapterFactory.class).getSymbolicName(),
+			"platform:/plugin/" + FrameworkUtil.getBundle(AHCAdapterFactory.class).getSymbolicName() + "/icons/cah.png"); //$NON-NLS-1$ //$NON-NLS-2$
+	
+	/**
+	 * Gets the adapter.
+	 *
+	 * @param adaptableObject the adaptable object
+	 * @param adapterType the adapter type
+	 * @return the adapter
+	 * @see org.eclipse.core.runtime.IAdapterFactory#getAdapter(java.lang.Object, java.lang.Class)
+	 */
+	@Override
+	public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) {
+		if (this.canAdapt(adapterType) && adaptableObject instanceof AHC) {
+			return adapterType.cast(new TXMResultAdapter() {
+				
+				@Override
+				public ImageDescriptor getImageDescriptor(Object object) {
+					return ICON;
+				}
+			});
+		}
+		return null;
+	}
+	
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/src/org/txm/ahc/rcp/adapters/AHCAdapterFactory.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/build.properties
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/build.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/build.properties	(revision 3653)
@@ -0,0 +1,9 @@
+#Fri Jul 06 10:25:02 CEST 2018
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml,\
+               icons/,\
+               OSGI-INF/
+output..=bin/
+source..=src/
+#qualifier=svn

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/build.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle_ru.properties
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle_ru.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle_ru.properties	(revision 3653)
@@ -0,0 +1,6 @@
+#TXM OSGI messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+command.name=ÐÐ»Ð°ÑÑÐµÑÐ¸Ð·Ð°ÑÐ¸Ñ
+command.tooltip=ÐÑÐ¿Ð¾Ð»Ð½Ð¸ÑÑ ÐÐ»Ð°ÑÑÐµÑÐ¸Ð·Ð°ÑÐ¸Ñ
+editor.name=ÐÐ»Ð°ÑÑÐµÑÐ¸Ð·Ð°ÑÐ¸Ñ
+page.name=ÐÐ»Ð°ÑÑÐµÑÐ¸Ð·Ð°ÑÐ¸Ñ

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle_ru.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle_fr.properties
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle_fr.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle_fr.properties	(revision 3653)
@@ -0,0 +1,6 @@
+#TXM OSGI messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+command.name=Classification
+command.tooltip=Calculer la classification
+editor.name=Classification
+page.name=Classification

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle_fr.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle_ru_utf-8.properties
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle_ru_utf-8.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle_ru_utf-8.properties	(revision 3653)
@@ -0,0 +1,5 @@
+#TXM OSGI messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+command.name=Классификация
+command.tooltip=Классификация
+page.name=Классификация

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle_ru_utf-8.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle.properties
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle.properties	(revision 3653)
@@ -0,0 +1,7 @@
+#TXM OSGI messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+Bundle-Name=AHC RCP
+command.name=Cluster Analysis
+command.tooltip=Compute clustering
+editor.name=Cluster Analysis
+page.name=Cluster Analysis

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/OSGI-INF/l10n/bundle.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/icons/compute_rows.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/icons/compute_rows.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.ahc.rcp/icons/cah.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/icons/cah.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.ahc.rcp/icons/compute_columns.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/icons/compute_columns.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.ahc.rcp/plugin.xml
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/plugin.xml	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/plugin.xml	(revision 3653)
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>  
+   <extension
+         point="org.eclipse.ui.commands">
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.ahc.rcp.handlers.ComputeAHC"
+            id="org.txm.cah.rcp.handlers.ComputeAHC"
+            name="%command.name"
+            returnTypeId="org.txm.ahc.core.functions.AHC">
+      </command>
+   </extension>
+   <extension
+         point="org.eclipse.ui.menus">
+      <menuContribution
+            allPopups="false"
+            locationURI="toolbar:org.txm.rcp.toolbartools?after=org.txm.ca.rcp.handlers.ComputeCA">
+         <command
+               commandId="org.txm.cah.rcp.handlers.ComputeAHC"
+               icon="icons/cah.png"
+               style="push"
+               tooltip="%command.name">
+            <visibleWhen
+                  checkEnabled="false">
+               <or>
+                  <reference
+                        definitionId="OneCASelected">
+                  </reference>
+                  <reference
+                        definitionId="OneLexicalTableSelected">
+                  </reference>
+                  <reference
+                        definitionId="OnePartitionSelected">
+                  </reference>
+                  <reference
+                        definitionId="OnePartitionIndexSelected">
+                  </reference>
+               </or>
+            </visibleWhen>
+         </command>
+      </menuContribution>
+      <menuContribution
+            allPopups="false"
+            locationURI="popup:org.txm.rcp.views.corpora.CorporaView?after=org.txm.ca.rcp.handlers.ComputeCA">
+         <command
+               commandId="org.txm.cah.rcp.handlers.ComputeAHC"
+               icon="icons/cah.png"
+               style="push"
+               tooltip="%command.name">
+            <visibleWhen
+                  checkEnabled="false">
+               <or>
+                  <reference
+                        definitionId="OneCASelected">
+                  </reference>
+                  <reference
+                        definitionId="OneLexicalTableSelected">
+                  </reference>
+                  <reference
+                        definitionId="OnePartitionSelected">
+                  </reference>
+                  <reference
+                        definitionId="OnePartitionIndexSelected">
+                  </reference>
+               </or>
+            </visibleWhen>
+         </command>
+      </menuContribution>
+      <menuContribution
+            locationURI="menu:menu.tools?after=org.txm.ca.rcp.handlers.ComputeCA">
+         <command
+               commandId="org.txm.cah.rcp.handlers.ComputeAHC"
+               icon="icons/cah.png"
+               style="push"
+               tooltip="%command.name">
+            <visibleWhen
+                  checkEnabled="false">
+               <or>
+                  <reference
+                        definitionId="OneCASelected">
+                  </reference>
+                  <reference
+                        definitionId="OneLexicalTableSelected">
+                  </reference>
+                  <reference
+                        definitionId="OnePartitionSelected">
+                  </reference>
+                  <reference
+                        definitionId="OnePartitionIndexSelected">
+                  </reference>
+               </or>
+            </visibleWhen>
+         </command>
+      </menuContribution>
+   </extension>
+   <extension
+         point="org.eclipse.ui.editors">
+      <editor
+            class="org.txm.ahc.rcp.editors.AHCEditor"
+            default="false"
+            icon="icons/cah.png"
+            id="org.txm.ahc.core.functions.AHC"
+            name="%editor.name">
+      </editor>
+   </extension>
+   <extension
+         point="org.eclipse.core.runtime.adapters">
+      <factory
+            adaptableType="org.txm.ahc.core.functions.AHC"
+            class="org.txm.ahc.rcp.adapters.AHCAdapterFactory">
+         <adapter
+               type="org.eclipse.ui.model.IWorkbenchAdapter">
+         </adapter>
+         <adapter
+               type="org.eclipse.ui.model.IWorkbenchAdapter2">
+         </adapter>
+      </factory>
+   </extension>
+   <extension
+         point="org.eclipse.ui.preferencePages">
+      <page
+            category="org.txm.rcp.preferences.UserPreferencePage"
+            class="org.txm.ahc.rcp.preferences.AHCPreferencePage"
+            id="org.txm.cah.rcp.preferences.CAHPreferencePage"
+            name="%page.name">
+      </page>
+   </extension>
+   <extension
+         point="org.eclipse.core.expressions.definitions">
+      <definition
+            id="OneCAHSelected">
+         <with
+               variable="corporaSelection">
+            <iterate
+                  ifEmpty="false"
+                  operator="and">
+               <instanceof
+                     value="org.txm.ahc.core.functions.AHC">
+               </instanceof>
+            </iterate>
+         </with>
+      </definition>
+   </extension>
+
+</plugin>

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/plugin.xml
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/.settings/org.eclipse.core.resources.prefs
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/.settings/org.eclipse.core.resources.prefs	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/.settings/org.eclipse.core.resources.prefs	(revision 3653)
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding//src/org/txm/ahc/rcp/messages/messages_fr.properties=UTF-8

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/.settings/org.eclipse.core.resources.prefs
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/.classpath
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/.classpath	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/.classpath	(revision 3653)
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con"
+		path="org.eclipse.jdt.launching.JRE_CONTAINER" />
+	<classpathentry kind="con"
+		path="org.eclipse.pde.core.requiredPlugins">
+		<accessrules>
+			<accessrule kind="accessible" pattern="**" />
+		</accessrules>
+	</classpathentry>
+	<classpathentry kind="src" path="src" />
+	<classpathentry kind="output" path="bin" />
+</classpath>
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/.classpath
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.rcp/META-INF/MANIFEST.MF
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.rcp/META-INF/MANIFEST.MF	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.rcp/META-INF/MANIFEST.MF	(revision 3653)
@@ -0,0 +1,16 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: org.txm.ahc.rcp
+Export-Package: org.txm.ahc.rcp.adapters,org.txm.ahc.rcp.editors,org.t
+ xm.ahc.rcp.handlers,org.txm.ahc.rcp.messages,org.txm.ahc.rcp.preferen
+ ces
+Bundle-SymbolicName: org.txm.ahc.rcp;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Name: %Bundle-Name
+Require-Bundle: org.txm.chartsengine.rcp;bundle-version="1.0.0";visibi
+ lity:=reexport,org.txm.lexicaltable.rcp;bundle-version="1.0.0";visibi
+ lity:=reexport,org.txm.ahc.core;bundle-version="1.0.0";visibility:=re
+ export,org.txm.ca.rcp;visibility:=reexport
+Bundle-ManifestVersion: 2
+Bundle-RequiredExecutionEnvironment: JavaSE-16
+Bundle-Vendor: Textometrie.org
+

Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp/META-INF/MANIFEST.MF
___________________________________________________________________
Added: svn:mime-type
   + text/plain


Property changes on: TXM/trunk/bundles/org.txm.ahc.rcp
___________________________________________________________________
Added: svn:ignore
   + bin

target


Index: TXM/trunk/bundles/org.txm.annotation.core/OSGI-INF/l10n/bundle.properties
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.core/OSGI-INF/l10n/bundle.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.core/OSGI-INF/l10n/bundle.properties	(revision 3653)
@@ -0,0 +1,5 @@
+#Properties file for org.txm.annotation.core
+EngineManager.description = Annotation engines manager
+extension-point.name = org.txm.annotation.core.AnnotationEngine
+Bundle-Vendor = Textometrie.org
+Bundle-Name = Annotation Core
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.annotation.core/OSGI-INF/l10n/bundle.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.core/plugin.xml
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.core/plugin.xml	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.core/plugin.xml	(revision 3653)
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>  
+   <extension-point id="org.txm.annotation.core.AnnotationEngine" name="org.txm.annotation.core.AnnotationEngine" schema="schema/org.txm.annotation.core.AnnotationEngine.exsd"/>
+   <extension
+         point="org.eclipse.core.runtime.preferences">
+      <initializer
+            class="org.txm.annotation.core.preferences.AnnotationPreferences">
+      </initializer>
+   </extension>
+   <extension
+         point="org.txm.core.engines.EnginesManager">
+      <EngineManager
+            class="org.txm.annotation.core.AnnotationEnginesManager"
+            description="Annotation engines manager"
+            name="Annotation">
+      </EngineManager>
+   </extension>
+
+</plugin>

Property changes on: TXM/trunk/bundles/org.txm.annotation.core/plugin.xml
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.core/.classpath
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.core/.classpath	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.core/.classpath	(revision 3653)
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con"
+		path="org.eclipse.jdt.launching.JRE_CONTAINER" />
+	<classpathentry exported="true" kind="con"
+		path="org.eclipse.pde.core.requiredPlugins">
+		<accessrules>
+			<accessrule kind="accessible" pattern="**" />
+		</accessrules>
+	</classpathentry>
+	<classpathentry kind="src" path="src" />
+	<classpathentry kind="output" path="bin" />
+</classpath>
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.annotation.core/.classpath
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.core/META-INF/MANIFEST.MF
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.core/META-INF/MANIFEST.MF	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.core/META-INF/MANIFEST.MF	(revision 3653)
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: org.txm.annotation.core
+Bundle-SymbolicName: org.txm.annotation.core;singleton:=true
+Require-Bundle: org.txm.core;bundle-version="0.7.0";visibility:=reexport
+Bundle-ActivationPolicy: lazy
+Bundle-ManifestVersion: 2
+Bundle-RequiredExecutionEnvironment: JavaSE-16
+Bundle-Vendor: Textometrie.org
+Export-Package: org.txm.annotation.core,org.txm.annotation.core.prefer
+ ences
+Bundle-Version: 1.0.0.qualifier
+Bundle-Name: Annotation Core
+Bundle-ClassPath: .
+Bundle-Activator: org.txm.annotation.core.Activator
+

Property changes on: TXM/trunk/bundles/org.txm.annotation.core/META-INF/MANIFEST.MF
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.core/schema/org.txm.annotation.core.AnnotationEngine.exsd
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.core/schema/org.txm.annotation.core.AnnotationEngine.exsd	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.core/schema/org.txm.annotation.core.AnnotationEngine.exsd	(revision 3653)
@@ -0,0 +1,109 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.txm.annotation.core" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema plugin="org.txm.annotation.core" id="org.txm.annotation.core.AnnotationEngine" name="org.txm.annotation.core.AnnotationEngine"/>
+      </appinfo>
+      <documentation>
+         Annotation engine
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <choice minOccurs="1" maxOccurs="unbounded">
+            <element ref="AnnotationEngine"/>
+         </choice>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="AnnotationEngine">
+      <complexType>
+         <attribute name="class" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="java" basedOn="org.txm.annotation.core.AnnotationEngine:"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+         <attribute name="description" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="since"/>
+      </appinfo>
+      <documentation>
+         [Enter the first release in which this extension point appears.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="examples"/>
+      </appinfo>
+      <documentation>
+         [Enter extension point usage example here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="apiinfo"/>
+      </appinfo>
+      <documentation>
+         [Enter API information here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="implementation"/>
+      </appinfo>
+      <documentation>
+         [Enter information about supplied implementation of this extension point.]
+      </documentation>
+   </annotation>
+
+
+</schema>

Property changes on: TXM/trunk/bundles/org.txm.annotation.core/schema/org.txm.annotation.core.AnnotationEngine.exsd
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.core/.project
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.core/.project	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.core/.project	(revision 3653)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.txm.annotation.core</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

Property changes on: TXM/trunk/bundles/org.txm.annotation.core/.project
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/preferences/AnnotationPreferences.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/preferences/AnnotationPreferences.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/preferences/AnnotationPreferences.java	(revision 3653)
@@ -0,0 +1,36 @@
+package org.txm.annotation.core.preferences;
+
+
+import org.osgi.service.prefs.Preferences;
+import org.txm.core.preferences.TXMPreferences;
+
+/**
+ * Preferences initializer and manager.
+ * 
+ * @author mdecorde
+ * @author sjacquot
+ *
+ */
+public class AnnotationPreferences extends TXMPreferences {
+	
+	
+	
+	/**
+	 * Gets the instance.
+	 * 
+	 * @return the instance
+	 */
+	public static TXMPreferences getInstance() {
+		if (!TXMPreferences.instances.containsKey(AnnotationPreferences.class)) {
+			new AnnotationPreferences();
+		}
+		return TXMPreferences.instances.get(AnnotationPreferences.class);
+	}
+	
+	
+	@Override
+	public void initializeDefaultPreferences() {
+		super.initializeDefaultPreferences();
+		Preferences preferences = this.getDefaultPreferencesNode();
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/preferences/AnnotationPreferences.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/Activator.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/Activator.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/Activator.java	(revision 3653)
@@ -0,0 +1,19 @@
+package org.txm.annotation.core;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator {
+	
+	@Override
+	public void start(BundleContext context) throws Exception {
+		// TODO Auto-generated method stub
+		
+	}
+	
+	@Override
+	public void stop(BundleContext context) throws Exception {
+		// TODO Auto-generated method stub
+		
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/Activator.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/AnnotationEnginesManager.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/AnnotationEnginesManager.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/AnnotationEnginesManager.java	(revision 3653)
@@ -0,0 +1,153 @@
+package org.txm.annotation.core;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.osgi.util.NLS;
+import org.txm.Toolbox;
+import org.txm.core.engines.EngineType;
+import org.txm.core.engines.EnginesManager;
+import org.txm.objects.CorpusBuild;
+import org.txm.objects.Project;
+import org.txm.utils.logger.Log;
+
+
+/**
+ * 
+ * @author mdecorde, sjacquot
+ * 
+ *         FIXME: SJ: useless class, the type and priority/order should be defined in org.txm.core.engines.EnginesManager extension point
+ **/
+public class AnnotationEnginesManager extends EnginesManager<AnnotationEngine> {
+	
+	public AnnotationEnginesManager() {
+		
+	}
+	
+	@Override
+	public boolean startEngines(IProgressMonitor monitor) {
+		
+		for (AnnotationEngine e : values()) {
+			
+			// lazy mode
+			
+			// AnnotationEngine se = (AnnotationEngine)e;
+			// if (monitor != null) monitor.subTask("Starting "+ se.getName()+" annotation engine.");
+			// try {
+			// se.start(monitor);
+			// } catch (Exception ex) {
+			// System.out.println("Error: failed to start annotation engine: "+se.getName()+": "+ex.getLocalizedMessage());
+			// }
+		}
+		return true;
+	}
+	
+	/**
+	 * Check all AnnotationEngine s and call ae.hasAnnotationsToSave(corpus)
+	 * 
+	 * @param corpus
+	 * @return true if any AnnotationEngine have annotations to save
+	 */
+	public boolean hasAnnotationsToSave(CorpusBuild corpus) {
+		boolean todo = false;
+		for (AnnotationEngine engine : this.getEngines().values()) {
+			AnnotationEngine ae = engine;
+			todo = todo || ae.hasAnnotationsToSave(corpus);
+		}
+		return todo;
+	}
+	
+	@Override
+	public boolean stopEngines() {
+		for (AnnotationEngine e : values()) {
+			// System.out.println(e);
+			AnnotationEngine se = e;
+			Log.fine("Stoping " + se.getName() + " annotation engine.");
+			try {
+				se.stop();
+			}
+			catch (Exception ex) {
+				Log.severe("Error: failed to stop annotation engine: " + se.getName() + ": " + ex.getLocalizedMessage());
+			}
+		}
+		return true;
+	}
+	
+	@Override
+	public EngineType getEnginesType() {
+		return EngineType.ANNOTATION;
+	}
+	
+	@Override
+	public boolean fetchEngines() {
+		
+		IConfigurationElement[] contributions = Platform.getExtensionRegistry().getConfigurationElementsFor(AnnotationEngine.EXTENSION_POINT_ID);
+		// System.out.println("search engine contributions: "+SearchEngine.EXTENSION_POINT_ID);
+		for (int i = 0; i < contributions.length; i++) {
+			try {
+				AnnotationEngine e = (AnnotationEngine) contributions[i].createExecutableExtension("class"); //$NON-NLS-1$
+				if (e.initialize()) {
+					put(e.getName(), e);
+				}
+				else {
+					Log.warning(NLS.bind("Fail to initialize the {0} annotation engine.", e.getName()));
+				}
+			}
+			catch (Exception e) {
+				Log.warning(NLS.bind("Fail to instanciate {0}: {1}", contributions[i].getName(), e.getLocalizedMessage()));
+				Log.printStackTrace(e);
+			}
+		}
+		
+		return size() > 0;
+	}
+	
+	public boolean isSaveNeeded() {
+		
+		for (AnnotationEngine a : values()) {
+			for (Project project : Toolbox.workspace.getProjects()) {
+				for (CorpusBuild corpus : project.getCorpora()) {
+					if (a.hasAnnotationsToSave(corpus)) {
+						return true;
+					}
+				}
+			}
+		}
+		return false;
+	}
+
+	public List<AnnotationEngine> getEnginesWithSaveNeeded() {
+		
+		List<AnnotationEngine> tmp = new ArrayList<AnnotationEngine>();
+		for (AnnotationEngine a : values()) {
+			for (Project project : Toolbox.workspace.getProjects()) {
+				for (CorpusBuild corpus : project.getCorpora()) {
+					if (a.hasAnnotationsToSave(corpus)) {
+						tmp.add(a);
+					}
+				}
+			}
+		}
+		return tmp;
+	}
+	
+	public HashMap<CorpusBuild, ArrayList<AnnotationEngine>> getEnginesWithSaveNeededPerCorpus() {
+		
+		HashMap<CorpusBuild, ArrayList<AnnotationEngine>> tmp = new HashMap<CorpusBuild, ArrayList<AnnotationEngine>>();
+		for (AnnotationEngine a : values()) {
+			for (Project project : Toolbox.workspace.getProjects()) {
+				for (CorpusBuild corpus : project.getCorpora()) {
+					if (a.hasAnnotationsToSave(corpus)) {
+						if (!tmp.containsKey(corpus)) tmp.put(corpus, new ArrayList<>());
+						tmp.get(corpus).add(a);
+					}
+				}
+			}
+		}
+		return tmp;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/AnnotationEnginesManager.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/AnnotationEngine.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/AnnotationEngine.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/AnnotationEngine.java	(revision 3653)
@@ -0,0 +1,93 @@
+package org.txm.annotation.core;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.HashMap;
+
+import org.txm.core.engines.Engine;
+import org.txm.objects.CorpusBuild;
+import org.txm.tokenizer.SimpleStringTokenizer;
+import org.txm.tokenizer.StringTokenizer;
+import org.txm.utils.ConsoleProgressBar;
+import org.txm.utils.DeleteDir;
+import org.txm.utils.logger.Log;
+
+public abstract class AnnotationEngine implements Engine {
+	
+	public static final String EXTENSION_POINT_ID = AnnotationEngine.class.getCanonicalName();
+	
+	@Override
+	public abstract String getName();
+	
+	/**
+	 * 
+	 * @return true if the Annotation Engine can be used in the "importer" step of import modules
+	 */
+	public abstract boolean isAutomatic();
+	
+	/**
+	 * 
+	 * @return true if the Annotation Engine has some annotations not saved (that will be lost if not saved)
+	 */
+	public abstract boolean hasAnnotationsToSave(CorpusBuild corpus);
+		
+	/**
+	 * 
+	 * @return a StringTokenizer, override this method if the engine needs a speciq tokenization
+	 * @throws Exception
+	 */
+	public StringTokenizer getStringTokenizer(String lang) throws Exception {
+		return new SimpleStringTokenizer(lang);
+	}
+	
+	/**
+	 * Automatically annotate a XML-TXM file
+	 * 
+	 * @param xmlFile to annotate
+	 * @param binaryCorpusDirectory
+	 * @param parameters
+	 * @return
+	 */
+	public abstract boolean processFile(File xmlFile, File binaryCorpusDirectory, HashMap<String, Object> parameters);
+	
+	/**
+	 * 
+	 * @param xmlFilesDirectory contains the *.xml files to process
+	 * @param binaryCorpusDirectory the output directory
+	 * @param parameters ["lang": model_file_name_without_extension]
+	 * @return
+	 */
+	public boolean processDirectory(File xmlFilesDirectory, File binaryCorpusDirectory, HashMap<String, Object> parameters) {
+		File[] files = xmlFilesDirectory.listFiles(new FileFilter() {
+			
+			@Override
+			public boolean accept(File pathname) {
+				return pathname.isFile() && !pathname.isHidden() && !pathname.getName().startsWith(".") && pathname.getName().endsWith(".xml");
+			}
+		});
+		if (files == null || files.length == 0) {
+			Log.warning("Error: no suitable file to process in " + xmlFilesDirectory);
+			return false;
+		}
+		boolean ret = true;
+		ConsoleProgressBar cpb = new ConsoleProgressBar(files.length);
+		
+		File annotDir = new File(binaryCorpusDirectory, "annotations");
+		DeleteDir.deleteDirectory(annotDir);
+		annotDir.mkdir();
+		File ptreetaggerDir = new File(binaryCorpusDirectory, "ptreetagger");
+		DeleteDir.deleteDirectory(ptreetaggerDir);
+		ptreetaggerDir.mkdir();
+		File treetaggerDir = new File(binaryCorpusDirectory, "treetagger");
+		DeleteDir.deleteDirectory(treetaggerDir);
+		treetaggerDir.mkdir();
+		
+		for (File xmlFile : files) {
+			ret = processFile(xmlFile, binaryCorpusDirectory, parameters) && ret;
+			
+			cpb.tick();
+		}
+		cpb.done();
+		return ret;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.core/src/org/txm/annotation/core/AnnotationEngine.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.core/libs/sqlite-jdbc-3.8.11.2.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.annotation.core/libs/sqlite-jdbc-3.8.11.2.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.annotation.core/libs/postgresql-9.4.1207.jre6.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.annotation.core/libs/postgresql-9.4.1207.jre6.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.annotation.core/libs/hsqldb.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.annotation.core/libs/hsqldb.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.annotation.core/build.properties
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.core/build.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.core/build.properties	(revision 3653)
@@ -0,0 +1,9 @@
+#Fri Jul 06 10:25:02 CEST 2018
+output..=bin/
+bin.includes = plugin.xml,\
+               META-INF/,\
+               .,\
+               libs/,\
+               OSGI-INF/
+source..=src/
+#qualifier=svn

Property changes on: TXM/trunk/bundles/org.txm.annotation.core/build.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain


Property changes on: TXM/trunk/bundles/org.txm.annotation.core
___________________________________________________________________
Added: svn:ignore
   + bin

target


Index: TXM/trunk/bundles/org.txm.ahc.core/build.properties
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/build.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/build.properties	(revision 3653)
@@ -0,0 +1,9 @@
+#Fri Jul 06 10:25:01 CEST 2018
+output..=bin/
+
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml,\
+               OSGI-INF/
+source..=src/
+#qualifier=svn

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/build.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/OSGI-INF/l10n/bundle.properties
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/OSGI-INF/l10n/bundle.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/OSGI-INF/l10n/bundle.properties	(revision 3653)
@@ -0,0 +1,4 @@
+#TXM OSGI messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+Bundle-Name=AHC Core
+Bundle-Vendor=Textometrie.org

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/OSGI-INF/l10n/bundle.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/plugin.xml
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/plugin.xml	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/plugin.xml	(revision 3653)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>  
+   <extension
+         point="org.eclipse.core.runtime.preferences">
+      <initializer
+            class="org.txm.ahc.core.preferences.AHCPreferences">
+      </initializer>
+   </extension>
+   <extension
+         point="org.txm.chartsengine.chartcreator">
+      <ChartCreator
+            class="org.txm.ahc.core.chartsengine.r.RAHCChartCreator"
+            fileNamePrefix="ahc">
+      </ChartCreator>
+   </extension>
+
+</plugin>

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/plugin.xml
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/.settings/org.eclipse.core.resources.prefs
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/.settings/org.eclipse.core.resources.prefs	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/.settings/org.eclipse.core.resources.prefs	(revision 3653)
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding//src/org/txm/ahc/core/messages/messages_fr.properties=UTF-8

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/.settings/org.eclipse.core.resources.prefs
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/.classpath
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/.classpath	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/.classpath	(revision 3653)
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con"
+		path="org.eclipse.jdt.launching.JRE_CONTAINER" />
+	<classpathentry kind="con"
+		path="org.eclipse.pde.core.requiredPlugins">
+		<accessrules>
+			<accessrule kind="accessible" pattern="**" />
+		</accessrules>
+	</classpathentry>
+	<classpathentry kind="src" path="src" />
+	<classpathentry kind="output" path="bin" />
+</classpath>
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/.classpath
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/META-INF/MANIFEST.MF
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/META-INF/MANIFEST.MF	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/META-INF/MANIFEST.MF	(revision 3653)
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: org.txm.ahc.core
+Export-Package: org.txm.ahc.core.chartsengine.jfreechart,org.txm.ahc.c
+ ore.chartsengine.r,org.txm.ahc.core.functions,org.txm.ahc.core.messag
+ es,org.txm.ahc.core.preferences
+Bundle-SymbolicName: org.txm.ahc.core;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Name: AHC Core
+Require-Bundle: org.txm.ca.core;bundle-version="1.0.0";visibility:=ree
+ xport
+Bundle-ActivationPolicy: lazy
+Bundle-ManifestVersion: 2
+Bundle-RequiredExecutionEnvironment: JavaSE-16
+Bundle-Vendor: Textometrie.org
+

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/META-INF/MANIFEST.MF
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/.project
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/.project	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/.project	(revision 3653)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.txm.ahc.core</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/.project
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/AHCCoreMessages.java
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/AHCCoreMessages.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/AHCCoreMessages.java	(revision 3653)
@@ -0,0 +1,56 @@
+package org.txm.ahc.core.messages;
+
+import org.eclipse.osgi.util.NLS;
+import org.txm.utils.messages.Utf8NLS;
+
+/**
+ * AHC core messages.
+ * 
+ * @author mdecorde
+ * @author sjacquot
+ *
+ */
+public class AHCCoreMessages extends NLS {
+	
+	private static final String BUNDLE_NAME = "org.txm.ahc.core.messages.messages"; //$NON-NLS-1$
+	
+	public static String AHC_computedWithTheP0MethodAndTheP1Metric;
+
+	public static String P0classesOfP1;
+	
+	public static String columns;
+	
+	public static String rows;
+	
+	public static String RESULT_TYPE;
+	
+	public static String error_error2;
+
+	public static String error_errorWhileExportingCAHToTXT;
+	
+	public static String common_ok;
+
+	public static String computingAHC;
+
+	public static String Error;
+	
+	public static String info_ahcOfTheP0PartitionCommaP1Property;
+	
+	public static String info_ahcOfTheP0LexcialTable;
+	
+	public static String info_ahcOfTheP0ca;
+	
+	public static String error_canNotComputeAHCOnLexicalTableWithLessThan4Columns;
+	
+	public static String error_canNotComputeAHCWith;
+
+	public static String error_canNotComputeAHCWithLessThan4RowsInTheTable;
+
+	public static String failToBuildTheAHCForSelectionP0DbldotP1;
+	
+	
+	
+	static {
+		Utf8NLS.initializeMessages(BUNDLE_NAME, AHCCoreMessages.class);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/AHCCoreMessages.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/messages.properties
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/messages.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/messages.properties	(revision 3653)
@@ -0,0 +1,19 @@
+#TXM messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+AHC_computedWithTheP0MethodAndTheP1Metric=\ computed with the {0} method and the {1} metric.
+columns=columns
+common_ok=
+computingAHC=Computing clustering…
+Error=Error
+error_canNotComputeAHCOnLexicalTableWithLessThan4Columns=** Can not compute clustering on a lexical table with less than 4 columns in the table
+error_canNotComputeAHCWith=
+error_canNotComputeAHCWithLessThan4RowsInTheTable=** Can not compute clustering with less than 4 rows in the table
+error_error2=
+error_errorWhileExportingCAHToTXT=** Error while exporting clustering result.
+failToBuildTheAHCForSelectionP0DbldotP1=Failed to build the clustering of the selection {0}: {1}
+info_ahcOfTheP0ca=Clustering based on the {0} Correspondence analysis…
+info_ahcOfTheP0LexcialTable=Clustering of the {0} lexical table...
+info_ahcOfTheP0PartitionCommaP1Property=Clustering of partition {0} on property {1}...
+P0classesOfP1={0} clusters of {1}.
+RESULT_TYPE=HCA
+rows=rows

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/messages.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/messages_fr.properties
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/messages_fr.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/messages_fr.properties	(revision 3653)
@@ -0,0 +1,19 @@
+#TXM messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+AHC_computedWithTheP0MethodAndTheP1Metric=\ calculée avec la méthode {0} et la métrique {1}.
+columns=colonnes
+common_ok=
+computingAHC=Calcul de la classification…
+Error=Erreur
+error_canNotComputeAHCOnLexicalTableWithLessThan4Columns=** Impossible de calculer une classification avec moins de 4 colonnes dans la table
+error_canNotComputeAHCWith=
+error_canNotComputeAHCWithLessThan4RowsInTheTable=** Impossible de calculer une classification avec moins de 4 lignes dans la table
+error_error2=null
+error_errorWhileExportingCAHToTXT=** Erreur durant l'exportation du résultat de la classification.
+failToBuildTheAHCForSelectionP0DbldotP1=Échec de la construction de la classification de la sélection  {0} : {1}
+info_ahcOfTheP0ca=Classification basée sur l'Analyse des correspondances {0}...
+info_ahcOfTheP0LexcialTable=Classification de la table lexicale {0}...
+info_ahcOfTheP0PartitionCommaP1Property=Classification de la partition {0} selon la propriété {1}...
+P0classesOfP1={0} classes de {1}.
+RESULT_TYPE=CAH
+rows=lignes

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/messages_fr.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/messages_ru2.properties
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/messages_ru2.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/messages_ru2.properties	(revision 3653)
@@ -0,0 +1,3 @@
+#TXM messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+RESULT_TYPE=Классификация

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/messages/messages_ru2.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/functions/AHC.java
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/functions/AHC.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/functions/AHC.java	(revision 3653)
@@ -0,0 +1,783 @@
+// Copyright © 2010-2020 ENS de Lyon., University of Franche-Comté
+// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
+// Lyon 2, University of Franche-Comté, University of Nice
+// Sophia Antipolis, University of Paris 3.
+//
+// The TXM platform 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 2 of the License, or (at your option) any
+// later version.
+//
+// The TXM platform 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 the TXM platform. If not, see
+// http://www.gnu.org/licenses.
+//
+//
+//
+// $LastChangedDate:$
+// $LastChangedRevision:$
+// $LastChangedBy:$
+//
+package org.txm.ahc.core.functions;
+
+import java.io.File;
+import java.util.Arrays;
+
+import org.eclipse.osgi.util.NLS;
+import org.rosuda.REngine.REXP;
+import org.txm.ahc.core.messages.AHCCoreMessages;
+import org.txm.ahc.core.preferences.AHCPreferences;
+import org.txm.ca.core.functions.CA;
+import org.txm.chartsengine.core.results.ChartResult;
+import org.txm.core.messages.TXMCoreMessages;
+import org.txm.core.results.Parameter;
+import org.txm.core.results.TXMParameters;
+import org.txm.lexicaltable.core.functions.LexicalTable;
+import org.txm.searchengine.cqp.corpus.Property;
+import org.txm.statsengine.r.core.RResult;
+import org.txm.statsengine.r.core.RWorkspace;
+import org.txm.statsengine.r.core.exceptions.RWorkspaceException;
+import org.txm.utils.TXMProgressMonitor;
+import org.txm.utils.logger.Log;
+
+/**
+ * Agglomerative Hierarchical Clustering.
+ * 
+ * @author mdecorde
+ * @author sjacquot
+ *
+ */
+public class AHC extends ChartResult implements RResult {
+	
+	/**
+	 * The R name prefix.
+	 */
+	protected static String prefixR = "FactoMineRAHC"; //$NON-NLS-1$
+	
+	/**
+	 * Counter used in name suffix.
+	 */
+	protected static int ahcCounter = 1;
+	
+	
+	/** The symbol. */
+	String symbol = null;
+	
+	/** The CA symbol target. */
+	String target;
+	
+	
+	/**
+	 * The coordinates of the clusters.
+	 */
+	protected double[][] clusterCoords = null;
+	
+	/**
+	 * The numbers of the clusters.
+	 */
+	protected int[] clusterNumbers = null;
+	
+	/**
+	 * The names of the cluster rows.
+	 */
+	protected String[] clusterRowNames = null;
+	
+	/**
+	 * The ordered names of the cluster rows.
+	 */
+	protected String[] clusterOrderedRowNames = null;
+	
+	/**
+	 * The cluster tree heights.
+	 */
+	protected double[] clusterHeights = null;
+	
+	/**
+	 * The cluster tree merges.
+	 */
+	protected double[][] clusterMerges = null;
+	
+	/**
+	 * The inertia gains.
+	 */
+	protected double[] inertiaGains = null;
+	
+	/**
+	 * The metric (euclidean, manhattan).
+	 */
+	@Parameter(key = AHCPreferences.METRIC)
+	protected String metric;
+	
+	/**
+	 * The method (METHODS <- c("average", "single", "complete", "ward", "weighted", "flexible")).
+	 */
+	@Parameter(key = AHCPreferences.METHOD)
+	protected String method;
+	
+	/**
+	 * The number of clusters.
+	 */
+	@Parameter(key = AHCPreferences.N_CLUSTERS)
+	protected int numberOfClusters;
+	
+	/**
+	 * To compute the columns or the rows.
+	 */
+	@Parameter(key = AHCPreferences.COLUMNS_COMPUTING)
+	protected boolean columnsComputing;
+	
+	/**
+	 * To display in 2D or 3D.
+	 */
+	@Parameter(key = AHCPreferences.RENDERING_2D)
+	protected boolean rendering2D;
+	
+	
+	
+	/**
+	 * Instantiates a new AHC.
+	 *
+	 * @param ca the ca
+	 * @param col the col
+	 * @param method the method
+	 * @param metric the metric
+	 * @param numberOfClusters the n cluster
+	 * @param display2D the display mode
+	 */
+	public AHC(String parametersNodePath) {
+		this(parametersNodePath, null);
+	}
+	
+	/**
+	 * Instantiates a new AHC.
+	 *
+	 * @param ca the ca
+	 * @param col the col
+	 * @param method the method
+	 * @param metric the metric
+	 * @param numberOfClusters the n cluster
+	 * @param display2D the display mode
+	 */
+	public AHC(CA ca) {
+		this(null, ca);
+	}
+	
+	@Override
+	public CA getParent() {
+		return (CA) parent;
+	}
+	
+	/**
+	 * Instantiates a new AHC.
+	 *
+	 * @param ca the ca
+	 * @param col the col
+	 * @param method the method
+	 * @param metric the metric
+	 * @param numberOfClusters the n cluster
+	 * @param display2D the display mode
+	 */
+	public AHC(String parametersNodePath, CA ca) {
+		super(parametersNodePath, ca);
+	}
+	
+	@Override
+	protected boolean __compute(TXMProgressMonitor monitor) {
+		
+		try {
+			CA ca = getParent();
+			LexicalTable table = ca.getLexicalTable();
+			this.target = ca.getRSymbol();
+			
+			// reset the number of clusters to default if columns or rows computing has changed
+			// if(this.hasParameterChanged(AHCPreferences.COLUMNS_COMPUTING)) {
+			// this.numberOfClusters = AHCPreferences.getInstance().getInt(AHCPreferences.N_CLUSTERS);
+			// }
+			
+			String colOrLine = "columns"; //$NON-NLS-1$
+			if (!this.columnsComputing) {
+				colOrLine = "rows"; //$NON-NLS-1$
+			}
+			
+			if (this.symbol == null) {
+				this.symbol = prefixR + (ahcCounter++);
+			}
+			else {
+				try {
+					RWorkspace.getRWorkspaceInstance().removeVariableFromWorkspace(this.symbol);
+				}
+				catch (RWorkspaceException e) {
+					Log.printStackTrace(e);
+				}
+			}
+			
+			RWorkspace rw = RWorkspace.getRWorkspaceInstance();
+			rw.eval("library(FactoMineR)"); //$NON-NLS-1$
+			rw.eval(this.symbol + " <- HCPC(" + this.target + //$NON-NLS-1$
+					", cluster.CA=\"" + colOrLine + "\"" + //$NON-NLS-1$ //$NON-NLS-2$
+					", nb.clust=" + this.numberOfClusters + //$NON-NLS-1$
+					", metric=\"" + this.metric + "\"" + //$NON-NLS-1$ //$NON-NLS-2$
+					", method=\"" + this.method + "\"" + //$NON-NLS-1$ //$NON-NLS-2$
+					", graph=FALSE)"); //$NON-NLS-1$
+			
+		}
+		catch (Exception e) {
+			Log.printStackTrace(e);
+			return false;
+		}
+		
+		// Reset the cached data
+		this.resetCache();
+		return true;
+	}
+	
+	
+	/**
+	 * 
+	 * @param columns
+	 * @param metric
+	 * @param nCluster
+	 * @param method
+	 */
+	public void setParameters(Boolean columns, String metric, Integer nCluster, String method) {
+		if (columns != null) {
+			this.columnsComputing = columns;
+		}
+		if (metric != null) {
+			this.metric = metric;
+		}
+		if (nCluster != null) {
+			this.numberOfClusters = nCluster;
+		}
+		if (method != null) {
+			this.method = method;
+		}
+		this.setDirty(); //TODO check if this is still necessary
+	}
+	
+	
+	@Override
+	public boolean loadParameters() {
+		// if(this.ca == null) { // moved to ComputeAHC command
+		// this.ca = (CA) this.getParent();
+		// this.ca.setVisible(false); // hide the temporary CA
+		// }
+		return true;
+	}
+	
+	@Override
+	public boolean saveParameters() {
+		// nothing to do
+		return true;
+	}
+	
+	@Override
+	public boolean canCompute() {
+		return Arrays.binarySearch(AHC.getMethods(), this.method) >= 0
+				&& Arrays.binarySearch(AHC.getMetrics(), this.metric) >= 0
+				&& this.numberOfClusters >= 2;
+	}
+	
+	@Override
+	public boolean setParameters(TXMParameters parameters) {
+		// TODO Auto-generated method stub
+		System.err.println("AHC.setParameters() is not yet implemented."); //$NON-NLS-1$
+		return true;
+	}
+	
+	/**
+	 * Resets the cached data so the next getter calls will request the values from R.
+	 */
+	public void resetCache() {
+		this.clusterCoords = null;
+		this.clusterNumbers = null;
+		this.clusterRowNames = null;
+		this.clusterOrderedRowNames = null;
+		this.clusterHeights = null;
+		this.clusterMerges = null;
+	}
+	
+	@Override
+	public String getRSymbol() {
+		return symbol;
+	}
+	
+	/**
+	 * Gets the methods.
+	 *
+	 * @return the methods
+	 */
+	public static String[] getMethods() {
+		String[] methods = { "average", "single", "complete", "ward", "weighted", "flexible" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
+		return methods;
+	}
+	
+	/**
+	 * Gets the metrics.
+	 *
+	 * @return the metrics
+	 */
+	public static String[] getMetrics() {
+		String[] metrics = { "euclidean", "manhattan" }; //$NON-NLS-1$ //$NON-NLS-2$
+		return metrics;
+	}
+	
+	/**
+	 *
+	 * @param outfile
+	 * @param encoding
+	 * @return
+	 */
+	// FIXME: SJ: to extract to future exporter extension
+	public boolean _toTxt(File outfile, String encoding, String colsep, String txtsep) {
+		boolean ret = true;
+		acquireSemaphore();
+		RWorkspace rw;
+		try {
+			rw = RWorkspace.getRWorkspaceInstance();
+			rw.eval("sink(file=\"" + outfile.getAbsolutePath().replace("\\", "\\\\") + "\")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+			rw.eval("print(" + symbol + "$call)"); //$NON-NLS-1$ //$NON-NLS-2$
+			rw.eval("sink()"); //$NON-NLS-1$
+		}
+		catch (RWorkspaceException e) {
+			Log.severe(AHCCoreMessages.error_errorWhileExportingCAHToTXT);
+			org.txm.utils.logger.Log.printStackTrace(e);
+			ret = false;
+		}
+		finally {
+			releaseSemaphore();
+		}
+		return true;
+	}
+		
+	/**
+	 * Gets the default method.
+	 *
+	 * @return the default method
+	 */
+	public static String getDefaultMethod() {
+		return "ward"; //$NON-NLS-1$
+	}
+	
+	/**
+	 * Gets the default metric.
+	 *
+	 * @return the default metric
+	 */
+	public static String getDefaultMetric() {
+		return "euclidean"; //$NON-NLS-1$
+	}
+	
+	@Override
+	public void clean() {
+		try {
+			RWorkspace.getRWorkspaceInstance().removeVariableFromWorkspace(this.symbol);
+		}
+		catch (RWorkspaceException e) {
+			Log.printStackTrace(e);
+		}
+	}
+	
+	/**
+	 * Gets the clusters coordinates.
+	 * 
+	 * @return the clusters coordinates
+	 */
+	public double[][] getClusterCoords() {
+		if (this.clusterCoords == null) {
+			try {
+				
+				// FIXME: check this code for the CAH 3D chart implementation
+				RWorkspace rw = RWorkspace.getRWorkspaceInstance();
+				for (int i = 0; i < 2; i++) { // 2 dimensions
+					REXP sv = rw.extractItemFromListByName(symbol, "data.clust[," + (i + 1) + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+					double[] coords = RWorkspace.toDouble(sv);
+					for (int j = 0; j < coords.length; j++) {
+						if (this.clusterCoords == null) {
+							this.clusterCoords = new double[coords.length][2];
+						}
+						this.clusterCoords[j][i] = coords[j];
+					}
+				}
+			}
+			catch (Exception e) {
+				// TODO Auto-generated catch block
+				org.txm.utils.logger.Log.printStackTrace(e);
+			}
+		}
+		return this.clusterCoords;
+	}
+	
+	
+	/**
+	 * Gets the clusters numbers.
+	 * 
+	 * @return
+	 */
+	public int[] getClusterNumbers() {
+		if (this.clusterNumbers == null) {
+			try {
+				RWorkspace rw = RWorkspace.getRWorkspaceInstance();
+				// FIXME: not sorted version
+				REXP sv = rw.extractItemFromListByName(symbol, "data$clust"); //$NON-NLS-1$
+				// FIXME: sorted version
+				// REXP sv = rw.extractItemFromListByName(symbol, "data$clust[c(" + symbol + "$call$t$tree$order)]"); //$NON-NLS-1$
+				this.clusterNumbers = sv.asIntegers();
+			}
+			catch (Exception e) {
+				// TODO Auto-generated catch block
+				org.txm.utils.logger.Log.printStackTrace(e);
+			}
+		}
+		return this.clusterNumbers;
+	}
+	
+	/**
+	 * Gets the cluster row names.
+	 * 
+	 * @return
+	 */
+	public String[] getClusterRowNames() {
+		if (this.clusterRowNames == null) {
+			try {
+				RWorkspace rw = RWorkspace.getRWorkspaceInstance();
+				
+				// FIXME: old method, Save the row names in the R data frame
+				// rw.safeEval(symbol + "$rownames <- rownames(" + symbol + "$data)");
+				// REXP sv = rw.extractItemFromListByName(symbol, "rownames"); //$NON-NLS-1$
+				
+				
+				REXP sv = rw.extractItemFromListByName(symbol, "call$t$tree$labels"); //$NON-NLS-1$
+				
+				
+				this.clusterRowNames = sv.asStrings();
+				
+			}
+			catch (Exception e) {
+				// TODO Auto-generated catch block
+				org.txm.utils.logger.Log.printStackTrace(e);
+			}
+		}
+		return this.clusterRowNames;
+	}
+	
+	
+	
+	/**
+	 * Gets the cluster orderer row names.
+	 * 
+	 * @return
+	 */
+	public String[] getClusterOrderedRowNames() {
+		if (this.clusterOrderedRowNames == null) {
+			try {
+				RWorkspace rw = RWorkspace.getRWorkspaceInstance();
+				REXP sv = rw.extractItemFromListByName(symbol, "call$t$tree$labels[c(" + symbol + "$call$t$tree$order)]"); //$NON-NLS-1$ //$NON-NLS-2$
+				this.clusterOrderedRowNames = sv.asStrings();
+			}
+			catch (Exception e) {
+				// TODO Auto-generated catch block
+				org.txm.utils.logger.Log.printStackTrace(e);
+			}
+		}
+		return this.clusterOrderedRowNames;
+	}
+	
+	
+	/**
+	 * Gets the cluster tree heights.
+	 * 
+	 * @return
+	 */
+	public double[] getClusterTreeHeights() {
+		if (this.clusterHeights == null) {
+			try {
+				RWorkspace rw = RWorkspace.getRWorkspaceInstance();
+				REXP sv = rw.extractItemFromListByName(symbol, "call$t$tree$height"); //$NON-NLS-1$
+				this.clusterHeights = sv.asDoubles();
+			}
+			catch (Exception e) {
+				// TODO Auto-generated catch block
+				org.txm.utils.logger.Log.printStackTrace(e);
+			}
+		}
+		return this.clusterHeights;
+	}
+	
+	
+	/**
+	 * Gets the inertia gains.
+	 * 
+	 * @return
+	 */
+	// FIXME: for test purpose, this method is not used for the chart computing
+	public double[] getInertiaGains() {
+		if (this.inertiaGains == null) {
+			try {
+				RWorkspace rw = RWorkspace.getRWorkspaceInstance();
+				REXP sv = rw.extractItemFromListByName(symbol, "call$t$inert.gain"); //$NON-NLS-1$
+				// FIXME: tests
+				// REXP sv = rw.extractItemFromListByName(symbol, "call$t$within"); //$NON-NLS-1$
+				
+				this.inertiaGains = sv.asDoubles();
+			}
+			catch (Exception e) {
+				// TODO Auto-generated catch block
+				org.txm.utils.logger.Log.printStackTrace(e);
+			}
+		}
+		return this.inertiaGains;
+	}
+	
+	
+	/**
+	 * Gets the cluster tree merges.
+	 * 
+	 * @return
+	 */
+	public double[][] getClusterTreeMerges() {
+		if (this.clusterMerges == null) {
+			try {
+				RWorkspace rw = RWorkspace.getRWorkspaceInstance();
+				REXP sv = rw.extractItemFromListByName(symbol, "call$t$tree$merge"); //$NON-NLS-1$
+				this.clusterMerges = sv.asDoubleMatrix();
+			}
+			catch (Exception e) {
+				// TODO Auto-generated catch block
+				org.txm.utils.logger.Log.printStackTrace(e);
+			}
+		}
+		return this.clusterMerges;
+	}
+	
+	
+	
+	
+	
+	
+	/**
+	 * Sets the metric to use for computing.
+	 * 
+	 * @param metric the metric to set
+	 */
+	public void setMetric(String metric) {
+		this.metric = metric;
+	}
+	
+	/**
+	 * Sets the method to use for computing
+	 * 
+	 * @param method the method to set
+	 */
+	public void setMethod(String method) {
+		this.method = method;
+	}
+	
+	/**
+	 * Sets the computing to columns or rows and rest the number of clusters to default value.
+	 * 
+	 * @param columnsComputing the columns to set
+	 */
+	public void setColumnsComputing(boolean columnsComputing) {
+		this.columnsComputing = columnsComputing;
+	}
+	
+	/**
+	 * Sets the number of clusters to use for computing
+	 * 
+	 * @param nClusters the nCluster to set
+	 */
+	public void setNumberOfClusters(int nClusters) {
+		numberOfClusters = nClusters;
+	}
+	
+	/**
+	 * Checks if the computing mode is set as columns. If not, the computing mode is set as rows.
+	 * 
+	 * @return
+	 */
+	public boolean isColumnsComputing() {
+		return columnsComputing;
+	}
+	
+	/**
+	 * Gets the maximum clusters available according to the current computing mode (columns or rows) and according to current source (<code>CA</code> or <code>LexicalTable</code>).
+	 * The maximum numbers of available clusters is for now limited to 16 by this method due of a limitation of FactoMineR plot.HCPC().
+	 * 
+	 * @return the maximum clusters available according to the current computing mode
+	 */
+	public int getMaxClustersCount() {
+		
+		int maxClustersCount = 16;
+		try {
+			int n = -1;
+			if (!this.columnsComputing) {
+				n = this.getParent().getParent().getNRows() - 1; // -1 because HCPC can't make as much groups as rows
+			}
+			else {
+				n = this.getParent().getParent().getNColumns() - 1; // -1 because HCPC can't make as much groups as cols
+			}
+			
+			if (n >= 0 && n < maxClustersCount) {
+				maxClustersCount = n;
+			}
+		}
+		catch (Exception e) {
+			Log.printStackTrace(e);
+		}
+		
+		// try {
+		// RWorkspace rw = RWorkspace.getRWorkspaceInstance();
+		// REXP sv = rw.eval("min(length(" + symbol + "$data$clust) - 1, 16)"); //$NON-NLS-1$ //$NON-NLS-2$
+		// maxClustersCount = sv.asInteger();
+		// } catch(Exception e) {
+		// System.out.println("Error: "+e.getLocalizedMessage());
+		// Log.printStackTrace(e);
+		// }
+		
+		// FIXME: FactoMineR plot.HCPC doesn't manage more than 16 clusters when tree.barplot=TRUE, therefore we can't plot a SVG with more than that, see ticket #836 then use the code below in
+		// ChartsEngine to compute
+		// the real maximum available clusters count
+		// // CA
+		// if(this.source instanceof CA) {
+		// if(this.columns == true) {
+		// maxClustersCount = ((CA)this.source).getColumnsCount() - 1;
+		// }
+		// else {
+		// maxClustersCount = ((CA)this.source).getRowsCount() - 1;
+		// }
+		// }
+		// // Lexical table
+		// else if(this.source instanceof LexicalTable) {
+		// if(this.columns == true) {
+		// maxClustersCount = ((LexicalTable)this.source).getColumnsCount() - 1;
+		// }
+		// else {
+		// maxClustersCount = ((LexicalTable)this.source).getRowsCount() - 1;
+		// }
+		// }
+		
+		return maxClustersCount;
+	}
+	
+	
+	
+	@Override
+	public String[] getExportTXTExtensions() {
+		return new String[] { "*.txt" }; //$NON-NLS-1$
+	}
+	
+	
+	/**
+	 * Returns the number of clusters.
+	 * 
+	 * @return the number of clusters
+	 */
+	public int getNumberOfClusters() {
+		return numberOfClusters;
+	}
+	
+	/**
+	 * Gets the parent lexical table.
+	 * 
+	 * @return the parent lexical table
+	 */
+	public LexicalTable getLexicalTable() {
+		return this.getParent().getLexicalTable();
+	}
+	
+	
+	@Override
+	public String getSimpleName() {
+		try {
+			return this.getName();
+		}
+		catch (Exception e) {
+			return this.getEmptyName();
+		}
+	}
+	
+	@Override
+	public String getName() {
+		return NLS.bind(AHCCoreMessages.P0classesOfP1, this.getNumberOfClusters(), this.columnsComputing ? AHCCoreMessages.columns : AHCCoreMessages.rows);
+	}
+	
+	
+	@Override
+	public String getDetails() {
+		return NLS.bind(this.getName() + AHCCoreMessages.AHC_computedWithTheP0MethodAndTheP1Metric, method, metric);
+	}
+	
+	@Override
+	public String getComputingStartMessage() {
+		
+		// from CA
+		if (this.getParent().isVisible()) {
+			return TXMCoreMessages.bind(AHCCoreMessages.info_ahcOfTheP0ca, this.getParent().getSimpleName());
+		}
+		// from lexical table
+		else if (this.getLexicalTable().isVisible()) {
+			return TXMCoreMessages.bind(AHCCoreMessages.info_ahcOfTheP0LexcialTable, this.getLexicalTable().getSimpleName());
+		}
+		
+		else {
+			
+			// from partition
+			if (this.getParent().getParent().getPartition() != null) {
+				return TXMCoreMessages.bind(AHCCoreMessages.info_ahcOfTheP0PartitionCommaP1Property, this.getLexicalTable().getPartition().getSimpleName(), this.getLexicalTable().getProperty());
+			}
+			// from sub-corpus lexical table
+			// FIXME: SJ: this special case is possible when creating Specificities then calling the command on the invisible Lexical Table
+			// need to if we need a special log message here
+			else {
+				return ""; //$NON-NLS-1$
+			}
+		}
+		
+		
+	}
+	
+	/**
+	 * Gets the 2D rendering state.
+	 * If false, the rendering will be done in 3D.
+	 * 
+	 * @return the rendering2D
+	 */
+	public boolean isRendering2D() {
+		return rendering2D;
+	}
+	
+	/**
+	 * Sets the 2D rendering state.
+	 * If set to false, the rendering will be done in 3D.
+	 * 
+	 * @param rendering2d the rendering2D to set
+	 */
+	public void setRendering2D(boolean rendering2d) {
+		rendering2D = rendering2d;
+	}
+	
+	@Override
+	public String getResultType() {
+		return AHCCoreMessages.RESULT_TYPE;
+	}
+	
+	/**
+	 * Gets the parent lexical table unit property.
+	 * 
+	 * @return the parent lexical table unit property
+	 */
+	public Property getUnitProperty() {
+		if (this.getLexicalTable() != null) {
+			return this.getLexicalTable().getProperty();
+		}
+		return null;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/functions/AHC.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/functions/package.html
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/functions/package.html	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/functions/package.html	(revision 3653)
@@ -0,0 +1,5 @@
+<html>
+<body>
+	<p>Classifcation using FactoMineR's CAH.</p>
+</body>
+</html>
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/functions/package.html
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/chartsengine/jfreechart/JFCAHCChartCreator.java
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/chartsengine/jfreechart/JFCAHCChartCreator.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/chartsengine/jfreechart/JFCAHCChartCreator.java	(revision 3653)
@@ -0,0 +1,694 @@
+package org.txm.ahc.core.chartsengine.jfreechart;
+
+import org.jfree.chart.JFreeChart;
+import org.txm.ahc.core.functions.AHC;
+import org.txm.chartsengine.core.results.ChartResult;
+import org.txm.chartsengine.jfreechart.core.JFCChartCreator;
+
+/**
+ * JFC CAH chart creator.
+ * 
+ * @author mdecorde
+ * @author sjacquot
+ * 
+ * 
+ */
+public class JFCAHCChartCreator extends JFCChartCreator<AHC> {
+	
+	
+	@Override
+	public JFreeChart createChart(AHC result) {
+		
+		System.err.println("JFCAHCChartCreator.createChart() is not yet implemented."); //$NON-NLS-1$
+		
+		return null;
+		
+	}
+	
+	
+	@Override
+	public Class<AHC> getResultDataClass() {
+		return AHC.class;
+	}
+	
+	
+	
+	
+	
+	// FIXME: old version with bar plot renderer
+	// @Override
+	// public JFreeChart createCAH2dChart(CAH cah) {
+	//
+	//
+	// JFreeChart chart = null;
+	//
+	// // Creating the data set from the result
+	// DefaultCategoryDataset dataset = new DefaultCategoryDataset();
+	// String category = "cluster ";
+	//
+	//
+	//
+	// int[] clusterNumbers = cah.getClusterNumbers();
+	// String[] rowNames = cah.getClusterRowNames();
+	// String[] orderedRowNames = cah.getClusterOrderedRowNames();
+	// double[] clusterHeights = cah.getClusterTreeHeights();
+	// double[][] clusterMerges = cah.getClusterTreeMerges();
+	// double[][] clusterCoords = cah.getClusterCoords();
+	//
+	// double[] yValuesByOrderedRowNames = new double[rowNames.length];
+	// double[] clusterNumbersValuesByOrderedRowNames = new double[rowNames.length];
+	//
+	//
+	//
+	// // FIXME: Sort the cluster numbers in reverse order
+	//// Arrays.sort(clusterNumbers);
+	//// ArrayUtils.reverse(clusterNumbers);
+	//// System.out.println(Arrays.toString(clusterNumbers));
+	//
+	//
+	// // FIXME: tests row names
+	// //System.err.println("JFCChartsEngine.createCAH2dChart(): cluster row names: \t\t" + Arrays.toString(rowNames));
+	//
+	// // FIXME: tests ordered row names
+	// //System.err.println("JFCChartsEngine.createCAH2dChart(): cluster ordered row names: \t" + Arrays.toString(orderedRowNames));
+	//
+	// // FIXME: tests, ordered cluster numbers
+	// //System.err.println("JFCChartsEngine.createCAH2dChart(): cluster numbers: \t\t" + Arrays.toString(clusterNumbers));
+	//
+	// // FIXME: tests, cluster tree merges
+	// //System.err.println("JFCChartsEngine.createCAH2dChart(): cluster tree merges: \t\t" + Arrays.toString(clusterMerges));
+	//
+	// // FIXME: tests, heights
+	//// System.err.println("JFCChartsEngine.createCAH2dChart(): cluster heights: \t\t" + Arrays.toString(clusterHeights));
+	//
+	//
+	// // FIXME: tests
+	// System.err.println("JFCChartsEngine.createCAH2dChart(): tests: \t\t" + Arrays.toString(cah.getInertiaGains()));
+	//
+	//
+	//
+	// System.out.println("JFCChartsEngine.createCAH2dChart() cluster heights count: " + clusterHeights.length);
+	// for(int i = 0; i < clusterHeights.length; i++) {
+	// System.out.println("JFCChartsEngine.createCAH2dChart() cluster height: " + new DecimalFormat("0.00000000000000000").format(clusterHeights[i]));
+	// }
+	//
+	////
+	//// String[] clusterUnorderedRowNames = cah.getClusterRowNames();
+	//// for(int i = 0; i < clusterUnorderedRowNames.length; i++) {
+	//// System.out.println("JFCChartsEngine.createCAH2dChart() unordered row names " + i + " : " + clusterUnorderedRowNames[i]);
+	//// }
+	//
+	// // Parse the merge pairs
+	// // A negative number in the FactoMineR tree merge table means a singleton
+	// for (int i = 0 ; i < clusterMerges.length ; i++) {
+	//
+	// // FIXME: debug
+	// //for (int j = 0 ; j < clusterMerges.length ; j++) {
+	// System.err.println("JFCChartsEngine.createCAH2dChart(): cluster tree merges: \t\t" + Arrays.toString(clusterMerges[i]));
+	// System.err.println("JFCChartsEngine.createCAH2dChart(): row names: \t\t" + rowNames[(int) Math.abs(clusterMerges[i][0]) - 1] + " | " + rowNames[(int) Math.abs(clusterMerges[i][1]) - 1]);
+	//
+	//
+	// //}
+	//
+	// // Leaves pair
+	// if(clusterMerges[i][0] < 0) {
+	//
+	// //System.err.print("JFCChartsEngine.createCAH2dChart(): merging: " + rowNames[(int) Math.abs(clusterMerge[i][0]) - 1]);
+	//
+	// // Put the height in the ordered by names values table
+	// for(int j = 0; j < orderedRowNames.length; j++) {
+	// if(orderedRowNames[j].equals(rowNames[(int) Math.abs(clusterMerges[i][0]) - 1])) {
+	// yValuesByOrderedRowNames[j] = clusterHeights[i];
+	// //clusterNumbersValuesByOrderedRowNames[j] = clusterNumbers[(int) Math.abs(clusterMerge[i][0]) - 1];
+	// }
+	// }
+	//
+	// }
+	// // Non-singleton
+	//// else {
+	//// //System.err.print("JFCChartsEngine.createCAH2dChart(): merging aggregation: " + clusterMerge[i][0]);
+	//// }
+	//
+	// // Leaves pair
+	// if(clusterMerges[i][1] < 0) {
+	// //System.err.print(" with: " + rowNames[(int) Math.abs(clusterMerge[i][1]) - 1]);
+	//
+	// // Put the height in the ordered by names values table
+	// for(int j = 0; j < orderedRowNames.length; j++) {
+	// if(orderedRowNames[j].equals(rowNames[(int) Math.abs(clusterMerges[i][1]) - 1])) {
+	// yValuesByOrderedRowNames[j] = clusterHeights[i];
+	// //clusterNumbersValuesByOrderedRowNames[j] = clusterNumbers[(int) Math.abs(clusterMerge[i][1]) - 1];
+	// }
+	//
+	// }
+	//
+	// }
+	// // Non-singleton
+	//// else {
+	//// //System.err.print(" with aggregation: " + clusterMerge[i][1]);
+	//// }
+	//
+	// //System.err.println(" and height: " + clusterHeights[i] + " as aggregation: " + (i + 1));
+	//
+	// }
+	//
+	//
+	// //
+	//// for (int i = 0 ; i < cah.getClusterTreeMerges().length; i++) {
+	//// System.err.println("JFCChartsEngine.createCAH2dChart() merges : ");
+	//// for(int j = 0; j < cah.getClusterTreeMerges()[i].length; j++) {
+	//// System.err.print(" : " + cah.getClusterTreeMerges()[i][j]);
+	//// }
+	//// }
+	//
+	//
+	//
+	//// ArrayList<Double> middlePoints = cah.getClusterTreeMiddlePoints();
+	////
+	//// for (int i = 0 ; i < middlePoints.size(); i++) {
+	//// System.err.println("JFCChartsEngine.createCAH2dChart() middle points X: " + middlePoints.get(i));
+	//// }
+	//
+	//
+	//
+	//// for (int i = 0 ; i < cah.getClusterCoords().length ; i++) {
+	//// for(int j = 0; j < cah.getClusterCoords()[i].length; j++) {
+	//// //System.err.println("JFCChartsEngine.createCAH2dChart(): " + cah.getClusterCoords()[i][j]);
+	//// dataset.setValue(cah.getClusterCoords()[i][j], category + clusterNumbers[i], rownames[i]);
+	//// }
+	//// }
+	//
+	//
+	//
+	// // Create chart title
+	// String title = "title";
+	// String xAxisLabel = "Column";
+	// if(!cah.isColumnsComputing()) {
+	// xAxisLabel = "Row";
+	// }
+	//
+	//
+	//
+	// // Create the data set
+	// // FIXME: bar plot test
+	//// for(int i = 0; i < yValuesByOrderedRowNames.length; i++) {
+	//// //dataset.setValue(yValuesByOrderedRowNames[i], category + clusterNumbers[clusterNumbers.length - 1 - i], orderedRowNames[i]);
+	////
+	////
+	//// dataset.setValue(yValuesByOrderedRowNames[i], category + clusterNumbers[yValuesByOrderedRowNames.length - 1 - i], orderedRowNames[i]);
+	//// //dataset.setValue(yValuesByOrderedRowNames[i], category + clusterNumbers[i], orderedRowNames[i]);
+	////
+	//// //dataset.setValue(yValuesByOrderedRowNames[i], category + clusterNumbersValuesByOrderedRowNames[i], orderedRowNames[i]);
+	//// }
+	////
+	//// // Create the chart
+	//// chart = this.createCategoryBarChart(dataset, title, xAxisLabel, "Height", false, false, false);
+	//// ((IItemSelectionRenderer) chart.getCategoryPlot().getRenderer()).setChartType(ChartsEngine.CHART_TYPE_CAH_2D);
+	////
+	//// // Draw tree
+	//// for(int j = 0; j < chart.getCategoryPlot().getDataset().getColumnCount() - 1; j++) {
+	//// //System.err.println("JFCChartsEngine.createCAH2dChart(): " + chart.getCategoryPlot().getDataset().getColumnKey(j));
+	////
+	////
+	//// // Non-singleton pairs lines
+	//// if(yValuesByOrderedRowNames[j] == yValuesByOrderedRowNames[j + 1]) {
+	//// chart.getCategoryPlot().addAnnotation(new CategoryLineAnnotation(chart.getCategoryPlot().getDataset().getColumnKey(j), yValuesByOrderedRowNames[j],
+	//// chart.getCategoryPlot().getDataset().getColumnKey(j + 1), yValuesByOrderedRowNames[j + 1], Color.red, new BasicStroke(2.0f)));
+	//// }
+	////
+	////
+	//// //chart.getCategoryPlot().addAnnotation(new Cate
+	////
+	////
+	////
+	//// }
+	//
+	//
+	//
+	// // Create the data set
+	// // FIXME: step chart test
+	//// for(int i = 0; i < yValuesByOrderedRowNames.length - 1; i++) {
+	//// if(yValuesByOrderedRowNames[i] == yValuesByOrderedRowNames[i + 1]) {
+	//// dataset.setValue(yValuesByOrderedRowNames[i], category + clusterNumbers[yValuesByOrderedRowNames.length - 1 - i], orderedRowNames[i]);
+	//// }
+	//// }
+	////// dataset.addValue(0, "test", "truc 1");
+	////// dataset.addValue(0.5, "test", "truc 1");
+	////// dataset.addValue(0.9, "test", "truc 1");
+	//// // Create the chart
+	//// chart = this.createCategoryStepChart(dataset, title, xAxisLabel, "Height", false, false);
+	//// ((IItemSelectionRenderer) chart.getCategoryPlot().getRenderer()).setChartType(ChartsEngine.CHART_TYPE_CAH_2D);
+	//
+	//
+	// // Create the data set
+	// // FIXME: XY category bar chart test
+	// XYSeriesCollection dataset2 = new XYSeriesCollection();
+	//
+	// // Last tree level (leaves level)
+	// XYSeries series = new XYSeries("leaves");
+	// for(int i = 0; i < yValuesByOrderedRowNames.length - 1; i++) {
+	// series.add(i, 0);
+	// series.add(i, yValuesByOrderedRowNames[i]);
+	// if(yValuesByOrderedRowNames[i] == yValuesByOrderedRowNames[i + 1]) {
+	// series.add(i + 1, yValuesByOrderedRowNames[i]);
+	// series.add(i + 1, 0);
+	// }
+	// else {
+	// series.add(i + 1, null);
+	// }
+	// }
+	// dataset2.addSeries(series);
+	//
+	//
+	// // Link singletons to non singleton
+	// series = new XYSeries("singleton to non singleton links");
+	// for(int i = clusterHeights.length; i >= 0; i--) {
+	//
+	// // Skip non singletons case
+	// if(i > 3 && yValuesByOrderedRowNames[i] == yValuesByOrderedRowNames[i - 1] && yValuesByOrderedRowNames[i - 2] == yValuesByOrderedRowNames[i - 3]) {
+	// continue;
+	// }
+	//
+	// // Link singletons to non singleton
+	// if(i > 1 && yValuesByOrderedRowNames[i] == yValuesByOrderedRowNames[i - 1] && yValuesByOrderedRowNames[i - 1] != yValuesByOrderedRowNames[i - 2]) {
+	// series.add(i - 0.5, yValuesByOrderedRowNames[i - 2]);
+	// series.add(i - 0.5, yValuesByOrderedRowNames[i]);
+	// series.add(i - 0.5, null);
+	// series.add(i - 2, yValuesByOrderedRowNames[i - 2]);
+	// }
+	// }
+	// dataset2.addSeries(series);
+	//
+	// // Link singletons to newly created pairs
+	// series = new XYSeries("singleton to newly created pairs");
+	// for(int i = clusterHeights.length; i >= 0; i--) {
+	//
+	// // Skip non singletons case
+	// if(i > 0 && yValuesByOrderedRowNames[i] == yValuesByOrderedRowNames[i - 1]) {
+	// series.add(i, null);
+	// continue;
+	// }
+	//
+	// // Link singletons to newly created pairs
+	// if(i < clusterHeights.length - 1 && yValuesByOrderedRowNames[i] != yValuesByOrderedRowNames[i + 1]
+	// && yValuesByOrderedRowNames[i + 1] != yValuesByOrderedRowNames[i + 2]
+	//
+	//// && i > 1 &&
+	//
+	// ) {
+	//
+	// series.add(i, null);
+	//
+	// series.add(i, yValuesByOrderedRowNames[i]);
+	//
+	// series.add(i + 1.75, yValuesByOrderedRowNames[i]);
+	// series.add(i + 1.75, yValuesByOrderedRowNames[i + 1]);
+	//
+	//
+	// //series.add(i - 2, yValuesByOrderedRowNames[i - 2]);
+	// }
+	// }
+	// dataset2.addSeries(series);
+	//
+	//
+	//
+	// // Link singletons; test 2
+	//// series = new XYSeries("singleton links");
+	//// for(int i = 0; i < clusterHeights.length - 2; i++) {
+	//// if(i > 0 && i < clusterHeights.length - 2 && yValuesByOrderedRowNames[i] != yValuesByOrderedRowNames[i + 1] && yValuesByOrderedRowNames[i] != yValuesByOrderedRowNames[i - 1]) {
+	//// series.add(i, yValuesByOrderedRowNames[i]);
+	//// series.add(i + 1.5, yValuesByOrderedRowNames[i]);
+	//// series.add(i + 1.5, yValuesByOrderedRowNames[i + 1]);
+	//// series.add(i + 1.5, null);
+	//// }
+	//// }
+	//// dataset2.addSeries(series);
+	//
+	//
+	//// // Other clusters
+	//// ArrayList<Double> otherClusters = new ArrayList<Double>();
+	//// //series = new XYSeries("other clusters");
+	//// for(int i = 0; i < clusterHeights.length; i++) {
+	//// // If not a leaf
+	//// boolean done = false;
+	//// for(int j = 0; j < clusterNumbersValuesByOrderedRowNames.length; j++) {
+	//// if(clusterHeights[i] == yValuesByOrderedRowNames[j]) {
+	//// done = true;
+	//// break;
+	//// }
+	//// }
+	//// if(done) {
+	//// continue;
+	//// }
+	//// System.err.println("JFCChartsEngine.createCAH2dChart() other clusters: " + new DecimalFormat("0.0000000000000000").format(clusterHeights[i]));
+	//// }
+	//// //dataset2.addSeries(series);
+	//
+	//
+	//
+	//// dataset.addValue(0, "test", "truc 1");
+	//// dataset.addValue(0.5, "test", "truc 1");
+	//// dataset.addValue(0.9, "test", "truc 1");
+	// // Create the chart
+	// //chart = this.createXYBarChart(dataset2, title, xAxisLabel, "Height", false, false);
+	// chart = ChartFactory.createXYLineChart(
+	// title, // chart title
+	// xAxisLabel, // x axis label
+	// "height", // y axis label
+	// dataset2, // data
+	// PlotOrientation.VERTICAL,
+	// true, // include legend
+	// true, // tooltips
+	// false // urls
+	// );
+	//
+	//
+	//
+	//
+	// chart.getXYPlot().setRenderer(this.theme.createXYLineAndShapeRenderer(true, false));
+	// ((IItemSelectionRenderer) chart.getXYPlot().getRenderer()).setChartType(ChartsEngine.CHART_TYPE_CAH_2D);
+	//
+	//
+	// //chart.getXYPlot().addAnnotation(new XYLineAnnotation(0.5, yValuesByOrderedRowNames[0], 0.5, yValuesByOrderedRowNames[0] + 0.002));
+	//
+	//
+	//
+	//
+	//
+	//
+	//
+	//
+	// //System.err.println("JFCChartsEngine.createCAH2dChart() " + chart.getCategoryPlot().getCategories().get(0));
+	// //chart.getCategoryPlot().addAnnotation(new CategoryLineAnnotation("1970-12-31", .0002, "1965-12-31", .00005, Color.red, new BasicStroke(2.0f)));
+	//
+	// // Custom range axis for ticks drawing options
+	// //chart.getCategoryPlot().setRangeAxis(new ExtendedNumberAxis((NumberAxis) chart.getCategoryPlot().getRangeAxis(), false, true, 0,
+	// DatasetUtilities.findMaximumRangeValue(chart.getCategoryPlot().getDataset()).doubleValue()));
+	//
+	//
+	//
+	// // Apply theme to the chart
+	// this.theme.apply(chart);
+	//
+	//
+	//
+	// // FIXME: test algo R
+	// int dimens = 2;
+	// int ax1 = 0;
+	// int ax2 = 1;
+	// double x1, y1, x2, y2, w1, w2;
+	//
+	// double h1, h2; // FIXME: when using 3 dimensions
+	//
+	//
+	// double[][] aa = new double[clusterMerges.length][4];
+	// for(int i = 0; i < clusterMerges.length; i++) {
+	// for(int j = 0; j < 4; j++) {
+	// aa[i][j] = 0;
+	// }
+	// }
+	//
+	//
+	// //aa=matrix(ncol=4, nrow=nrow(merge))
+	//
+	//
+	//
+	//
+	// // Decrement/increment the cluster merge value because the R algorithm uses 1 as first table index
+	//
+	// for(int i = 0; i < clusterMerges.length; i++) {
+	// if(clusterMerges[i][0] < 0) {
+	// clusterMerges[i][0]++;
+	// }
+	// else {
+	// clusterMerges[i][0]--;
+	// }
+	//
+	// if(clusterMerges[i][1] < 0) {
+	// clusterMerges[i][1]++;
+	// }
+	// else {
+	// clusterMerges[i][1]--;
+	// }
+	// }
+	//
+	//
+	// for(int i = 0; i < clusterMerges.length; i++) {
+	//
+	//// for(i in 1:nrow(merge)){
+	// // if(merge[i,1]<0){
+	// // Singleton
+	// if(clusterMerges[i][0] < 0) {
+	//
+	//
+	// x1 = clusterCoords[(int) -clusterMerges[i][0]][ax1];
+	// y1 = clusterCoords[(int) -clusterMerges[i][0]][ax2];
+	//
+	//
+	// h1 = 0;
+	// w1 = 1;
+	// }
+	// else{
+	// x1 = aa[(int) clusterMerges[i][0]][0];
+	// y1 = aa[(int) clusterMerges[i][0]][1];
+	// w1 = aa[(int) clusterMerges[i][0]][3];
+	// h1 = aa[(int) clusterMerges[i][0]][2];
+	// }
+	// // Singleton
+	// if(clusterMerges[i][1] < 0) {
+	// //if(merge[i,2]<0){
+	// x2 = clusterCoords[-(int) clusterMerges[i][1]][ax1];
+	// y2 = clusterCoords[-(int) clusterMerges[i][1]][ax2];
+	// h2 = 0;
+	// w2 = 1;
+	// }
+	// else{
+	// x2 = aa[(int) clusterMerges[i][1]][0];
+	// y2 = aa[(int) clusterMerges[i][1]][1];
+	// w2 = aa[(int) clusterMerges[i][1]][3];
+	// h2 = aa[(int) clusterMerges[i][1]][2];
+	// }
+	// aa[i][0] = (w1 * x1 + w2 * x2) / (w1 + w2);
+	// aa[i][1] = (w1 * y1 + w2 * y2) / (w1 + w2);
+	//
+	// //if(i<=nrow(merge)-t.level+1)
+	// if(i <= clusterMerges.length) {
+	// clusterHeights[i] = 0;
+	// }
+	//
+	// aa[i][2] = clusterHeights[i];
+	// aa[i][3] = w1 + w2;
+	//
+	//// if(i>(nrow(merge)-t.level+1)){
+	//// if(i > clusterMerges[i][1]){ // FIXME: this test is strange
+	//// if(dimens==3) s$points3d(rbind(c(x1,y1,h1),c(x1,y1,height[i]), c(x2,y2,height[i]),c(x2,y2,h2)), lty=1, type="o", pch="")
+	// if(dimens == 2) {
+	// // lines(c(x1,x2), c(y1,y2), lwd=(height[i]/max(height))*3)
+	//
+	// //chart.getXYPlot().addAnnotation(new XYLineAnnotation(x1, y1, x2, y2));
+	// // tests with steps lines
+	// x1 *= 10;
+	// x2 *= 10;
+	// y1 /= 100;
+	// y2 /= 100;
+	//
+	// chart.getXYPlot().addAnnotation(new XYLineAnnotation(x1, y1, x1, y2));
+	// chart.getXYPlot().addAnnotation(new XYLineAnnotation(x1, y2, x2, y2));
+	// chart.getXYPlot().addAnnotation(new XYLineAnnotation(x2, y2, x2, y1));
+	//
+	//
+	// // FIXME: labels tests
+	// chart.getXYPlot().addAnnotation(new XYTextAnnotation(rowNames[(int) Math.abs(clusterMerges[i][0])], x1, y1));
+	// chart.getXYPlot().addAnnotation(new XYTextAnnotation(rowNames[(int) Math.abs(clusterMerges[i][1])], x2, y1));
+	//
+	//
+	//
+	//// chart.getXYPlot().addAnnotation(new XYLineAnnotation(y2, x1, y1, x1));
+	//
+	//
+	// //chart.getXYPlot().addAnnotation(new XYLineAnnotation(x2, y2, x2, y2));
+	//
+	//
+	// System.err.println("JFCChartsEngine.createCAH2dChart(): draw line " + x1 + ", " + y1 + " | " + x2 + "," + y2);
+	// }
+	//// }
+	// // }
+	//
+	//
+	// }
+	//
+	//
+	// // FIXME: test symbol axis
+	// //chart.getXYPlot().setDomainAxis(new SymbolAxis("test symbol axis", new String[]{"A", "b", "c"}));
+	//
+	// // FIXME: for cluster boxes we may use XYBoxAnnotation()
+	//
+	//
+	// //chart.getXYPlot().addAnnotation(new XYLineAnnotation(x1, y1, x2, y2));
+	//
+	//
+	// return chart;
+	//
+	// }
+	
+	// FIXME: new version with category step renderer
+	// @Override
+	// public JFreeChart createCAH2dChart(CAH cah) {
+	//
+	//
+	// JFreeChart chart = null;
+	//
+	// // Creating the data set from the result
+	// DefaultCategoryDataset dataset = new DefaultCategoryDataset();
+	// String category = "cluster ";
+	//
+	//
+	//
+	// int[] clusterNumbers = cah.getClusterNumbers();
+	// String[] rowNames = cah.getClusterRowNames();
+	// String[] orderedRowNames = cah.getClusterOrderedRowNames();
+	// double[] clusterHeights = cah.getClusterTreeHeights();
+	// double[][] clusterMerge = cah.getClusterTreeMerges();
+	//
+	//
+	// double[] yValuesByOrderedRowNames = new double[rowNames.length];
+	// double[] clusterNumbersValuesByOrderedRowNames = new double[rowNames.length];
+	//
+	//
+	//
+	// // FIXME: Sort the cluster numbers in reverse order
+	//// Arrays.sort(clusterNumbers);
+	//// ArrayUtils.reverse(clusterNumbers);
+	//// System.out.println(Arrays.toString(clusterNumbers));
+	//
+	//
+	// // FIXME: tests row names
+	// //System.err.println("JFCChartsEngine.createCAH2dChart(): cluster row names: \t\t" + Arrays.toString(rowNames));
+	//
+	// // FIXME: tests ordered row names
+	// //System.err.println("JFCChartsEngine.createCAH2dChart(): cluster ordered row names: \t" + Arrays.toString(orderedRowNames));
+	//
+	// // FIXME: tests, ordered cluster numbers
+	// //System.err.println("JFCChartsEngine.createCAH2dChart(): cluster number: \t\t" + Arrays.toString(clusterNumbers));
+	//
+	//
+	//
+	// for (int i = 0 ; i < clusterMerge.length ; i++) {
+	//
+	// // Singleton
+	// if(clusterMerge[i][0] < 0) {
+	//
+	// //System.err.print("JFCChartsEngine.createCAH2dChart(): merging: " + rowNames[(int) Math.abs(clusterMerge[i][0]) - 1]);
+	//
+	// // Put the height in the ordered by names values table
+	// for(int j = 0; j < orderedRowNames.length; j++) {
+	// if(orderedRowNames[j].equals(rowNames[(int) Math.abs(clusterMerge[i][0]) - 1])) {
+	// yValuesByOrderedRowNames[j] = clusterHeights[i];
+	// //clusterNumbersValuesByOrderedRowNames[j] = clusterNumbers[(int) Math.abs(clusterMerge[i][0]) - 1];
+	// }
+	// }
+	//
+	// }
+	// // Non-singleton
+	// else {
+	// //System.err.print("JFCChartsEngine.createCAH2dChart(): merging aggregation: " + clusterMerge[i][0]);
+	// }
+	//
+	// // Singleton
+	// if(clusterMerge[i][1] < 0) {
+	// //System.err.print(" with: " + rowNames[(int) Math.abs(clusterMerge[i][1]) - 1]);
+	//
+	// // Put the height in the ordered by names values table
+	// for(int j = 0; j < orderedRowNames.length; j++) {
+	// if(orderedRowNames[j].equals(rowNames[(int) Math.abs(clusterMerge[i][1]) - 1])) {
+	// yValuesByOrderedRowNames[j] = clusterHeights[i];
+	// //clusterNumbersValuesByOrderedRowNames[j] = clusterNumbers[(int) Math.abs(clusterMerge[i][1]) - 1];
+	// }
+	//
+	// }
+	//
+	// }
+	// // Non-singleton
+	// else {
+	// //System.err.print(" with aggregation: " + clusterMerge[i][1]);
+	// }
+	//
+	// //System.err.println(" and height: " + clusterHeights[i] + " as aggregation: " + (i + 1));
+	//
+	// }
+	//
+	//
+	// // Create the data set
+	//
+	// for(int i = 0; i < yValuesByOrderedRowNames.length; i++) {
+	// //dataset.setValue(yValuesByOrderedRowNames[i], category + clusterNumbers[clusterNumbers.length - 1 - i], orderedRowNames[i]);
+	//
+	// dataset.setValue(yValuesByOrderedRowNames[i], category + clusterNumbers[yValuesByOrderedRowNames.length - 1 - i], orderedRowNames[i]);
+	// //dataset.setValue(yValuesByOrderedRowNames[i], category, orderedRowNames[i]);
+	//
+	// //dataset.setValue(yValuesByOrderedRowNames[i], category + clusterNumbersValuesByOrderedRowNames[i], orderedRowNames[i]);
+	// }
+	//
+	////
+	//// for (int i = 0 ; i < cah.getClusterTreeMerges().length; i++) {
+	//// System.err.println("JFCChartsEngine.createCAH2dChart() merges : ");
+	//// for(int j = 0; j < cah.getClusterTreeMerges()[i].length; j++) {
+	//// System.err.print(" : " + cah.getClusterTreeMerges()[i][j]);
+	//// }
+	//// }
+	//
+	//
+	//
+	//// ArrayList<Double> middlePoints = cah.getClusterTreeMiddlePoints();
+	////
+	//// for (int i = 0 ; i < middlePoints.size(); i++) {
+	//// System.err.println("JFCChartsEngine.createCAH2dChart() middle points X: " + middlePoints.get(i));
+	//// }
+	//
+	//
+	//
+	//// for (int i = 0 ; i < cah.getClusterCoords().length ; i++) {
+	//// for(int j = 0; j < cah.getClusterCoords()[i].length; j++) {
+	//// //System.err.println("JFCChartsEngine.createCAH2dChart(): " + cah.getClusterCoords()[i][j]);
+	//// dataset.setValue(cah.getClusterCoords()[i][j], category + clusterNumbers[i], rownames[i]);
+	//// }
+	//// }
+	//
+	//
+	//
+	// // Create chart title
+	// String title = "title";
+	// String xAxisLabel = "Column";
+	// if(!cah.isColumnsComputing()) {
+	// xAxisLabel = "Row";
+	// }
+	//
+	//
+	// // Create the chart
+	// chart = this.createCategoryStepChart(dataset, title, xAxisLabel, "Height", false, false);
+	//
+	//
+	// ((IItemSelectionRenderer) chart.getCategoryPlot().getRenderer()).setChartType(ChartsEngine.CHART_TYPE_CAH_2D);
+	//
+	//
+	// // Draw tree
+	// chart.getCategoryPlot().addAnnotation(new CategoryLineAnnotation(chart.getCategoryPlot().getDataset().getColumnKey(0), 5.0,
+	// chart.getCategoryPlot().getDataset().getColumnKey(1), 8.0, Color.red, new BasicStroke(2.0f)));
+	//
+	// // Custom range axis for ticks drawing options: cut the range to minimum and maximum values
+	// chart.getCategoryPlot().setRangeAxis(new ExtendedNumberAxis((NumberAxis) chart.getCategoryPlot().getRangeAxis(), false, true, 0,
+	// DatasetUtilities.findMaximumRangeValue(chart.getCategoryPlot().getDataset()).doubleValue()));
+	//
+	//
+	// return chart;
+	//
+	//
+	//
+	//
+	// }
+	
+	
+	
+	
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/chartsengine/jfreechart/JFCAHCChartCreator.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/chartsengine/r/RAHCChartCreator.java
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/chartsengine/r/RAHCChartCreator.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/chartsengine/r/RAHCChartCreator.java	(revision 3653)
@@ -0,0 +1,47 @@
+package org.txm.ahc.core.chartsengine.r;
+
+import java.io.File;
+
+import org.txm.ahc.core.functions.AHC;
+import org.txm.chartsengine.r.core.RChartCreator;
+
+/**
+ * R AHC chart creator.
+ * 
+ * @author mdecorde
+ * @author sjacquot
+ *
+ */
+public class RAHCChartCreator extends RChartCreator<AHC> {
+	
+	@Override
+	public File createChart(AHC result, File file) {
+		
+		AHC ahc = result;
+		
+		String cmd = null;
+		// 2D
+		if (ahc.isRendering2D()) {
+			cmd = "plot.HCPC(" + ahc.getRSymbol() + ", new.plot=FALSE, choice=\"tree\")"; //$NON-NLS-1$ //$NON-NLS-2$
+			
+			// FIXME: SJ: for tests without drawing the inertia barplot. Without it, the max available clusters can exceed 16
+			// cmd = "plot.HCPC(" + cah.getSymbol() + ", new.plot=FALSE, choice=\"tree\", tree.barplot=FALSE)"; //$NON-NLS-1$ //$NON-NLS-2$
+			// FIXME: Tests for drawing only the inertia bar plot. We may need to create a chart creator for this plot
+			// cmd= "plot.HCPC(" + cah.getSymbol() + ", new.plot=FALSE, choice=\"bar\")"; //$NON-NLS-1$ //$NON-NLS-2$
+			
+			
+		}
+		// 3D
+		else {
+			cmd = "plot.HCPC(" + ahc.getRSymbol() + ", new.plot=FALSE)"; //$NON-NLS-1$ //$NON-NLS-2$
+		}
+		
+		return this.getChartsEngine().plot(file, cmd);
+	}
+	
+	
+	@Override
+	public Class<AHC> getResultDataClass() {
+		return AHC.class;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/chartsengine/r/RAHCChartCreator.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/preferences/AHCPreferences.java
===================================================================
--- TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/preferences/AHCPreferences.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/preferences/AHCPreferences.java	(revision 3653)
@@ -0,0 +1,68 @@
+package org.txm.ahc.core.preferences;
+
+
+import org.osgi.service.prefs.Preferences;
+import org.txm.chartsengine.core.preferences.ChartsEnginePreferences;
+import org.txm.core.preferences.TXMPreferences;
+
+/**
+ * Default preferences initializer.
+ * 
+ * @author mdecorde
+ * @author sjacquot
+ *
+ */
+public class AHCPreferences extends ChartsEnginePreferences {
+	
+	/**
+	 * To display in 2D or 3D.
+	 */
+	public static final String RENDERING_2D = "rendering_2d"; //$NON-NLS-1$
+	
+	/**
+	 * The method (METHODS <- c("average", "single", "complete", "ward", "weighted", "flexible")).
+	 */
+	public static final String METHOD = "method"; //$NON-NLS-1$
+	
+	/**
+	 * The metric (euclidean, manhattan).
+	 */
+	public static final String METRIC = "metric"; //$NON-NLS-1$
+	
+	/**
+	 * The number of clusters.
+	 */
+	public static final String N_CLUSTERS = "n_clusters"; //$NON-NLS-1$
+	
+	/**
+	 * To compute the columns or the rows.
+	 */
+	public static final String COLUMNS_COMPUTING = "columns_computing"; //$NON-NLS-1$
+	
+	
+	/**
+	 * Gets the instance.
+	 * 
+	 * @return the instance
+	 */
+	public static TXMPreferences getInstance() {
+		if (!TXMPreferences.instances.containsKey(AHCPreferences.class)) {
+			new AHCPreferences();
+		}
+		return TXMPreferences.instances.get(AHCPreferences.class);
+	}
+	
+	
+	@Override
+	public void initializeDefaultPreferences() {
+		super.initializeDefaultPreferences();
+		Preferences preferences = this.getDefaultPreferencesNode();
+		
+		preferences.putBoolean(RENDERING_2D, true);
+		preferences.putInt(N_CLUSTERS, 2);
+		preferences.put(METHOD, "ward"); //$NON-NLS-1$
+		preferences.put(METRIC, "euclidean"); //$NON-NLS-1$
+		
+		preferences.putBoolean(COLUMNS_COMPUTING, true);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.ahc.core/src/org/txm/ahc/core/preferences/AHCPreferences.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain


Property changes on: TXM/trunk/bundles/org.txm.ahc.core
___________________________________________________________________
Added: svn:ignore
   + bin

target


Index: TXM/trunk/bundles/org.txm.analec.rcp/plugin.xml
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/plugin.xml	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/plugin.xml	(revision 3653)
@@ -0,0 +1,526 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>  
+   <extension
+         point="org.eclipse.ui.menus">
+      <menuContribution
+            locationURI="menu:org.eclipse.ui.main.menu?after=menu.tools">
+         <menu
+               id="menu.urs"
+               label="%menu.label"
+               mnemonic="%menu.mnemonic">
+            <command
+                  commandId="org.txm.annotation.urs.commands.SaveCorpus"
+                  style="push">
+               <visibleWhen
+                     checkEnabled="false">
+                  <reference
+                        definitionId="OneCorpusSelected">
+                  </reference>
+               </visibleWhen>
+            </command>
+            <command
+                  commandId="org.txm.annotation.urs.commands.RestoreAnnotations"
+                  style="push">
+               <visibleWhen
+                     checkEnabled="false">
+                  <reference
+                        definitionId="OneCorpusSelected">
+                  </reference>
+               </visibleWhen>
+            </command>
+            <menu
+                  id="menu.urs.tools"
+                  label="%menu.label.1">
+               <menu
+                     label="%menu.label.2">
+                  <dynamic
+                        class="org.txm.annotation.urs.commands.URSToolsMenuContribution"
+                        id="edit">
+                  </dynamic>
+               </menu>
+               <menu
+                     label="%menu.label.3">
+                  <dynamic
+                        class="org.txm.annotation.urs.commands.URSToolsMenuContribution"
+                        id="check">
+                  </dynamic>
+               </menu>
+               <menu
+                     label="%menu.label.4">
+                  <dynamic
+                        class="org.txm.annotation.urs.commands.URSToolsMenuContribution"
+                        id="exploit">
+                  </dynamic>
+               </menu>
+               <menu
+                     label="%menu.label.5">
+                  <dynamic
+                        class="org.txm.annotation.urs.commands.URSToolsMenuContribution"
+                        id="export">
+                  </dynamic>
+               </menu>
+               <command
+                     commandId="org.txm.annotation.urs.commands.OpenDemocratTools"
+                     style="push">
+               </command>
+            </menu>
+            <command
+                  commandId="org.txm.annotation.urs.commands.EditAnnotationStructure"
+                  style="push">
+               <visibleWhen
+                     checkEnabled="false">
+                  <reference
+                        definitionId="OneCorpusSelected">
+                  </reference>
+               </visibleWhen>
+            </command>
+            <command
+                  commandId="org.txm.annotation.urs.commands.EditVue"
+                  style="push">
+               <visibleWhen
+                     checkEnabled="false">
+                  <reference
+                        definitionId="OneCorpusSelected">
+                  </reference>
+               </visibleWhen>
+            </command>
+            <separator
+                  name="URSRCP.separator1"
+                  visible="true">
+            </separator>
+            <command
+                  commandId="org.txm.annotation.urs.commands.LoadStructureFromGlozz"
+                  style="push">
+               <visibleWhen
+                     checkEnabled="false">
+                  <reference
+                        definitionId="OneCorpusSelected">
+                  </reference>
+               </visibleWhen>
+            </command>
+         </menu>
+      </menuContribution>
+      <menuContribution
+            locationURI="popup:org.txm.rcp.views.corpora.CorporaView?after=org.txm.rcp.corporaview.annotation">
+         <menu
+               id="corpora.menu.urs"
+               label="%menu.label.0"
+               mnemonic="%menu.mnemonic.0">
+            <command
+                  commandId="org.txm.annotation.urs.commands.SaveCorpus"
+                  style="push">
+            </command>
+            <menu
+                  id="menu.urs.tools"
+                  label="%menu.label.1">
+               <menu
+                     label="%menu.label.2">
+                  <dynamic
+                        class="org.txm.annotation.urs.commands.URSToolsMenuContribution"
+                        id="edit">
+                  </dynamic>
+               </menu>
+               <menu
+                     label="%menu.label.3">
+                  <dynamic
+                        class="org.txm.annotation.urs.commands.URSToolsMenuContribution"
+                        id="check">
+                  </dynamic>
+               </menu>
+               <menu
+                     label="%menu.label.4">
+                  <dynamic
+                        class="org.txm.annotation.urs.commands.URSToolsMenuContribution"
+                        id="exploit">
+                  </dynamic>
+               </menu>
+               <menu
+                     label="%menu.label.5">
+                  <dynamic
+                        class="org.txm.annotation.urs.commands.URSToolsMenuContribution"
+                        id="export">
+                  </dynamic>
+               </menu>
+               <command
+                     commandId="org.txm.annotation.urs.commands.OpenDemocratTools"
+                     style="push">
+               </command>
+            </menu>
+            <command
+                  commandId="org.txm.annotation.urs.commands.EditAnnotationStructure"
+                  style="push">
+               <visibleWhen
+                     checkEnabled="false">
+                  <reference
+                        definitionId="OneCorpusSelected">
+                  </reference>
+               </visibleWhen>
+            </command>
+            <command
+                  commandId="org.txm.annotation.urs.commands.EditVue"
+                  style="push">
+               <visibleWhen
+                     checkEnabled="false">
+                  <reference
+                        definitionId="OneCorpusSelected">
+                  </reference>
+               </visibleWhen>
+            </command>
+            <separator
+                  name="URSRCP.separator1"
+                  visible="true">
+            </separator>
+            <command
+                  commandId="org.txm.annotation.urs.commands.LoadStructureFromGlozz"
+                  style="push">
+               <visibleWhen
+                     checkEnabled="false">
+                  <reference
+                        definitionId="OneCorpusSelected">
+                  </reference>
+               </visibleWhen>
+            </command>
+            <command
+                  commandId="org.txm.annotation.urs.commands.ImportTEIAnnotations"
+                  style="push">
+               <visibleWhen
+                     checkEnabled="false">
+                  <reference
+                        definitionId="OneCorpusSelected">
+                  </reference>
+               </visibleWhen>
+            </command>
+            <menu
+                  label="%menu.label.6">
+               <command
+                     commandId="org.txm.annotation.urs.commands.ExportTEICorpus"
+                     label="%command.label.0"
+                     style="push">
+               </command>
+               <command
+                     commandId="org.txm.annotation.urs.commands.ExportGlozzCorpus"
+                     label="%command.label.1"
+                     style="push">
+               </command>
+            </menu>
+         </menu>
+      </menuContribution>
+      <menuContribution
+            locationURI="menu:menu.file.export.annotations">
+         <command
+               commandId="org.txm.annotation.urs.commands.ExportTEICorpus"
+               label="%command.label.0"
+               style="push">
+            <visibleWhen
+                  checkEnabled="false">
+               <reference
+                     definitionId="OneMainCorpusSelected">
+               </reference>
+            </visibleWhen>
+         </command>
+         <command
+               commandId="org.txm.annotation.urs.commands.ExportGlozzCorpus"
+               label="%command.label.1"
+               style="push">
+            <visibleWhen
+                  checkEnabled="false">
+               <reference
+                     definitionId="OneMainCorpusSelected">
+               </reference>
+            </visibleWhen>
+         </command>
+      </menuContribution>
+      <menuContribution
+            locationURI="menu:menu.file.import.corpus?before=menu.file.import.separator.software">
+         <command
+               commandId="org.txm.annotation.urs.commands.ImportGlozzCorpus"
+               style="push">
+         </command>
+         <command
+               commandId="org.txm.annotation.urs.commands.ImportTEICorpus"
+               label="%command.label.2"
+               style="push">
+         </command>
+      </menuContribution>
+      <menuContribution
+            locationURI="menu:menu.help.plugins">
+         <command
+               commandId="org.txm.rcp.commands.OpenBrowser"
+               label="%command.label.3"
+               style="push">
+            <parameter
+                  name="org.txm.rcp.commands.commandParameter2"
+                  value="https://groupes.renater.fr/wiki/txm-users/public/extensions_beta#urs">
+            </parameter>
+         </command>
+      </menuContribution>
+      <menuContribution
+            allPopups="false"
+            locationURI="toolbar:org.txm.rcp.toolbarcorpus?after=org.txm.rcp.toolbarcorpus.annotation">
+         <command
+               commandId="org.txm.annotation.urs.commands.SaveCorpus"
+               icon="platform:/plugin/org.txm.annotation.rcp/icons/functions/pencil_save.png"
+               label="URS"
+               mode="FORCE_TEXT"
+               style="push"
+               tooltip="URS">
+         </command>
+      </menuContribution>
+      <menuContribution
+            locationURI="menu:menu.file.import.annotations">
+         <command
+               commandId="org.txm.annotation.urs.commands.ImportTEIAnnotations"
+               style="push">
+            <visibleWhen
+                  checkEnabled="false">
+               <reference
+                     definitionId="OneCorpusSelected">
+               </reference>
+            </visibleWhen>
+         </command>
+      </menuContribution>
+   </extension>
+   <extension
+         point="org.eclipse.ui.commands">
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.LoadStructure"
+            id="org.txm.annotation.urs.commands.LoadStructure"
+            name="%command.name">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.EditStructure"
+            id="org.txm.annotation.urs.commands.EditAnnotationStructure"
+            name="%command.name.0">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.SaveStructure"
+            id="org.txm.annotation.urs.commands.SaveStructure"
+            name="%command.name.1">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.LoadStructureFromGlozz"
+            id="org.txm.annotation.urs.commands.LoadStructureFromGlozz"
+            name="%command.name.2">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.LoadCorpus"
+            id="org.txm.annotation.urs.commands.LoadCorpus"
+            name="%command.name.3">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.SaveCorpus"
+            id="org.txm.annotation.urs.commands.SaveCorpus"
+            name="%command.name.4">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.RestoreAnnotations"
+            id="org.txm.annotation.urs.commands.RestoreAnnotations"
+            name="%command.name.17">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.LoadVue"
+            id="org.txm.annotation.urs.commands.LoadVue"
+            name="%command.name.5">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.SaveVue"
+            id="org.txm.annotation.urs.commands.SaveVue"
+            name="%command.name.6">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.SaveStructureAsGlozzModel"
+            id="org.txm.annotation.urs.commands.SaveStructureAsGlozzModel"
+            name="%command.name.7">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.ImportGlozzCorpus"
+            id="org.txm.annotation.urs.commands.ImportGlozzCorpus"
+            name="%command.name.8">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.ImportGlozzAnnotations"
+            id="org.txm.annotation.urs.commands.ImportGlozzAnnotations"
+            name="%command.name.9">
+      </command>
+      <command
+            defaultHandler="org.txm.annotation.urs.commands.DoInstallStep"
+            id="org.txm.annotation.urs.commands.DoInstallStep"
+            name="%command.name.10">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.ExportGlozzCorpus"
+            id="org.txm.annotation.urs.commands.ExportGlozzCorpus"
+            name="%command.name.12">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.ExportTEICorpus"
+            id="org.txm.annotation.urs.commands.ExportTEICorpus"
+            name="%command.name.13">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.ImportTEICorpus"
+            id="org.txm.annotation.urs.commands.ImportTEICorpus"
+            name="%command.name.14">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.ImportTEIAnnotations"
+            id="org.txm.annotation.urs.commands.ImportTEIAnnotations"
+            name="%command.name.11">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.EditVue"
+            id="org.txm.annotation.urs.commands.EditVue"
+            name="%command.name.16">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.urs.commands.OpenDemocratTools"
+            id="org.txm.annotation.urs.commands.OpenDemocratTools"
+            name="%command.name.18">
+      </command>
+   </extension>
+   <extension
+         point="org.eclipse.ui.views">
+      <view
+            allowMultiple="false"
+            category="org.txm.rcp"
+            class="org.txm.annotation.urs.view.ElementPropertiesView"
+            icon="icons/pencil.png"
+            id="org.txm.annotation.urs.view.ElementPropertiesView"
+            name="%view.name"
+            restorable="true">
+      </view>
+      <view
+            allowMultiple="false"
+            category="org.txm.rcp"
+            class="org.txm.annotation.urs.view.ElementSearchView"
+            icon="platform:/plugin/org.txm.rcp/icons/functions/Search.png"
+            id="org.txm.annotation.urs.view.ElementSearchView"
+            name="%view.name.0"
+            restorable="true">
+      </view>
+   </extension>
+   <extension
+         point="org.txm.rcp.extentionpoint.command">
+      <installcommand
+            class="org.txm.annotation.urs.commands.DoInstallStep"></installcommand>
+   </extension>
+   <extension
+         point="org.eclipse.core.expressions.definitions">
+      <definition
+            id="CanAnnotateWithURS">
+         <test
+               forcePluginActivation="true"
+               property="org.txm.annotation.urs.testers.canAnnotate">
+         </test>
+      </definition>
+      <definition
+            id="CorpusNeedtoSaveURSAnnotation">
+         <and>
+            <reference
+                  definitionId="OneMainCorpusSelected">
+            </reference>
+            <test
+                  forcePluginActivation="true"
+                  property="org.txm.annotation.urs.rcp.testers.IsURSCorpusDirty">
+            </test>
+         </and>
+      </definition>
+   </extension>
+   <extension
+         point="org.eclipse.core.expressions.propertyTesters">
+      <propertyTester
+            class="org.txm.annotation.urs.testers.IsCorpusAnnotated"
+            id="org.txm.annotation.urs.testers.IsCorpusAnnotated"
+            namespace="org.txm.annotation.urs.testers"
+            properties="canAnnotate"
+            type="java.lang.Object">
+      </propertyTester>
+   </extension>
+   <extension
+         point="org.eclipse.ui.preferencePages">
+      <page
+            category="org.txm.annotation.rcp.preferences.AnnotationPreferencePage"
+            class="org.txm.annotation.urs.preferences.URSPreferencePage"
+            id="org.txm.annotation.urs.preferences.URSPreferencePage"
+            name="%page.name.0">
+      </page>
+      <page
+            category="org.txm.searchengine.rcp.preferences.SearchEnginePreferencesPage"
+            class="org.txm.annotation.urs.preferences.URSSearchPreferencePage"
+            id="org.txm.annotation.urs.preferences.URSSearchPreferencePage"
+            name="%page.name.1">
+      </page>
+   </extension>
+   <extension
+         point="org.txm.annotation.rcp.editor.AnnotationArea">
+      <annotationtoolbar
+            class="org.txm.annotation.urs.toolbar.UnitToolbar"
+            position="1">
+      </annotationtoolbar>
+      <annotationtoolbar
+            class="org.txm.annotation.urs.toolbar.SchemaToolbar"
+            position="2">
+      </annotationtoolbar>
+      <annotationtoolbar
+            class="org.txm.annotation.urs.toolbar.UnitConcordanceToolbar"
+            position="4">
+      </annotationtoolbar>
+   </extension>
+   <extension
+         point="org.txm.PostTXMHOMEInstallationStep">
+      <PostTXMHOMEInstallationStep
+            class="org.txm.annotation.urs.InstallURSFiles"
+            description="%PostTXMHOMEInstallationStep.description"
+            name="URS macro">
+      </PostTXMHOMEInstallationStep>
+   </extension>
+   <extension
+         point="org.txm.annotation.core.AnnotationEngine">
+      <AnnotationEngine
+            class="org.txm.annotation.urs.URSCorpora"
+            description="URS annotations">
+      </AnnotationEngine>
+   </extension>
+   <extension
+         point="org.txm.searchengine.core.SearchEngine">
+      <SearchEngine
+            class="org.txm.annotation.urs.search.URSSearchEngine">
+      </SearchEngine>
+   </extension>
+   <extension
+         point="org.eclipse.core.runtime.preferences">
+      <initializer
+            class="org.txm.annotation.urs.preferences.URSPreferences">
+      </initializer>
+   </extension>
+   <extension
+         point="org.eclipse.core.expressions.propertyTesters">
+      <propertyTester
+            class="org.txm.annotation.urs.rcp.testers.IsURSCorpusDirty"
+            id="org.txm.annotation.urs.rcp.testers.IsURSCorpusDirty"
+            namespace="org.txm.annotation.urs.rcp.testers"
+            properties="IsURSCorpusDirty"
+            type="java.lang.Object">
+      </propertyTester>
+   </extension>
+
+</plugin>

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/plugin.xml
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauCommandesUnites.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauCommandesUnites.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauCommandesUnites.java	(revision 3653)
@@ -0,0 +1,276 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.Message.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.elements.*;
+import visuAnalec.texte.*;
+import visuAnalec.texte.PanneauAffTexte.*;
+import visuAnalec.texte.PanneauTexte.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class PanneauCommandesUnites extends PanneauCommandes implements ActionListener {
+  private PanneauChamps panneauChamps;
+  public TypeComboBox saisieTypeUnites;
+  private ElementComboBox saisieUnite;
+  private JButton creeUnite;
+  private JButton supprimeUnite;
+  private JButton rectifieBorne;
+  private int[] bornesSelectTexte;
+
+  /*
+   * CREATION PAR LE PANNEAU EDITEUR
+   */
+  PanneauCommandesUnites(Vue vue, PanneauAffTexte pTexte, PanneauChamps pChamps) {
+    super(vue, pTexte);
+    JToolBar barre1 = new JToolBar("Gestion des unités");
+    barre1.setPreferredSize(new Dimension(0, 22));
+//    barre1.setBackground(PanneauTexte.getCouleurFond1());
+    barre1.setAlignmentX(0.0f);
+    add(barre1);
+    panneauChamps = pChamps;
+    saisieTypeUnites = new TypeComboBox(Unite.class);
+    saisieTypeUnites.addActionListener(this);
+    saisieUnite = new ElementComboBox();
+    saisieUnite.addActionListener(this);
+    creeUnite = new JButton(new GAction("Créer") {
+      public void executer() {
+        creerUnite();
+      }
+    });
+    supprimeUnite = new JButton(new GAction("Supprimer") {
+      public void executer() {
+        supprimerUnite();
+      }
+    });
+    rectifieBorne = new JButton(new GAction("Rectifier une borne") {
+      public void executer() {
+        modifierBorne();
+      }
+    });
+    barre1.addSeparator();
+    barre1.add(new TitreBarre("Unité : ", PanneauTexte.getCouleurFond1()));
+    barre1.addSeparator();
+    barre1.add(saisieTypeUnites);
+    barre1.add(saisieUnite);
+    barre1.addSeparator();
+    barre1.add(creeUnite);
+    barre1.addSeparator();
+    barre1.add(supprimeUnite);
+    barre1.addSeparator();
+    barre1.add(rectifieBorne);
+  }
+
+  /*
+   * COMMANDES UTILISEES PAR LE PANNEAU EDITEUR
+   */
+  public void reinitialiser() {
+    // typiquement, appelé par le panneau éditeur à la suite d'une modif de vue ou de structure
+    saisieTypeUnites.removeActionListener(this);
+    saisieTypeUnites.setModele(vue.getTypesUnitesAVoir());
+    saisieTypeUnites.effSelection();
+    saisieTypeUnites.addActionListener(this);
+    supprimeUnite.setEnabled(false);
+    rectifieBorne.setEnabled(false);
+    initSaisieUnite();
+    etatSelectRien();
+    revalidate();
+    repaint();
+  }
+  public void reafficher() {
+    // potentiellement appelé par le panneau éditeur ?
+    // appelé aussi par  traiterElementEvent
+    if (saisieUnite.pasdeSelection()) {
+      initSaisieUnite();
+      etatSelectRien();
+    } else {
+      Unite uniteCourante = (Unite) saisieUnite.getSelection();
+      initSaisieUnite(uniteCourante);
+      etatSelectUnite(uniteCourante);
+    }
+  }
+  public void elementSuivant(int sens) {
+    if (sens>0) saisieUnite.gotoSuivant();
+    else saisieUnite.gotoPrecedent();
+  }
+  public Element elementSelectionne() {
+    if (saisieUnite.pasdeSelection()) return null;
+    return saisieUnite.getSelection();
+  }
+  public void editerElement(Element elt) {
+    // appelé par le panneauEditeur : elt est forcément une unité
+    if (elt.getClass()!=Unite.class)
+      throw new UnsupportedOperationException("Erreur : classe incorrecte");
+    editerUnite((Unite) elt);
+  }
+  public ArrayList<ElementMarque> trouverElementsVises(Unite uniteVisee, TypeMarquage marqueUniteVisee,
+          boolean avecId) {
+    ArrayList<ElementMarque> eltsMarques = new ArrayList<ElementMarque>();
+    eltsMarques.add(new ElementMarque(uniteVisee, marqueUniteVisee,
+            avecId ? saisieUnite.getIdElement(uniteVisee) : null));
+    return eltsMarques;
+  }
+  public void traiterElementEvent(ElementEvent evt) {
+    // relayé par le panneau éditeur 
+    switch (evt.getModif()) {
+      case AJOUT_UNITE:
+        Unite unite = (Unite) evt.getElement();
+        editerUnite(unite);
+        return;
+      case SUP_UNITE:
+        if (evt.getElement()==saisieUnite.getSelection()) {
+          initSaisieUnite();
+          etatSelectRien();
+        } else {
+          reafficher();
+        }
+        return;
+      case BORNES_UNITE:
+        return;  // traité directement par le panneau Texte : à revoir ?
+      case AJOUT_RELATION:
+      case AJOUT_SCHEMA:
+      case SUP_RELATION:
+      case MODIF_SCHEMA:
+      case SUP_SCHEMA:
+      case MODIF_VALEUR:
+        reafficher();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getModif()+" oublié dans un switch");
+    }
+  }
+  void editerUnite(Unite unite) {
+    // appelé  par traiterElementEvent, 
+    // et aussi directement par le panneau éditeur quand il est sollicité par d'autres fenêtres
+    if (!unite.getType().equals(saisieTypeUnites.getTypeSelection())) {
+      saisieTypeUnites.removeActionListener(this);
+      saisieTypeUnites.setSelection(unite.getType());
+      saisieTypeUnites.addActionListener(this);
+    }
+    initSaisieUnite(unite);
+    etatSelectUnite(unite);
+  }
+  /*
+   * ACTIONS DE L'UTILISATEUR : CHANGEMENTS D'ETAT
+   */
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource()==saisieTypeUnites) {
+        initSaisieUnite();
+        if (bornesSelectTexte==null) etatSelectRien();
+        else {
+          panneauTexte.getCaret().setSelectionVisible(true);
+          etatSelectTexte();
+        }
+        return;
+      }
+      if (evt.getSource()==saisieUnite) {
+        if (saisieUnite.pasdeSelection()) etatSelectRien();
+        else etatSelectUnite((Unite) saisieUnite.getSelection());
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  @Override
+  public void traiterSourisEvent(SourisEvent evt) {
+    switch (evt.getTypeEvent()) {
+      case SELECT_RIEN:
+        saisieUnite.effSelection();
+        bornesSelectTexte = null;
+        return;
+      case SELECT_TEXTE:
+        saisieUnite.removeActionListener(this);
+        saisieUnite.effSelection();
+        saisieUnite.addActionListener(this);
+        bornesSelectTexte = evt.getBornesSelectionTexte();
+        etatSelectTexte();
+        return;
+      case SELECT_ELEMENT:
+        saisieUnite.setSelection(evt.getElementVise());
+        bornesSelectTexte = null;
+        return;
+    }
+    throw new UnsupportedOperationException("Evénement non prévu : "+evt.getTypeEvent());
+  }
+  /*
+   * ACTIONS DE L'UTILISATEUR : BOUTONS
+   */
+  private void creerUnite() {
+    if (vue.getCorpus().checkPresenceUnite(saisieTypeUnites.getTypeSelection(), bornesSelectTexte[0], bornesSelectTexte[1])
+            &&!GMessages.confirmationAction("Dupliquer cette unité  ?")) return;
+    vue.getCorpus().addUniteSaisie(saisieTypeUnites.getTypeSelection(), bornesSelectTexte[0], bornesSelectTexte[1]);
+  }
+  private void supprimerUnite() {
+    if (!GMessages.confirmationAction("Supprimer l'unité sélectionnée ?"))
+      return;
+    vue.getCorpus().supUnite((Unite) saisieUnite.getSelection());
+  }
+  private void modifierBorne() {
+    panneauTexte.rectifierBorneUnite((Unite) saisieUnite.getSelection());
+  }
+  /* 
+   * GESTION INTERNE
+   */
+  private void etatSelectUnite(Unite unite) {  // une unité est sélectionnée
+    panneauTexte.saisir(unite, new Unite[]{unite}, TypeMarquage.SELECT1);
+    //           (Unite[]) saisieUnite.getElements(), TypeMarquage.FOND1);
+    panneauChamps.afficher(unite);
+    creeUnite.setEnabled(false);
+    supprimeUnite.setEnabled(true);
+    rectifieBorne.setEnabled(true);
+  }
+  private void etatSelectRien() {  // rien n'est sélectionné
+    if (saisieTypeUnites.pasdeSelection()) panneauTexte.pasDeMarquage();
+    else
+      panneauTexte.saisir(null, (Unite[]) saisieUnite.getElements(), TypeMarquage.FOND1);
+    panneauChamps.effacer();
+    creeUnite.setEnabled(false);
+    supprimeUnite.setEnabled(false);
+    rectifieBorne.setEnabled(false);
+  }
+  private void etatSelectTexte() {    // du texte est sélectionné
+    panneauTexte.pasDeMarquage();
+//    if (saisieTypeUnites.pasdeSelection()) panneauTexte.pasDeMarquage();
+//    else panneauTexte.saisir(null, (Unite[]) saisieUnite.getElements(), TypeMarquage.FOND1);
+    panneauChamps.effacer();
+    if (!saisieTypeUnites.pasdeSelection()) {
+      creeUnite.setEnabled(true);
+//      Boutons.setDefaut(creeUnite, true);
+    }
+    supprimeUnite.setEnabled(false);
+    rectifieBorne.setEnabled(false);
+  }
+  private void initSaisieUnite(Unite unit) {
+    saisieUnite.removeActionListener(this);
+    if (saisieTypeUnites.pasdeSelection()) saisieUnite.setModeleVide();
+    else {
+      String type0 = saisieTypeUnites.getTypeSelection();
+      Unite[] unites = vue.getUnitesAVoir(type0);
+      saisieUnite.setModele(unites, vue.getIdUnites(type0, unites));
+    }
+    if (unit==null) saisieUnite.effSelection();
+    else saisieUnite.setSelection(unit);
+    saisieUnite.addActionListener(this);
+    saisieUnite.revalidate();
+  }
+  private void initSaisieUnite() {
+    initSaisieUnite(null);
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauCommandesUnites.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauEditeur.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauEditeur.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauEditeur.java	(revision 3653)
@@ -0,0 +1,353 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec;
+
+import java.awt.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.text.Document;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.StyleConstants;
+import visuAnalec.Message.*;
+import visuAnalec.elements.*;
+import visuAnalec.texte.*;
+import visuAnalec.texte.PanneauTexte.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.vue.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class PanneauEditeur extends JPanel implements VueListener {
+  private enum Commandes {
+    GESTION_UNITES,
+    GESTION_RELATIONS,
+    GESTION_SCHEMAS,
+    MODIF_TEXTE;
+    private static Commandes getCommande(Class<? extends Element> classe) {
+      if (classe==Unite.class) return GESTION_UNITES;
+      if (classe==Relation.class) return GESTION_RELATIONS;
+      if (classe==Schema.class) return GESTION_SCHEMAS;
+      throw new UnsupportedOperationException("sous-classe non traitée");
+    }
+  }
+  private Vue vue;
+  private PanneauAffTexte panneauTexte;
+  private JPanel panneauOccurrences;
+  private PanneauChamps panneauChamps;
+  private Commandes commandes = null;
+  private HashMap<Commandes, PanneauCommandes> panneauxCommandes =
+          new HashMap<Commandes, PanneauCommandes>();
+  private HashMap<Commandes, String> titresPanneauxCommandes =
+          new HashMap<Commandes, String>();
+  private JDialog fenetreModifTexte;
+  private PanneauModifTexte panneauModifTexte;
+  private PanneauCommandesModifTexte panneauCommandesModifTexte;
+  private String recherche = "";
+  private Element elementCourant;
+
+  public static class ElementMarque {
+    public Element elt;
+    public String id;
+    public TypeMarquage marque;
+    public ElementMarque(Element elt, TypeMarquage marque, String id) {
+      this.elt = elt;
+      this.id = id;
+      this.marque = marque;
+    }
+  }
+
+  public static abstract class PanneauCommandes extends Box {
+    protected Vue vue;
+    protected PanneauAffTexte panneauTexte;
+    PanneauCommandes(Vue vue, PanneauAffTexte panneauTexte) {
+      super(BoxLayout.Y_AXIS);
+      this.vue = vue;
+      this.panneauTexte = panneauTexte;
+    }
+    public Vue getVue() {
+      return vue;
+    }
+    abstract public void reafficher();        // quand la vue n'a pas changé
+    abstract public void reinitialiser();     // quand la vue a changé
+    abstract public void elementSuivant(int sens);
+    abstract public Element elementSelectionne();
+    abstract public void editerElement(Element elt);
+    abstract public void traiterElementEvent(ElementEvent evt);
+    abstract public void traiterSourisEvent(PanneauAffTexte.SourisEvent evt);   // appelée par le panneau AffTexte
+    abstract public ArrayList<ElementMarque> trouverElementsVises(Unite uniteVisee,
+            TypeMarquage marqueUniteVisee, boolean avecId);  // appelée par le panneau AffTexte
+  }
+  public PanneauEditeur(Vue vue) {
+    super(new BorderLayout());
+    this.vue = vue;
+    vue.addEventListener(this);
+    setBorder(new TitledBorder(""));
+    panneauOccurrences = new JPanel(new BorderLayout());
+    panneauTexte = new PanneauAffTexte(vue.getCorpus());
+    panneauOccurrences.add(new JScrollPane(panneauTexte), BorderLayout.CENTER);
+    panneauChamps = new PanneauChamps(this, vue);
+    add(new JSplitPane(JSplitPane.VERTICAL_SPLIT, panneauOccurrences, panneauChamps), BorderLayout.CENTER);
+    // Les différents panneaux de commandes 
+    panneauxCommandes.put(Commandes.GESTION_UNITES,
+            new PanneauCommandesUnites(vue, panneauTexte, panneauChamps));
+    titresPanneauxCommandes.put(Commandes.GESTION_UNITES, "Gestion des unités");
+    panneauxCommandes.put(Commandes.GESTION_RELATIONS,
+            new PanneauCommandesRelations(vue, panneauTexte, panneauChamps));
+    titresPanneauxCommandes.put(Commandes.GESTION_RELATIONS, "Gestion des relations");
+    panneauxCommandes.put(Commandes.GESTION_SCHEMAS,
+            new PanneauCommandesSchemas(vue, panneauTexte, panneauChamps));
+    titresPanneauxCommandes.put(Commandes.GESTION_SCHEMAS, "Gestion des schémas");
+    new GActionClavier(this, "suivant", "F1", "control DOWN") {
+      public void executer() {
+        elementSuivant(1);
+      }
+    };
+    new GActionClavier(this, "précédent", "F2", "control UP") {
+      public void executer() {
+        elementSuivant(-1);
+      }
+    };
+    new GActionClavier(this, "copier", "F3", "control M") {
+      public void executer() {
+        copierElement();
+      }
+    };
+    new GActionClavier(this, "coller", "F4", "control R") {
+      public void executer() {
+        collerElement();
+      }
+    };
+    // La fenêtre modale pour éditer le texte
+    fenetreModifTexte = new JDialog((VisuMain) getTopLevelAncestor(), true);
+    fenetreModifTexte.setUndecorated(true);
+    fenetreModifTexte.getContentPane().setLayout(new BorderLayout());
+    panneauModifTexte = new PanneauModifTexte(vue.getCorpus());
+    fenetreModifTexte.getContentPane().add(new JScrollPane(panneauModifTexte), BorderLayout.CENTER);
+    panneauCommandesModifTexte = new visuAnalec.texte.PanneauCommandesModifTexte(this, vue, panneauModifTexte);
+    panneauModifTexte.setCommandesModifTexte(panneauCommandesModifTexte);
+    fenetreModifTexte.getContentPane().add(panneauCommandesModifTexte, BorderLayout.SOUTH);
+    fenetreModifTexte.setVisible(false);
+    // Panneau initial : gestion des unités
+    changerPanneauCommandes(Commandes.GESTION_UNITES);
+    reinitCommandes();
+
+  }
+  void agencerPanneaux() {
+    JSplitPane split = (JSplitPane) panneauOccurrences.getParent();
+    split.setDividerLocation(2./3);
+    revalidate();
+    repaint();
+  }
+  private void changerPanneauCommandes(Commandes newCommandes) {
+    if (commandes!=null)
+      panneauOccurrences.remove(panneauxCommandes.get(commandes));
+    commandes = newCommandes;
+    panneauOccurrences.add(panneauxCommandes.get(commandes), BorderLayout.NORTH);
+    ((TitledBorder) getBorder()).setTitle(titresPanneauxCommandes.get(commandes));
+    panneauTexte.setCommandes(panneauxCommandes.get(commandes));
+    revalidate();
+    repaint();
+  }
+  private void reinitCommandes() {
+    panneauxCommandes.get(commandes).reinitialiser();
+  }
+  private void elementSuivant(int sens) {
+    panneauxCommandes.get(commandes).elementSuivant(sens);
+  }
+  private void copierElement() {
+    Element elt = panneauxCommandes.get(commandes).elementSelectionne();
+    if (elt!=null) elementCourant = elt;
+  }
+  private void collerElement() {
+    if (elementCourant==null) return;
+    Element elt = panneauxCommandes.get(commandes).elementSelectionne();
+    if (elt==null) return;
+    vue.copierValeurs(elementCourant, elt);
+  }
+  private void reinitCommandes(Element elt) {
+    panneauxCommandes.get(commandes).reinitialiser();
+    panneauxCommandes.get(commandes).editerElement(elt);
+  }
+  private void reaffCommandes() {
+    panneauxCommandes.get(commandes).reafficher();
+  }
+  private void initNewCorpus() {
+    panneauTexte.setTexteVisu();
+    panneauTexte.initAscenseur();
+    colorierTexte();
+    changerPanneauCommandes(Commandes.GESTION_UNITES);
+    reinitCommandes();
+  }
+  private void colorierTexte() {
+    panneauTexte.setAttributsStandard(vue.getStyleTexte());
+    panneauTexte.colorierUnites(vue.getUnitesAColorier());
+  }
+  void initRechercherTexte() {
+    recherche = (String) JOptionPane.showInputDialog(this, "Recherche dans le texte",
+            "Rechercher", JOptionPane.PLAIN_MESSAGE, null, null, recherche);
+    if (recherche==null) recherche = "";
+    if (recherche.isEmpty()) return;
+    panneauTexte.rechercherTexte(recherche);
+  }
+  void rechercherSuivantTexte() {
+    if (recherche.isEmpty()) return;
+    panneauTexte.rechercherTexte(recherche);
+
+  }
+  void initModifierTexte() {
+    ((TitledBorder) getBorder()).setTitle("Modification du texte");
+    repaint();
+    fenetreModifTexte.setSize(panneauOccurrences.getSize());
+    fenetreModifTexte.setLocationRelativeTo(panneauOccurrences);
+    panneauChamps.effacer();
+    panneauModifTexte.init();
+    fenetreModifTexte.setModal(false);
+    fenetreModifTexte.setVisible(true);
+    panneauModifTexte.ajusterAscenseur(panneauTexte);
+    fenetreModifTexte.setVisible(false);
+    fenetreModifTexte.setModal(true);
+    fenetreModifTexte.setVisible(true);
+  }
+  public void finModifTexte() {
+    fenetreModifTexte.setVisible(false);
+    panneauTexte.ajusterAscenseur(panneauModifTexte);
+    if (commandes==null) {
+      changerPanneauCommandes(Commandes.GESTION_UNITES);
+      reinitCommandes();
+    } else {
+      ((TitledBorder) getBorder()).setTitle(titresPanneauxCommandes.get(commandes));
+      reaffCommandes();
+    }
+    repaint();
+  }
+  public void saisirStyleTexte(Vue vue) {
+    VisuStyleTexte.newVisuStyleTexte(this, vue.getStyleTexte());
+  }
+  public void changerStyleTexte(SimpleAttributeSet att) {
+    vue.setStyleTexte(att);
+    panneauTexte.setAttributsStandard(att);
+    panneauModifTexte.setAttributsStandard(att);
+    reaffCommandes();
+  }
+  public Document getTexteFormate() {
+    return panneauTexte.getDocument();
+  }
+  public void editerElement(Element elt) {
+    // typiquement, appelée de l'extérieur par d'autres fenêtres
+    changerPanneauCommandes(Commandes.getCommande(elt.getClass()));
+    reinitCommandes(elt);
+    ((VisuMain) getTopLevelAncestor()).premierPlan();
+  }
+  public void editerUniteChaine(Unite unit, Schema chaine) {
+    // appelée de l'extérieur notamment par visuChaines)
+    changerPanneauCommandes(Commandes.GESTION_SCHEMAS);
+    reinitCommandes();
+    ((PanneauCommandesSchemas) panneauxCommandes.get(commandes)).editerSchemaElement(chaine, unit);
+    ((VisuMain) getTopLevelAncestor()).premierPlan();
+  }
+  public void editerUniteTypeChaine(Unite unit, String typechaine) {
+    // appelée de l'extérieur notamment par visuChaines)
+    changerPanneauCommandes(Commandes.GESTION_SCHEMAS);
+    reinitCommandes();
+    ((PanneauCommandesSchemas) panneauxCommandes.get(commandes)).editerElementTypeSchema(unit, typechaine);
+    ((VisuMain) getTopLevelAncestor()).premierPlan();
+  }
+  void initGestionUnites() {
+    if (vue.getTypesUnitesAVoir().length==0) {
+      JOptionPane.showMessageDialog(getTopLevelAncestor(), "Aucun type d'unités n'est défini dans la vue actuelle",
+              "Saisie d'unités impossible", JOptionPane.ERROR_MESSAGE);
+      return;
+    }
+    changerPanneauCommandes(Commandes.GESTION_UNITES);
+    reinitCommandes();
+  }
+  void initGestionRelations() {
+    if (vue.getTypesRelationsAVoir().length==0) {
+      JOptionPane.showMessageDialog(getTopLevelAncestor(), "Aucun type de relation n'est défini dans la vue actuelle",
+              "Saisie de relations impossible", JOptionPane.ERROR_MESSAGE);
+      return;
+    }
+    changerPanneauCommandes(Commandes.GESTION_RELATIONS);
+    reinitCommandes();
+  }
+  void initGestionSchemas() {
+    if (vue.getTypesSchemasAVoir().length==0) {
+      JOptionPane.showMessageDialog(getTopLevelAncestor(), "Aucun type de schéma n'est défini dans la vue actuelle",
+              "Saisie de schéma impossible", JOptionPane.ERROR_MESSAGE);
+      return;
+    }
+    changerPanneauCommandes(Commandes.GESTION_SCHEMAS);
+    reinitCommandes();
+  }
+  public void traiterVueEvent(VueEvent evt) {
+    switch (evt.getModif()) {
+      case EXTRACTION:
+      case NEW_VUE:
+      case VUE_DEFAUT:
+        colorierTexte();
+        reinitCommandes();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getModif()+" oublié dans un switch");
+    }
+  }
+  public void traiterStructureEvent(StructureEvent evt) {
+    switch (evt.getModif()) {
+      case SUPPR_TYPE:
+      case FUSION_TYPE:
+      case RENOM_TYPE:
+      case AJOUT_TYPE:
+      case AJOUT_TYPE_ET_ELEMENTS:
+        colorierTexte();
+        reinitCommandes();
+        return;
+      case VALEUR_PAR_DEFAUT:
+      case AJOUT_FORME_UNITE:
+      case FUSION_PROP:
+      case RENOM_PROP:
+      case SUPPR_PROP:
+      case AJOUT_PROP:
+      case FUSION_VALEUR:
+      case RENOM_VALEUR:
+      case SUPPR_VALEUR:
+      case AJOUT_VALEUR:
+        colorierTexte();
+        panneauChamps.reafficher();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getModif()+" oublié dans un switch");
+    }
+  }
+  public void traiterEvent(Message evt) {
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        initNewCorpus();
+        return;
+      case NEW_CORPUS:
+        initNewCorpus();
+        return;
+      case MODIF_TEXTE:
+        panneauTexte.setTexteVisu();
+        return;
+      case MODIF_VUE:
+        traiterVueEvent((VueEvent) evt);
+        return;
+      case MODIF_STRUCTURE:
+        traiterStructureEvent((StructureEvent) evt);
+        return;
+      case MODIF_ELEMENT:
+        colorierTexte();
+        panneauxCommandes.get(commandes).traiterElementEvent((ElementEvent) evt);
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauEditeur.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauAffTexte.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauAffTexte.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauAffTexte.java	(revision 3653)
@@ -0,0 +1,318 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.texte;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.texte.PanneauAffTexte.ListenerSourisTexte.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import static visuAnalec.texte.PanneauAffTexte.SourisEvent.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class PanneauAffTexte extends PanneauTexte {
+  private PanneauCommandes panneauCommandes;
+  private ListenerSourisTexte sourisListener;
+  protected Marquage marquage = new Marquage(this);
+  public PanneauAffTexte(Corpus corpus) {
+    super(corpus);
+    coloriage = new Coloriage(this);
+    setEditable(false);
+    setSourisListener();
+  }
+  @Override
+  public String getToolTipText() {
+    Point pt = getMousePosition();
+    if (pt == null) return "";
+    Unite[] unitesVisees = getUnitesVisees(marquage, pt);
+    if (unitesVisees.length == 0) return "";
+    ArrayList<String> textes = new ArrayList<String>();
+    ArrayList<String> idsElementsVises = new ArrayList<String>();
+    for (Unite unit : unitesVisees) {
+      String texte = getTexteUnite(unit);
+      for (ElementMarque eltMarque : panneauCommandes.trouverElementsVises(unit,
+              marquage.getMarquage(unit), true)) {
+        idsElementsVises.add(eltMarque.id);
+        textes.add(texte);
+      }
+    }
+    return GVisu.styleIdTooltip(textes, idsElementsVises);
+  }
+  protected void setSourisListener() {
+    sourisListener = new ListenerSourisTexte(this);
+    addMouseListener(sourisListener);
+  }
+  public void setCommandes(PanneauCommandes panneauCommandes) {
+    this.panneauCommandes = panneauCommandes;
+    sourisListener.setCommandes(panneauCommandes);
+  }
+  private void deselecterUnite(Unite unite) {  // utilisé uniquement pour rectifier une borne
+    int debUnite = indexToPosition(unite.getDeb());
+    int finUnite = indexToPosition(unite.getFin());
+    doc.setCharacterAttributes(debUnite, finUnite - debUnite, AttributsStandard, true);
+  }
+  private void selecterUnite(Unite unite) {   // utilisé uniquement pour rectifier une borne
+    int debUnite = indexToPosition(unite.getDeb());
+    int finUnite = indexToPosition(unite.getFin());
+    doc.setCharacterAttributes(debUnite, finUnite - debUnite, SELECTION_1, true);
+  }
+  public void pasDeMarquage() {
+    marquerUnites(marquage, new TypeMarquage[0], null);
+    sourisListener.setEtat(EtatClic.SAISIE);
+  }
+  public void saisir(Unite amontrer, Unite[] lUnites, TypeMarquage type) {
+    TypeMarquage[] typesMarq = {type};
+    EnumMap<TypeMarquage, Unite[]> unites = new EnumMap<TypeMarquage, Unite[]>(TypeMarquage.class);
+    unites.put(type, lUnites);
+    marquerUnites(marquage, typesMarq, unites);
+    if (amontrer != null) placerAscenseur(amontrer);
+    sourisListener.setEtat(EtatClic.SAISIE);
+  }
+  public void saisir(Unite amontrer, Unite[] lUnites1, TypeMarquage type1, Unite[] lUnites2, TypeMarquage type2) {
+    TypeMarquage[] typesMarq = {type1, type2};
+    EnumMap<TypeMarquage, Unite[]> unites = new EnumMap<TypeMarquage, Unite[]>(TypeMarquage.class);
+    unites.put(type1, lUnites1);
+    unites.put(type2, lUnites2);
+    marquerUnites(marquage, typesMarq, unites);
+    if (amontrer != null) placerAscenseur(amontrer);
+    sourisListener.setEtat(EtatClic.SAISIE);
+  }
+  public void saisir(Unite amontrer, Unite[] lUnites1, TypeMarquage type1,
+          Unite[] lUnites2, TypeMarquage type2, Unite[] lUnites3, TypeMarquage type3) {
+    TypeMarquage[] typesMarq = {type1, type2, type3};
+    EnumMap<TypeMarquage, Unite[]> unites = new EnumMap<TypeMarquage, Unite[]>(TypeMarquage.class);
+    unites.put(type1, lUnites1);
+    unites.put(type2, lUnites2);
+    unites.put(type3, lUnites3);
+    marquerUnites(marquage, typesMarq, unites);
+    if (amontrer != null) placerAscenseur(amontrer);
+    sourisListener.setEtat(EtatClic.SAISIE);
+  }
+  public void saisir(Unite amontrer, Unite[] lUnites1, TypeMarquage type1, Unite[] lUnites2, TypeMarquage type2,
+          Unite[] lUnites3, TypeMarquage type3, Unite[] lUnites4, TypeMarquage type4) {
+    TypeMarquage[] typesMarq = {type1, type2, type3, type4};
+    EnumMap<TypeMarquage, Unite[]> unites = new EnumMap<TypeMarquage, Unite[]>(TypeMarquage.class);
+    unites.put(type1, lUnites1);
+    unites.put(type2, lUnites2);
+    unites.put(type3, lUnites3);
+    unites.put(type4, lUnites4);
+    marquerUnites(marquage, typesMarq, unites);
+    if (amontrer != null) placerAscenseur(amontrer);
+    sourisListener.setEtat(EtatClic.SAISIE);
+  }
+  public void rectifierBorneUnite(Unite unite) {
+    sourisListener.etatChtBornes(unite);
+  }
+  void changerBornes(Unite unite, int borneGauche, int borneDroite) {
+    corpus.modifBornesUnite(unite, borneGauche, borneDroite);
+  }
+
+  public static class SourisEvent {
+    public enum TypeEvent {
+      SELECT_TEXTE, SELECT_RIEN, SELECT_ELEMENT
+    }
+    private TypeEvent type;
+    private Element elementVise;
+    private TypeMarquage marquageElementVise;
+    private int[] bornesSelectionTexte;
+    protected SourisEvent(TypeEvent type) {
+      this(type, null, null, null);
+    }
+    protected SourisEvent(TypeEvent type, Element elt, TypeMarquage marque) {
+      this(type, elt, marque, null);
+    }
+    protected SourisEvent(TypeEvent type, int[] bornes) {
+      this(type, null, null, bornes);
+    }
+    protected SourisEvent(TypeEvent type, Element elt, TypeMarquage marque, int[] bornes) {
+      this.type = type;
+      marquageElementVise = marque;
+      bornesSelectionTexte = bornes;
+      elementVise = elt;
+    }
+    public TypeEvent getTypeEvent() {
+      return type;
+    }
+    public TypeMarquage getMarquageElementVise() {
+      return marquageElementVise;
+    }
+    public int[] getBornesSelectionTexte() {
+      return bornesSelectionTexte;
+    }
+    public Element getElementVise() {
+      return elementVise;
+    }
+  }
+
+  protected static class ListenerSourisTexte extends MouseAdapter {
+    enum EtatClic {
+      INACTIF,
+      SAISIE,
+      BORNES,
+    }
+    private EtatClic etatClic;
+    private Unite uniteABorner;
+    private PanneauAffTexte panneauTexte;
+    private PanneauCommandes panneauCommandes;
+    private JPopupMenuUnites popupMenuUnites;
+    public ListenerSourisTexte(PanneauAffTexte pTexte) {
+      panneauTexte = pTexte;
+      popupMenuUnites = new JPopupMenuUnites(pTexte);
+    }
+    void setCommandes(PanneauCommandes commandes) {
+      panneauCommandes = commandes;
+      popupMenuUnites.setCommandes(commandes);
+    }
+    void setEtat(EtatClic etat) {
+      this.etatClic = etat;
+    }
+    void etatChtBornes(Unite uniteABorner) {
+      etatClic = EtatClic.BORNES;
+      this.uniteABorner = uniteABorner;
+      int deb = panneauTexte.indexToPosition(uniteABorner.getDeb());
+      int fin = panneauTexte.indexToPosition(uniteABorner.getFin());
+      panneauTexte.doc.setCharacterAttributes(deb, fin - deb, BORNAGE, true);
+    }
+    @Override
+    public void mousePressed(MouseEvent e) {
+      if (e.isPopupTrigger()) mousePopup(e);
+    }
+    @Override
+    public void mouseReleased(MouseEvent e) {
+      try {
+        if (e.isPopupTrigger()) {
+          mousePopup(e);
+          return;
+        }
+        switch (etatClic) {
+          case INACTIF:
+          case BORNES:
+            return;
+          case SAISIE:
+            if (panneauTexte.getSelectedText() != null) panneauCommandes.traiterSourisEvent(new SourisEvent(
+                      TypeEvent.SELECT_TEXTE, panneauTexte.getIndSelection()));
+            return;
+          default:
+            throw new UnsupportedOperationException("Cas non prévu d'étatClic");
+        }
+      } catch (Throwable ex) {
+        GMessages.erreurFatale(ex);
+      }
+    }
+    @Override
+    public void mouseClicked(MouseEvent e) {
+      try {
+        if (e.getButton() != MouseEvent.BUTTON1) return;
+        if (e.getClickCount() > 1) return;
+        switch (etatClic) {
+          case INACTIF:  // peut-être inutile ??
+            return;
+          case SAISIE:
+            Unite uniteVisee = panneauTexte.getUniteVisee(panneauTexte.marquage, e.getPoint());
+            if (uniteVisee == null) {
+              panneauCommandes.traiterSourisEvent(new SourisEvent(TypeEvent.SELECT_RIEN));
+              return;
+            }
+            ElementMarque eltM = panneauCommandes.trouverElementsVises(uniteVisee,
+                    panneauTexte.marquage.getMarquage(uniteVisee), false).get(0);
+            panneauCommandes.traiterSourisEvent(new SourisEvent(TypeEvent.SELECT_ELEMENT,
+                    eltM.elt, eltM.marque));
+            return;
+          case BORNES: // à revoir
+            int olddeb = uniteABorner.getDeb();
+            int oldfin = uniteABorner.getFin();
+            int newdeb = olddeb;
+            int newfin = oldfin;
+            int newborne = panneauTexte.positionToIndex(panneauTexte.viewToModel(e.getPoint()));
+            if (2 * newborne < olddeb + oldfin) newdeb = newborne;
+            else newfin = newborne;
+            panneauTexte.deselecterUnite(uniteABorner);
+            panneauTexte.changerBornes(uniteABorner, newdeb, newfin);
+            panneauTexte.selecterUnite(uniteABorner);
+            etatClic = EtatClic.SAISIE;
+            return;
+          default:
+            throw new UnsupportedOperationException("Cas non prévu d'état d'AffTexte");
+        }
+      } catch (Throwable ex) {
+        GMessages.erreurFatale(ex);
+      }
+    }
+    public void mousePopup(MouseEvent e) {
+      Unite[] unitesVisees = panneauTexte.getUnitesVisees(panneauTexte.marquage, e.getPoint());
+      if (unitesVisees.length > 0) {
+        popupMenuUnites.reinitialiser(unitesVisees);
+        popupMenuUnites.show(e.getComponent(), e.getX(), e.getY());
+      }
+    }
+  }
+
+  private static class JPopupMenuUnites extends JPopupMenu {
+    private PanneauAffTexte panneauTexte;
+    private PanneauCommandes panneauCommandes;
+    private ArrayList<ElementMarque> elementsMarques = new ArrayList<ElementMarque>();
+    private Element[] elementsVises;
+    private String[] idsElementsVises;
+    private TypeMarquage[] marquesElementsVises;
+    public JPopupMenuUnites(PanneauAffTexte panneauTexte) {
+      super();
+      this.panneauTexte = panneauTexte;
+    }
+    void setCommandes(PanneauCommandes commandes) {
+      panneauCommandes = commandes;
+    }
+    void reinitialiser(Unite[] unitesVisees) {
+      removeAll();
+      elementsMarques.clear();
+      elementsVises = new Element[unitesVisees.length];
+      idsElementsVises = new String[unitesVisees.length];
+      marquesElementsVises = new TypeMarquage[unitesVisees.length];
+      int no = 0;
+      ArrayList<ElementMarque> eltsMARajouter = new ArrayList<ElementMarque>();
+      ArrayList<String> descrsARajouter = new ArrayList<String>();
+      for (Unite unit : unitesVisees) {
+        String texte = panneauTexte.getTexteUnite(unit);
+        ArrayList<TypeMarquage> typesM = panneauTexte.marquage.getMarquages(unit);
+        for (ElementMarque eltM : panneauCommandes.trouverElementsVises(unit, typesM.get(0), true)) {
+          elementsMarques.add(eltM);
+          String descr = GVisu.styleIdPopup(texte, eltM.id);
+          add(new ActionSelectionUnites(descr, no++));
+        }
+        for (TypeMarquage typeM : typesM.subList(1, typesM.size()))
+          for (ElementMarque eltM : panneauCommandes.trouverElementsVises(unit, typeM, true)) {
+            eltsMARajouter.add(eltM);
+            descrsARajouter.add(GVisu.styleIdPopup(texte, eltM.id));
+          }
+      }
+      for (int i = 0; i < eltsMARajouter.size(); i++) {
+        elementsMarques.add(eltsMARajouter.get(i));
+        add(new ActionSelectionUnites(descrsARajouter.get(i), no++));
+      }
+    }
+
+    private class ActionSelectionUnites extends GAction {
+      int no;
+      private ActionSelectionUnites(String descr, int no) {
+        super(descr);
+        this.no = no;
+      }
+      public void executer() {
+        panneauCommandes.traiterSourisEvent(new SourisEvent(TypeEvent.SELECT_ELEMENT,
+                elementsMarques.get(no).elt, elementsMarques.get(no).marque));
+      }
+    }
+  }
+}
+
+      
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauAffTexte.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauModifTexte.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauModifTexte.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauModifTexte.java	(revision 3653)
@@ -0,0 +1,170 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.texte;
+
+import java.util.*;
+import javax.swing.event.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class PanneauModifTexte extends PanneauTexte implements DocumentListener {
+  protected static class BorneUnite implements Comparable {
+    public Unite unite;
+    public int pos;
+    public BorneUnite(Unite unite, int pos) {
+      this.unite = unite;
+      this.pos = pos;
+    }
+    public int compareTo(Object obj) {
+      if (obj.getClass() != BorneUnite.class) {
+        throw new ClassCastException("Comparaison impossible : " + obj.toString() +
+                " n'est pas une instance de BorneUnite");
+      }
+      int comp = Integer.signum(pos - (((BorneUnite) obj).pos));
+      if (comp == 0) {
+        comp = -Integer.signum(unite.getFin() - unite.getDeb() - ((BorneUnite) obj).unite.getFin() +
+                ((BorneUnite) obj).unite.getDeb());
+      }
+      return comp;
+    }
+  }
+  private PanneauCommandesModifTexte panneauCommandes;
+  private BorneUnite[] bornesGauches;
+  private BorneUnite[] bornesDroites;
+  public PanneauModifTexte(Corpus corpus) {
+    super(corpus);
+    setEditable(true);
+  }
+  public void setCommandesModifTexte(PanneauCommandesModifTexte panneauCommandes) {
+    this.panneauCommandes = panneauCommandes;
+  }
+  void setBornesModifTexte() {
+    ArrayList<Unite> units = corpus.getToutesUnites();
+    bornesGauches = new BorneUnite[units.size()];
+    bornesDroites = new BorneUnite[units.size()];
+    for (int i = 0; i < units.size(); i++) {
+      Unite unite = units.get(i);
+      bornesGauches[i] = new BorneUnite(unite, unite.getDeb());
+      bornesDroites[i] = new BorneUnite(unite, unite.getFin());
+    }
+    Arrays.sort(bornesGauches);
+    Arrays.sort(bornesDroites);
+
+  }
+  public void init() {
+    doc.removeDocumentListener(this);
+    setTexteVisu();
+    setEditable(true);
+    doc.setParagraphAttributes(0, getText().length(), AttributsStandard, true);
+    doc.setCharacterAttributes(0, getText().length(), AttributsStandard, true);
+    setBornesModifTexte();
+    doc.addDocumentListener(this);
+  }
+  public int preparerValiderModifTexte() {
+    Comparator<BorneUnite> comp = new Comparator<BorneUnite>() {
+      public int compare(BorneUnite b1, BorneUnite b2) {
+        return b1.unite.compareTo(b2.unite);
+      }
+    };
+    Arrays.sort(bornesGauches, comp);
+    Arrays.sort(bornesDroites, comp);
+    int nbSupprimes = 0;
+    for (int i = 0; i < bornesGauches.length; i++) {
+      if (bornesGauches[i].pos == bornesDroites[i].pos) {
+        nbSupprimes++;
+      }
+    }
+    return nbSupprimes;
+  }
+  public void validerModifTexte() {
+    for (int i = 0; i < bornesGauches.length; i++) {
+      Unite unite = bornesGauches[i].unite;
+      if (bornesGauches[i].pos == unite.getDeb() && bornesDroites[i].pos == unite.getFin()) {
+        continue;
+      }
+      if (bornesGauches[i].pos == bornesDroites[i].pos) {
+        corpus.supUnite(unite);
+      } else {
+        corpus.modifBornesUnite(unite, bornesGauches[i].pos, bornesDroites[i].pos);
+      }
+    }
+    setEditable(false);
+    setTexteCorpus();  // Corpus enverra l'événement MODIF_TEXTE à tous les panneaux occurrence
+  }
+  public void insertUpdate(DocumentEvent evt) {
+    try {
+      String texte = getText();
+      int debutInsertion = positionToIndex(evt.getOffset());
+      int lengthInsertion = evt.getLength();
+      int iIns = 0;
+      while (iIns < posNewLines.size() && posNewLines.get(iIns) < evt.getOffset()) {
+        iIns++;
+      }
+      for (int ind = iIns; ind < posNewLines.size(); ind++) {
+        posNewLines.set(ind, posNewLines.get(ind) + evt.getLength());
+      }
+      for (int pos = evt.getOffset(); pos < evt.getOffset() + evt.getLength(); pos++) {
+        if (texte.charAt(pos) == '\n') {
+          lengthInsertion--;
+          posNewLines.add(iIns++, pos);
+        }
+      }
+      shiftDroitBornes(bornesGauches, debutInsertion, lengthInsertion);
+      shiftDroitBornes(bornesDroites, debutInsertion, lengthInsertion);
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  public void removeUpdate(DocumentEvent evt) {
+    try {
+      int debutSuppression = positionToIndex(evt.getOffset());
+      int lengthSuppression = evt.getLength();
+      int iSup = 0;
+      while (iSup < posNewLines.size() && posNewLines.get(iSup) < evt.getOffset()) {
+        iSup++;
+      }
+      while (iSup < posNewLines.size() && posNewLines.get(iSup) < evt.getOffset() + evt.getLength()) {
+        posNewLines.remove(iSup);
+        lengthSuppression--;
+      }
+      for (int ind = iSup; ind < posNewLines.size(); ind++) {
+        posNewLines.set(ind, posNewLines.get(ind) - evt.getLength());
+      }
+      shiftGaucheBornes(bornesGauches, debutSuppression, lengthSuppression);
+      shiftGaucheBornes(bornesDroites, debutSuppression, lengthSuppression);
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  public void changedUpdate(DocumentEvent evt) {
+    // rien à faire
+  }
+  void shiftDroitBornes(BorneUnite[] bornes, int deb, int shift) {
+    for (int i = bornes.length - 1; i >= 0; i--) {
+      if (bornes[i].pos < deb) {
+        return;
+      }
+      bornes[i].pos += shift;
+    }
+  }
+  void shiftGaucheBornes(BorneUnite[] bornes, int deb, int shift) {
+    for (int i = bornes.length - 1; i >= 0; i--) {
+      if (bornes[i].pos <= deb) {
+        return;
+      }
+      if (bornes[i].pos < deb + shift) {
+        bornes[i].pos = deb;
+      } else {
+        bornes[i].pos -= shift;
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauModifTexte.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauTexte.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauTexte.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauTexte.java	(revision 3653)
@@ -0,0 +1,542 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.texte;
+
+import java.awt.*;
+import java.util.*;
+import java.util.ArrayList;
+import javax.swing.*;
+import javax.swing.text.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class PanneauTexte extends JTextPane {
+  final private static Color ROUGE = new Color(0x800000);
+  final private static Color BLEU = new Color(0x000080);
+  final private static Color JAUNE_CLAIR = new Color(0xffffb0);
+  final private static Color JAUNE_TRES_CLAIR = new Color(0xffffe0);
+  final private static Color JAUNE_FONCE = new Color(0xffff60);
+  final private static Color VERT_CLAIR = new Color(0xd8f0ff);
+  final private static Color VERT_FONCE = new Color(0xb0d0ff);
+  final private static Color VIOLET_CLAIR = new Color(0xffd8e0);
+  final private static Color VIOLET_FONCE = new Color(0xffb0c0);
+  final public static SimpleAttributeSet STANDARD_DEFAUT = creerStyleStandardDefaut();
+  final protected static AttributeSet COLORATION_1 = creerCouleurFond(JAUNE_CLAIR);
+  final protected static AttributeSet COLORATION_1_MULTI = creerCouleurFond(JAUNE_FONCE);
+  final protected static AttributeSet COLORATION_2 = creerCouleurFond(VERT_CLAIR);
+  final protected static AttributeSet COLORATION_2_MULTI = creerCouleurFond(VERT_FONCE);
+  final protected static AttributeSet COLORATION_3 = creerCouleurFond(VIOLET_CLAIR);
+  final protected static AttributeSet COLORATION_3_MULTI = creerCouleurFond(VIOLET_FONCE);
+  final protected static AttributeSet SELECTION_1_1 = ajouterCouleurCar(COLORATION_1, BLEU);
+  final protected static AttributeSet SELECTION_1_1_MULTI = ajouterCouleurCar(COLORATION_1_MULTI,
+          BLEU);
+  final protected static AttributeSet SELECTION_1_2 = ajouterCouleurCar(COLORATION_1, ROUGE);
+  final protected static AttributeSet SELECTION_1_2_MULTI = ajouterCouleurCar(COLORATION_1_MULTI,
+          ROUGE);
+  final protected static AttributeSet SELECTION_1 = ajouterCouleurCar(COLORATION_1, ROUGE);
+  final protected static AttributeSet SELECTION_1_MULTI = ajouterCouleurCar(COLORATION_1_MULTI,
+          ROUGE);
+  final protected static AttributeSet SELECTION_2 = ajouterCouleurCar(COLORATION_2, BLEU);
+  final protected static AttributeSet SELECTION_2_MULTI = ajouterCouleurCar(COLORATION_2_MULTI,
+          BLEU);
+  final protected static AttributeSet SELECTION_3 = ajouterCouleurCar(COLORATION_3, ROUGE);
+  final protected static AttributeSet SELECTION_3_MULTI = ajouterCouleurCar(COLORATION_3_MULTI,
+          ROUGE);
+  final protected static AttributeSet BORNAGE = ajouterCouleurCar(COLORATION_1, null);
+  final private static HashMap<Integer, String> NOM_ALIGNEMENT = creerTableauNomsAlignement();
+
+  private static SimpleAttributeSet creerStyleStandardDefaut() {
+    String police;
+    if (Arrays.binarySearch(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(),
+            "Times New Roman")>=0) police = "Times New Roman";
+    else police = "Serif";
+    SimpleAttributeSet att = new SimpleAttributeSet();
+    StyleConstants.setFontFamily(att, police);
+    StyleConstants.setForeground(att, Color.BLACK);
+    StyleConstants.setBackground(att, Color.WHITE);
+    StyleConstants.setFontSize(att, 14);
+    StyleConstants.setBold(att, false);
+    StyleConstants.setItalic(att, false);
+    StyleConstants.setUnderline(att, false);
+    StyleConstants.setAlignment(att, StyleConstants.ALIGN_JUSTIFIED);
+    StyleConstants.setFirstLineIndent(att, 20f);
+    StyleConstants.setSpaceAbove(att, 4f);
+    StyleConstants.setSpaceBelow(att, 0f);
+    StyleConstants.setLeftIndent(att, 10f);
+    StyleConstants.setRightIndent(att, 10f);
+    StyleConstants.setLineSpacing(att, 0.1f);
+    return att;
+  }
+
+  private static HashMap<Integer, String> creerTableauNomsAlignement() {
+    HashMap<Integer, String> tab = new HashMap<Integer, String>();
+    tab.put(StyleConstants.ALIGN_CENTER, "Centré");
+    tab.put(StyleConstants.ALIGN_JUSTIFIED, "Justifié");
+    tab.put(StyleConstants.ALIGN_LEFT, "Gauche");
+    tab.put(StyleConstants.ALIGN_RIGHT, "Droite");
+    return tab;
+  }
+
+  public static String nomAlignement(int code) {
+    return NOM_ALIGNEMENT.get(code);
+  }
+
+  public static String[] nomsAlignement() {
+    String[] noms = NOM_ALIGNEMENT.values().toArray(new String[0]);
+    Arrays.sort(noms);
+    return noms;
+  }
+
+  public static int codeAlignement(String nom) {
+    for (int code : NOM_ALIGNEMENT.keySet()) if (nomAlignement(code).equals(nom))
+        return code;
+    return StyleConstants.ALIGN_JUSTIFIED;
+  }
+
+  private static SimpleAttributeSet creerCouleurFond(Color c) {
+    SimpleAttributeSet att = new SimpleAttributeSet();
+    StyleConstants.setBackground(att, c);
+    return att;
+  }
+
+  private static SimpleAttributeSet ajouterCouleurCar(AttributeSet att0, Color c) {
+    SimpleAttributeSet att = new SimpleAttributeSet(att0);
+    StyleConstants.setBold(att, true);
+    if (c!=null) StyleConstants.setForeground(att, c);
+    return att;
+  }
+
+  public static Color getCouleurFond1() {
+    return StyleConstants.getBackground(COLORATION_1);
+  }
+
+  public static Color getCouleurFond2() {
+    return StyleConstants.getBackground(COLORATION_2);
+  }
+
+  public static Color getCouleurFond3() {
+    return StyleConstants.getBackground(COLORATION_3);
+  }
+
+  public enum TypeMarquage {
+    FOND1(5, COLORATION_1, COLORATION_1_MULTI),
+    FOND1_2(5, COLORATION_1, COLORATION_1_MULTI),
+    FOND2(6, COLORATION_2, COLORATION_2_MULTI),
+    FOND3(7, COLORATION_3, COLORATION_3_MULTI),
+    SELECT1(2, SELECTION_1, SELECTION_1_MULTI),
+    SELECT1_2(1, SELECTION_1_1, SELECTION_1_1_MULTI),
+    SELECT1_3(2, SELECTION_1_2, SELECTION_1_2_MULTI),
+    SELECT2(3, SELECTION_2, SELECTION_2_MULTI),
+    SELECT3(4, SELECTION_3, SELECTION_3_MULTI);
+    protected AttributeSet attribut;
+    protected AttributeSet attributMulti;
+    protected int niveau;
+
+    TypeMarquage(int niv, AttributeSet att, AttributeSet attMulti) {
+      attribut = att;
+      attributMulti = attMulti;
+      niveau = niv;
+    }
+  }
+
+  public static class UniteColoree {
+    public Unite unite;
+    public AttributeSet att;
+
+    public UniteColoree(Unite unite, AttributeSet att) {
+      this.att = att;
+      this.unite = unite;
+    }
+  }
+
+  protected static class Coloriage {
+    private int[][] intervalles;
+    private AttributeSet[] attributIntervalles;
+    private PanneauTexte panneauTexte;
+
+    protected Coloriage(PanneauTexte pTexte) {
+      panneauTexte = pTexte;
+      intervalles = new int[0][];
+      attributIntervalles = new AttributeSet[0];
+    }
+
+    private void creerColoriage(UniteColoree[] unitsCol) {
+      ArrayList<int[]> intervlles = new ArrayList<int[]>();
+      ArrayList<AttributeSet> attIntervalle = new ArrayList<AttributeSet>();
+      for (UniteColoree unitCol : unitsCol) {
+        int deb = panneauTexte.indexToPosition(unitCol.unite.getDeb());
+        int fin = panneauTexte.indexToPosition(unitCol.unite.getFin());
+        intervlles.add(new int[]{deb, fin-deb});
+        attIntervalle.add(unitCol.att);
+      }
+      intervalles = intervlles.toArray(new int[0][]);
+      attributIntervalles = attIntervalle.toArray(new AttributeSet[0]);
+    }
+  }
+
+  protected static class Marquage {
+    private int[][] intervalles;
+    private Unite[][] unitesIntervalles;
+    private AttributeSet[] attributIntervalles;
+    private HashMap<Unite, ArrayList<TypeMarquage>> typesMarquage =
+            new HashMap<Unite, ArrayList<TypeMarquage>>();
+    private PanneauTexte panneauTexte;
+
+    protected Marquage(PanneauTexte pTexte) {
+      panneauTexte = pTexte;
+    }
+    // Ordre de masquage décroissant : si une unité est présente dans plusieurs types de marquage, 
+    // seule sa première mention sera prise en compte (grâce au HashMap typesMarquage)
+
+    void creerMarquage(TypeMarquage[] typesMarq, EnumMap<TypeMarquage, Unite[]> unites) {
+      HashMap<Integer, HashSet<Unite>> debs = new HashMap<Integer, HashSet<Unite>>();
+      HashMap<Integer, HashSet<Unite>> fins = new HashMap<Integer, HashSet<Unite>>();
+      HashSet<Integer> bornes = new HashSet<Integer>();
+      HashMap<Unite, Boolean> multis = new HashMap<Unite, Boolean>();
+      typesMarquage.clear();
+      for (TypeMarquage typeM : typesMarq)
+        for (Unite unit : unites.get(typeM)) {
+          if (!typesMarquage.containsKey(unit)) {
+            typesMarquage.put(unit, new ArrayList<TypeMarquage>());
+            typesMarquage.get(unit).add(typeM);
+            multis.put(unit, false);
+          } else {
+            ArrayList<TypeMarquage> types = typesMarquage.get(unit);
+            if (!types.get(types.size()-1).equals(typeM)) types.add(typeM);
+            else if (types.size()==1) multis.put(unit, true);
+          }
+          int deb = panneauTexte.indexToPosition(unit.getDeb());
+          int fin = panneauTexte.indexToPosition(unit.getFin());
+          bornes.add(deb);
+          bornes.add(fin);
+          if (!debs.containsKey(deb)) debs.put(deb, new HashSet<Unite>());
+          debs.get(deb).add(unit);
+          if (!fins.containsKey(fin)) fins.put(fin, new HashSet<Unite>());
+          fins.get(fin).add(unit);
+        }
+      Integer[] brnes = bornes.toArray(new Integer[0]);
+      Arrays.sort(brnes);
+      ArrayList<Unite> units = new ArrayList<Unite>();
+      ArrayList<int[]> intervlles = new ArrayList<int[]>();
+      ArrayList<Unite[]> unitsIntervalle = new ArrayList<Unite[]>();
+      ArrayList<AttributeSet> attIntervalle = new ArrayList<AttributeSet>();
+      int deb = 0;  // début d'un intervalle
+      int lg = 0;   // longueur d'un intervalle
+      for (int borne : brnes) {
+        if (!units.isEmpty()) {
+          lg = borne-deb;
+          intervlles.add(new int[]{deb, lg});
+          unitsIntervalle.add(ordonnerUnites(units));
+          attIntervalle.add(choisirAttribut(units, multis));
+        }
+        if (debs.containsKey(borne)) for (Unite unit : debs.get(borne))
+            units.add(unit);
+        if (fins.containsKey(borne)) for (Unite unit : fins.get(borne))
+            units.remove(unit);
+        if (!units.isEmpty()) deb = borne;
+      }
+      intervalles = intervlles.toArray(new int[0][]);
+      unitesIntervalles = unitsIntervalle.toArray(new Unite[0][]);
+      attributIntervalles = attIntervalle.toArray(new AttributeSet[0]);
+    }
+
+    private Unite[] ordonnerUnites(ArrayList<Unite> units) {
+      Unite[] unites = new Unite[units.size()];
+      unites[0] = units.get(0);
+      for (int i = 1; i<unites.length; i++) {
+        if (units.get(i).getFin()-units.get(i).getDeb()>=unites[0].getFin()-unites[0].getDeb())
+          unites[i] = units.get(i);
+        else {
+          unites[i] = unites[0];
+          unites[0] = units.get(i);
+        }
+      }
+      return unites;
+    }
+
+    private AttributeSet choisirAttribut(ArrayList<Unite> units, HashMap<Unite, Boolean> multis) {
+      AttributeSet att;
+      if (units.size()==1) {
+        att = multis.get(units.get(0)) ? typesMarquage.get(units.get(0)).get(0).attributMulti : typesMarquage.get(units.get(0)).get(0).attribut;
+      } else {
+        att = typesMarquage.get(units.get(0)).get(0).attributMulti;
+        int niv = typesMarquage.get(units.get(0)).get(0).niveau;
+        for (int i = 1; i<units.size(); i++) {
+          if (typesMarquage.get(units.get(i)).get(0).niveau<niv) {
+            att = typesMarquage.get(units.get(i)).get(0).attributMulti;
+            niv = typesMarquage.get(units.get(i)).get(0).niveau;
+          }
+        }
+      }
+      return att;
+    }
+
+    public Unite[] getUnitesVisees(int pos) {   // peut être améliorée par une recherche dichotomique
+      for (int i = 0; i<intervalles.length; i++) {
+        int[] interv = intervalles[i];
+        if (pos<interv[0]) return new Unite[0];
+        if (pos<interv[0]+interv[1]) return unitesIntervalles[i];
+      }
+      return new Unite[0];
+    }
+
+    public Unite getUniteVisee(int pos) {   // peut être améliorée par une recherche dichotomique
+      Unite[] units = getUnitesVisees(pos);
+      if (units.length==0) return null;
+      return units[0];
+    }
+
+    public TypeMarquage getMarquage(Unite unit) {
+      return typesMarquage.get(unit).get(0);
+    }
+
+    public ArrayList<TypeMarquage> getMarquages(Unite unit) {
+      return typesMarquage.get(unit);
+    }
+  }
+  // Champs de la classe PanneauTexte
+  protected SimpleAttributeSet AttributsStandard;
+  final static String CAR_FIN_PARAGRAPHE = "[\u00b6] ";
+  protected Corpus corpus;
+  protected StyledDocument doc;
+  protected Coloriage coloriage = null;
+  protected ArrayList<Integer> posNewLines = new ArrayList<Integer>();
+
+  public PanneauTexte(Corpus corpus) {
+    super();
+    this.corpus = corpus;
+    AttributsStandard = new SimpleAttributeSet(STANDARD_DEFAUT);
+    doc = getStyledDocument();
+    setText("");
+    ToolTipManager.sharedInstance().registerComponent(this);
+  }
+
+  @Override
+  public JToolTip createToolTip() {
+    JToolTip jt = new JToolTip();
+    jt.setBackground(JAUNE_TRES_CLAIR);
+    return jt;
+  }
+
+  public SimpleAttributeSet getAttributsStandard() {
+    return AttributsStandard;
+  }
+
+  public void setAttributsStandard(SimpleAttributeSet att) {
+    AttributsStandard = att;
+  }
+
+//  private int debParag;
+//  public void setTexteVisu() {
+//    final String texte = corpus.getTexte();
+//    posNewLines.clear();
+//    debParag = 0;
+//    final Integer[] finPars = corpus.getFinParagraphes();
+//    final StringBuffer newTexte = new StringBuffer(texte.length()+finPars.length);
+//    final GMessages.GProgression progression =
+//            new GMessages.GProgression(finPars.length, "paragraphes");
+//    Thread traitement = new Thread() {
+//      @Override
+//      public void run() {
+//        for (int i = 0; i<finPars.length; i++) {
+//          //           if(progression.isCanceled()) break;
+//          newTexte.append(texte.substring(debParag, finPars[i])).append("\n");
+//          posNewLines.add(newTexte.length()-1);
+//          debParag = finPars[i];
+//         progression.setNbTraites(i+1);
+//         }
+//        setText(new String(newTexte));
+//        revalidate();
+//        repaint();
+//      }
+//    };
+//    traitement.start();
+//  }
+//  
+  public void setTexteVisu() {
+    final String texte = corpus.getTexte();
+    posNewLines.clear();
+    int debParag = 0;
+    Integer[] finPars = corpus.getFinParagraphes();
+    StringBuffer newTexte = new StringBuffer(texte.length()+finPars.length);
+    for (int i = 0; i<finPars.length; i++) {
+      //           if(progression.isCanceled()) break;
+      newTexte.append(texte.substring(debParag, finPars[i])).append("\n");
+      posNewLines.add(newTexte.length()-1);
+      debParag = finPars[i];
+    }
+    setText(new String(newTexte));
+    revalidate();
+    repaint();
+  }
+
+  private int getYHautAff() {
+    return ((JViewport) getParent()).getViewPosition().y;
+  }
+
+  private void setYHautAff(int y) {
+    ((JViewport) getParent()).setViewPosition(new Point(0, y));
+  }
+
+  public void initAscenseur() {
+    setYHautAff(0);
+    setCaretPosition(0);
+  }
+
+  public void ajusterAscenseur(PanneauTexte panneau) {
+    setYHautAff(panneau.getYHautAff());
+    setCurseur(panneau.getCaretPosition());
+  }
+
+  public void setCurseur(int pos) {
+    int ymax = getYHautAff()+((JViewport) getParent()).getViewSize().height;
+    pos = Math.max(pos, viewToModel(new Point(0, getYHautAff())));
+    pos = Math.min(pos, viewToModel(new Point(0, ymax)));
+    setCaretPosition(pos);
+  }
+
+  protected void placerAscenseur(Unite unite) {
+    int posdeb = indexToPosition(unite.getDeb());
+    placerAscenseur(posdeb, indexToPosition(unite.getFin()));
+    setCaretPosition(posdeb);
+  }
+
+  protected void placerAscenseur(int posdeb, int posfin) {
+    try {
+      Rectangle rectdeb = modelToView(posdeb);
+      Rectangle rectfin = modelToView(posfin);
+      int hligne = rectdeb.height;
+      int yhaut = rectdeb.y;
+      int ybas = rectfin.y+hligne;
+      int y0 = getYHautAff();
+      int h = ((JViewport) getParent()).getExtentSize().height;
+      if (yhaut<y0||ybas>y0+h) {
+        setYHautAff(Math.max(0, modelToView(posdeb).y-h/3));
+      }
+    } catch (BadLocationException ex) {
+      System.out.println("Erreur dans placerAscenseur : "+ex.getLocalizedMessage());
+     // System.exit(1);
+    }
+  }
+
+  public int[] getIndSelection() {
+    int deb = getSelectionStart();
+    int fin = getSelectionEnd();
+    if (deb==fin) return null;
+    return new int[]{positionToIndex(deb), positionToIndex(fin)};
+  }
+
+  protected int indexToPosition(int ind) {
+    int nbnl = 0;
+    for (int finParag : corpus.getFinParagraphes()) {
+      if (ind<finParag) {
+        break;
+      }
+      nbnl++;
+    }
+    return ind+nbnl;
+  }
+
+  protected int positionToIndex(int pos) {
+    int nbnl = 0;
+    for (int posnl : posNewLines) {
+      if (pos<=posnl) {
+        break;
+      }
+      nbnl++;
+    }
+    return pos-nbnl;
+  }
+
+  public void colorierUnites(UniteColoree[] unitsCol) {
+    coloriage.creerColoriage(unitsCol);
+  }
+  // Ordre de masquage décroissant : si une unité est présente dans plusieurs types de marquage, 
+  // seule sa première mention sera prise en compte 
+
+  protected void marquerUnites(Marquage marquage, TypeMarquage[] typesMarq, EnumMap<TypeMarquage, Unite[]> unites) {
+    doc.setCharacterAttributes(0, getText().length(), AttributsStandard, true);
+    doc.setParagraphAttributes(0, getText().length(), AttributsStandard, true);
+    if (coloriage!=null&&typesMarq.length==0)
+      for (int i = 0; i<coloriage.intervalles.length; i++)
+        doc.setCharacterAttributes(
+                coloriage.intervalles[i][0], coloriage.intervalles[i][1], coloriage.attributIntervalles[i], false);
+    marquage.creerMarquage(typesMarq, unites);
+    for (int i = 0; i<marquage.intervalles.length; i++)
+      doc.setCharacterAttributes(
+              marquage.intervalles[i][0], marquage.intervalles[i][1], marquage.attributIntervalles[i], false);
+  }
+
+  protected Unite getUniteVisee(Marquage marquage, Point pt) {
+    return marquage.getUniteVisee(viewToModel(pt));
+  }
+
+  protected Unite[] getUnitesVisees(Marquage marquage, Point pt) {
+    return marquage.getUnitesVisees(viewToModel(pt));
+  }
+
+//  public static int[] calculerNoParagraphe(Unite[] unites, Integer[] finPar) {
+//    // les unites sont triées
+//    // les numéros de paragraphe commencent à 1 
+//    int[] nosPar = new int[unites.length];
+//    int nopar = 0;
+//    for (int i = 0; i<unites.length; i++) {
+//      while (unites[i].getDeb()>finPar[nopar]) nopar++;
+//      nosPar[i] = nopar+1;
+//    }
+//    return nosPar;
+//  }
+//
+  public static String insereCarFinParagraphe(String texte, Integer[] finPar, int offset) {
+    for (int ind : finPar) {
+      ind -= offset;
+      if (ind<=0) continue;
+      if (ind>=texte.length()) break;
+      texte = texte.substring(0, ind)+PanneauTexte.CAR_FIN_PARAGRAPHE+texte.substring(ind);
+      offset -= CAR_FIN_PARAGRAPHE.length();
+    }
+    return texte;
+  }
+
+  public String getTexteUnite(Unite unit) {  // utilisé pour les tooltips et les popups : à revoir
+    int deb = unit.getDeb();
+    int fin = unit.getFin();
+    return insereCarFinParagraphe(corpus.getTexte().substring(deb, fin), corpus.getFinParagraphes(), deb);
+  }
+
+  protected void setTexteCorpus() {
+    String newTexte = "";
+    ArrayList<Integer> newFinParag = new ArrayList<Integer>();
+    String texte = getText();
+    if (posNewLines.isEmpty()||posNewLines.get(posNewLines.size()-1)!=texte.length()-1) {
+      posNewLines.add(texte.length());
+    }
+    int debParag = 0;
+    for (int posnl : posNewLines) {
+      newTexte += texte.substring(debParag, posnl);
+      newFinParag.add(newTexte.length());
+      debParag = posnl+1;
+    }
+    corpus.modifTexte(newTexte, newFinParag);
+  }
+
+  public void rechercherTexte(String chaine) {
+    getCaret().setSelectionVisible(true);
+    String texte = getText();
+    int pos = texte.indexOf(chaine, getCaretPosition());
+    if (pos<0) pos = texte.indexOf(chaine);
+    if (pos>=0) {
+      placerAscenseur(pos, pos+chaine.length());
+      setCaretPosition(pos);
+      moveCaretPosition(pos+chaine.length());
+    } else moveCaretPosition(getCaretPosition());
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauTexte.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/VisuStyleTexte.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/VisuStyleTexte.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/VisuStyleTexte.java	(revision 3653)
@@ -0,0 +1,213 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.texte;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.text.*;
+import visuAnalec.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu;
+import visuAnalec.util.GVisu.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class VisuStyleTexte extends JFrame {
+  private static VisuStyleTexte instance = null;
+  private PanneauEditeur pEditeur;
+  private SimpleAttributeSet att;
+  JComboBox saisieTaille;
+  JComboBox saisiePolice;
+  JCheckBox saisieGras;
+  JCheckBox saisieItalique;
+  JCheckBox saisieSouligne;
+  CouleurComboBox saisieCouleur;
+  CouleurComboBox saisieFond;
+  JComboBox saisieInterligne;
+  JComboBox saisieEspaceAvant;
+  JComboBox saisieEspaceApres;
+  JComboBox saisieAlignement;
+  JComboBox saisieIndentGauche;
+  JComboBox saisieIndentDroite;
+  JComboBox saisieIndentPrem;
+  public static void newVisuStyleTexte(PanneauEditeur pEditeur, SimpleAttributeSet att) {
+    if (instance != null) instance.dispose();
+    instance = new VisuStyleTexte(pEditeur, att);
+
+  }
+  private VisuStyleTexte(PanneauEditeur pEditeur, SimpleAttributeSet att) {
+    super("Gestion du style du texte");
+    Container fen = pEditeur.getTopLevelAncestor();
+    Point pos = new Point(fen.getX() + 200, fen.getY() + 50);
+    setLocation(pos);
+    this.pEditeur = pEditeur;
+    this.att = att;
+    JPanel pStyleCaracteres = new JPanel(new GridLayout(0, 2, 2, 4));
+    pStyleCaracteres.setBorder(new TitledBorder("Caractères"));
+    pStyleCaracteres.add(new JLabel("Police", JLabel.TRAILING));
+    String[] polices = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
+    saisiePolice = new JComboBox(polices);
+    saisiePolice.setPrototypeDisplayValue("Times New Roman");
+    saisiePolice.setEditable(false);
+    saisiePolice.setSelectedItem(StyleConstants.getFontFamily(att));
+    saisiePolice.setMaximumSize(new Dimension(40, 100));
+    pStyleCaracteres.add(saisiePolice);
+    pStyleCaracteres.add(new JLabel("Taille (pts)", JLabel.TRAILING));
+    saisieTaille = new JComboBox(new String[]{"4", "8", "10", "12", "14", "16", "20"});
+    saisieTaille.setEditable(true);
+    saisieTaille.setSelectedItem(Integer.toString(StyleConstants.getFontSize(att)));
+    pStyleCaracteres.add(saisieTaille);
+    pStyleCaracteres.add(new JLabel("Couleur", JLabel.TRAILING));
+    saisieCouleur = new CouleurComboBox(GVisu.getCouleursEtNoirEtBlanc());
+    saisieCouleur.setEditable(true);
+    saisieCouleur.setSelectedItem(StyleConstants.getForeground(att));
+    pStyleCaracteres.add(saisieCouleur);
+    pStyleCaracteres.add(new JLabel("Surbrillance", JLabel.TRAILING));
+    saisieFond = new CouleurComboBox(GVisu.getCouleursEtNoirEtBlanc());
+    saisieFond.setEditable(true);
+    saisieFond.setSelectedItem(StyleConstants.getBackground(att));
+    pStyleCaracteres.add(saisieFond);
+    pStyleCaracteres.add(new JLabel("Caractères gras", JLabel.TRAILING));
+    saisieGras = new JCheckBox("", StyleConstants.isBold(att));
+    pStyleCaracteres.add(saisieGras);
+    pStyleCaracteres.add(new JLabel("italiques", JLabel.TRAILING));
+    saisieItalique = new JCheckBox("", StyleConstants.isItalic(att));
+   pStyleCaracteres.add(saisieItalique);
+    pStyleCaracteres.add(new JLabel("soulignés", JLabel.TRAILING));
+    saisieSouligne = new JCheckBox("", StyleConstants.isUnderline(att));
+    saisieSouligne.setHorizontalTextPosition(SwingConstants.LEADING);
+    pStyleCaracteres.add(saisieSouligne);
+    JPanel pStyleParagraphes = new JPanel(new GridLayout(0,2,2,4));
+    pStyleParagraphes.setBorder(new TitledBorder("Paragraphes"));
+    pStyleParagraphes.add(new JLabel("Alignement", JLabel.TRAILING));
+    saisieAlignement = new JComboBox(PanneauTexte.nomsAlignement());
+    saisieAlignement.setEditable(false);
+    saisieAlignement.setSelectedItem(PanneauTexte.nomAlignement(StyleConstants.getAlignment(att)));
+    pStyleParagraphes.add(saisieAlignement);
+    pStyleParagraphes.add(new JLabel("Interligne (pts)", JLabel.TRAILING));
+    saisieInterligne = new JComboBox(new String[]{"-0.2", "0", "0.2", "0.5", "1.0", "1.5", "2"});
+    saisieInterligne.setEditable(true);
+    saisieInterligne.setSelectedItem(Float.toString(StyleConstants.getLineSpacing(att)));
+    pStyleParagraphes.add(saisieInterligne);
+    pStyleParagraphes.add(new JLabel("Espacement avant (pts)", JLabel.TRAILING));
+    saisieEspaceAvant = new JComboBox(new String[]{"0.0", "2.0", "5.0", "10.0", "15.0", "20.0"});
+    saisieEspaceAvant.setEditable(true);
+    saisieEspaceAvant.setSelectedItem(Float.toString(StyleConstants.getSpaceAbove(att)));
+    pStyleParagraphes.add(saisieEspaceAvant);
+    pStyleParagraphes.add(new JLabel("après (pts)", JLabel.TRAILING));
+    saisieEspaceApres = new JComboBox(new String[]{"0.0", "2.0", "5.0", "10.0", "15.0", "20.0"});
+    saisieEspaceApres.setEditable(true);
+    saisieEspaceApres.setSelectedItem(Float.toString(StyleConstants.getSpaceBelow(att)));
+    pStyleParagraphes.add(saisieEspaceApres);
+    pStyleParagraphes.add(new JLabel("Retrait gauche (pts)", JLabel.TRAILING));
+    saisieIndentGauche = new JComboBox(new String[]{"0.0", "2.0", "5.0", "10.0", "15.0", "20.0"});
+    saisieIndentGauche.setEditable(true);
+    saisieIndentGauche.setSelectedItem(Float.toString(StyleConstants.getLeftIndent(att)));
+    pStyleParagraphes.add(saisieIndentGauche);
+    pStyleParagraphes.add(new JLabel("droit (pts)", JLabel.TRAILING));
+    saisieIndentDroite = new JComboBox(new String[]{"0.0", "2.0", "5.0", "10.0", "15.0", "20.0"});
+    saisieIndentDroite.setEditable(true);
+    saisieIndentDroite.setSelectedItem(Float.toString(StyleConstants.getRightIndent(att)));
+    pStyleParagraphes.add(saisieIndentDroite);
+    pStyleParagraphes.add(new JLabel("1ère ligne (pts)", JLabel.TRAILING));
+    saisieIndentPrem = new JComboBox(new String[]{"0.0", "2.0", "5.0", "10.0", "15.0", "20.0"});
+    saisieIndentPrem.setEditable(true);
+    saisieIndentPrem.setSelectedItem(Float.toString(StyleConstants.getFirstLineIndent(att)));
+    pStyleParagraphes.add(saisieIndentPrem);
+   Box pSaisieItems = Box.createHorizontalBox();
+   pSaisieItems.add(pStyleCaracteres);
+    pSaisieItems.add(Box.createHorizontalGlue());
+    pSaisieItems.add(pStyleParagraphes);
+   JPanel  pCommandesValidation = new JPanel(new FlowLayout(FlowLayout.CENTER));
+    JButton valideModifs = new JButton(
+            new GAction("Valider") {
+              public void executer() {
+                validerModifs();
+              }
+              ;
+            });
+    JButton annuleModifs = new JButton(
+            new GAction("Annuler") {
+              public void executer() {
+                dispose();
+              }
+              ;
+            });
+    pCommandesValidation.add(valideModifs);
+    pCommandesValidation.add(annuleModifs);
+    // cadre global de la fenêtre
+    JPanel cadre = new JPanel(new BorderLayout());
+    cadre.add(pStyleCaracteres, BorderLayout.WEST);
+   cadre.add(pStyleParagraphes, BorderLayout.EAST);
+    cadre.add(pCommandesValidation, BorderLayout.SOUTH);
+    setContentPane(cadre);
+    pack();
+    setVisible(true);
+    addWindowListener(new WindowAdapter() {
+      @Override
+      public void windowClosing(WindowEvent evt) {
+      }
+    });
+  }
+  private void validerModifs() {
+    int entierSaisi;
+    float decimalSaisi;
+    StyleConstants.setFontFamily(att, (String) saisiePolice.getSelectedItem());
+    StyleConstants.setForeground(att, (Color) saisieCouleur.getSelectedItem());
+    StyleConstants.setBackground(att, (Color) saisieFond.getSelectedItem());
+    try {
+      entierSaisi = Integer.parseInt((String) saisieTaille.getSelectedItem());
+    } catch (NumberFormatException numberFormatException) {
+      entierSaisi = StyleConstants.getFontSize(att);
+    }
+    StyleConstants.setFontSize(att, entierSaisi);
+    StyleConstants.setBold(att, (boolean) saisieGras.isSelected());
+    StyleConstants.setItalic(att, (boolean) saisieItalique.isSelected());
+    StyleConstants.setUnderline(att, (boolean) saisieSouligne.isSelected());
+    StyleConstants.setAlignment(att, PanneauTexte.codeAlignement((String) saisieAlignement.getSelectedItem()));
+    try {
+      decimalSaisi = Float.parseFloat((String) saisieEspaceAvant.getSelectedItem());
+    } catch (NumberFormatException numberFormatException) {
+      decimalSaisi = StyleConstants.getSpaceAbove(att);
+    }
+    StyleConstants.setSpaceAbove(att, decimalSaisi);
+    try {
+      decimalSaisi = Float.parseFloat((String) saisieEspaceApres.getSelectedItem());
+    } catch (NumberFormatException numberFormatException) {
+      decimalSaisi = StyleConstants.getSpaceBelow(att);
+    }
+    StyleConstants.setSpaceBelow(att, decimalSaisi);
+    try {
+      decimalSaisi = Float.parseFloat((String) saisieIndentGauche.getSelectedItem());
+    } catch (NumberFormatException numberFormatException) {
+      decimalSaisi = StyleConstants.getLeftIndent(att);
+    }
+    StyleConstants.setLeftIndent(att, decimalSaisi);
+    try {
+      decimalSaisi = Float.parseFloat((String) saisieIndentDroite.getSelectedItem());
+    } catch (NumberFormatException numberFormatException) {
+      decimalSaisi = StyleConstants.getRightIndent(att);
+    }
+    StyleConstants.setRightIndent(att, decimalSaisi);
+    try {
+      decimalSaisi = Float.parseFloat((String) saisieIndentPrem.getSelectedItem());
+    } catch (NumberFormatException numberFormatException) {
+      decimalSaisi = StyleConstants.getFirstLineIndent(att);
+    }
+    StyleConstants.setFirstLineIndent(att, decimalSaisi);
+    try {
+      decimalSaisi = Float.parseFloat((String) saisieInterligne.getSelectedItem());
+    } catch (NumberFormatException numberFormatException) {
+      decimalSaisi = (Float) StyleConstants.getLineSpacing(att);
+    }
+    StyleConstants.setLineSpacing(att, decimalSaisi);
+    pEditeur.changerStyleTexte(att);
+    dispose();
+  }
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/VisuStyleTexte.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauOccurrences.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauOccurrences.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauOccurrences.java	(revision 3653)
@@ -0,0 +1,172 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.texte;
+
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+import visuAnalec.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class PanneauOccurrences extends JTable implements ListSelectionListener {
+  ModeleTableauOcc modele;
+  ModeleTableur modeleTableur;
+  Vue vue;
+  PanneauEditeur pEditeur;
+  Element[] listElt;
+  final static int EMPAN = 80;  // paramètre à saisir (un jour)
+  public PanneauOccurrences(Vue vue, PanneauEditeur pEditeur) {
+    super();
+    modele = new ModeleTableauOcc();
+    setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+    setModel(modele);
+    modeleTableur = new ModeleTableur();
+    getSelectionModel().addListSelectionListener(this);
+    this.vue = vue;
+    this.pEditeur = pEditeur;
+  }
+  public TableModel getModeleTableur() {
+    return modeleTableur;
+  }
+  public void initVide() {
+    listElt = new Element[0];
+    getTableHeader().setVisible(false);
+    modele.clear();
+    modeleTableur.clear();
+  }
+  public void init(Class<? extends Element> classe, String type, Element[] listElt) {
+    this.listElt = listElt;
+    if (listElt.length==0) {
+      initVide();
+      return;
+    }
+    getTableHeader().setVisible(true);
+    String[] ids = vue.getIdListeElements(classe, type, listElt);
+    String[][] concordances = vue.getCorpus().getConcordances(listElt, EMPAN);
+    String[] champs = vue.getNomsChamps(classe, type);
+    String[][] valeurs = vue.getValeursChampsListeElements(champs, listElt);
+    modele.setModele(ids, concordances);
+    modeleTableur.setModele(ids, concordances, champs, valeurs);
+    getColumnModel().getColumn(0).setPreferredWidth(150);
+    getColumnModel().getColumn(1).setMinWidth(1200);
+  }
+  @Override
+  public void valueChanged(ListSelectionEvent evt) {
+    try {
+      if (evt.getValueIsAdjusting()) return;
+      if (evt.getSource().equals(getSelectionModel())) {
+        int row = getSelectedRow();
+        if (row>=0) pEditeur.editerElement(listElt[row]);
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.toString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+
+  private static class ModeleTableauOcc extends AbstractTableModel {
+    final static String STYLE_HTML = "<html>";
+    final static String STYLE_DEB_SELECT =
+            "<span style=\"font-weight:bold; background-color:#FFFF80\">";
+    final static String STYLE_FIN_SELECT = "</span>";
+    String[] ids;
+    String[] extraits;
+    public ModeleTableauOcc() {
+      super();
+      clear();
+    }
+    public int getRowCount() {
+      return ids.length;
+    }
+    public int getColumnCount() {
+      return 2;
+    }
+    @Override
+    public String getColumnName(int columnIndex) {
+      return columnIndex==0 ? "Identifiants" : "Occurrences";
+    }
+    public Object getValueAt(int rowIndex, int columnIndex) {
+      return columnIndex==0 ? ids[rowIndex] : extraits[rowIndex];
+
+    }
+    private void clear() {
+      ids = new String[0];
+    }
+    private void setModele(String[] ids, String[][] concordances) {
+      this.ids = ids;
+      extraits = new String[ids.length];
+      for (int i = 0; i<ids.length; i++)
+        extraits[i] = formerExtrait(concordances[i]);
+      fireTableDataChanged();
+    }
+    private String formerExtrait(String[] concordance) {
+      return STYLE_HTML+concordance[0]+STYLE_DEB_SELECT+concordance[1]
+              +STYLE_FIN_SELECT+concordance[2];
+    }
+  }
+
+  private static class ModeleTableur extends AbstractTableModel {
+    String[] ids;
+    String[][] concordances;
+    String[] champs;
+    String[][] valeurs;
+    public ModeleTableur() {
+      super();
+      clear();
+    }
+    public int getRowCount() {
+      return ids.length;
+    }
+    public int getColumnCount() {
+      return 4+champs.length;
+    }
+    @Override
+    public String getColumnName(int columnIndex) {
+      switch (columnIndex) {
+        case 0:
+          return "Identifiants";
+        case 1:
+          return "Contexte gauche";
+        case 2:
+          return "Elément";
+        case 3:
+          return "Contexte droit";
+        default:
+          return champs[columnIndex-4];
+      }
+    }
+    public Object getValueAt(int rowIndex, int columnIndex) {
+      switch (columnIndex) {
+        case 0:
+          return ids[rowIndex];
+        case 1:
+        case 2:
+        case 3:
+          return concordances[rowIndex][columnIndex-1];
+        default:
+          return valeurs[rowIndex][columnIndex-4];
+      }
+
+    }
+    private void clear() {
+      champs = ids = new String[0];
+    }
+    private void setModele(String[] ids, String[][] concordances,
+            String[] champs, String[][] valeurs) {
+      this.ids = ids;
+      this.concordances = concordances;
+      this.champs = champs;
+      this.valeurs = valeurs;
+      fireTableDataChanged();
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauOccurrences.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauCommandesModifTexte.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauCommandesModifTexte.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauCommandesModifTexte.java	(revision 3653)
@@ -0,0 +1,58 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package visuAnalec.texte;
+
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.Message.*;
+import visuAnalec.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class PanneauCommandesModifTexte extends Box  {
+  Vue vue;
+  PanneauModifTexte panneauTexte;
+  PanneauEditeur panneauEditeur;
+ public PanneauCommandesModifTexte( PanneauEditeur pEditeur, Vue vue, PanneauModifTexte pTexte) {
+    super(BoxLayout.X_AXIS);
+    this.panneauEditeur = pEditeur;
+    this.vue = vue;
+    this.panneauTexte = pTexte;
+        add(Box.createHorizontalGlue());
+    add( new JButton(new GAction("Valider") {
+      public void executer() {
+        validerModifTexte();
+        panneauEditeur.finModifTexte();
+      }
+    }));
+    add(Box.createHorizontalGlue());
+    add( new JButton(new GAction("Annuler") {
+      public void executer() {
+        panneauEditeur.finModifTexte();
+    }
+    }));
+    add(Box.createHorizontalGlue());
+  }
+ void validerModifTexte() {
+   int nbSupprimes = panneauTexte.preparerValiderModifTexte();
+  if (nbSupprimes > 0) {
+      int rep = JOptionPane.showOptionDialog(getTopLevelAncestor(),
+              "Les modifications du texte vont entraîner la suppression " +
+              (nbSupprimes == 1 ? "d'une unité" : "de " + nbSupprimes + " unités"), "Suppression d'unités",
+              JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+              null, new Object[]{"Continuer", "Annuler"}, "Continuer");
+      if (rep == 1) return;
+    }
+    panneauTexte.validerModifTexte();
+  }
+ }

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauCommandesModifTexte.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauAffChainesTexte.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauAffChainesTexte.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauAffChainesTexte.java	(revision 3653)
@@ -0,0 +1,77 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.texte;
+
+import java.awt.event.*;
+import java.util.*;
+import visuAnalec.chaines.*;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class PanneauAffChainesTexte extends PanneauTexte {
+  private ListenerSourisTexte sourisListener;
+  private VisuChaines visuChaines;
+  private Marquage marquage;
+  public PanneauAffChainesTexte(Corpus corpus, VisuChaines visuChaines) {
+    super(corpus);
+    setEditable(false);
+    this.visuChaines = visuChaines;
+    setSourisListener(visuChaines);
+    marquage = new Marquage(this);
+  }
+  protected void setSourisListener(VisuChaines vChaines) {
+    sourisListener = new ListenerSourisTexte(this, vChaines);
+    addMouseListener(sourisListener);
+  }
+  public void pasDeMarquage() {
+    marquerUnites(marquage, new TypeMarquage[0], null);
+  }
+  public void montrerUnite(Unite unit, TypeMarquage typeSelectUnite) {
+    TypeMarquage[] typesMarq = new TypeMarquage[]{typeSelectUnite};
+    EnumMap<TypeMarquage, Unite[]> unites = new EnumMap<TypeMarquage, Unite[]>(TypeMarquage.class);
+    unites.put(typeSelectUnite, new Unite[]{unit});
+    marquerUnites(marquage, typesMarq, unites);
+    placerAscenseur(unit);
+  }
+  public void montrerUnite(Unite unit, TypeMarquage typeSelectUnite, Unite[] unitsChaine,
+          TypeMarquage typeSelectChaine) {
+    TypeMarquage[] typesMarq = new TypeMarquage[]{typeSelectUnite, typeSelectChaine};
+    EnumMap<TypeMarquage, Unite[]> unites = new EnumMap<TypeMarquage, Unite[]>(TypeMarquage.class);
+    unites.put(typeSelectUnite, new Unite[]{unit});
+    unites.put(typeSelectChaine, unitsChaine);
+    marquerUnites(marquage, typesMarq, unites);
+    placerAscenseur(unit);
+  }
+  public void colorerUnites(Unite[] units, TypeMarquage typeColorChaines) {
+    TypeMarquage[] typesMarq = new TypeMarquage[]{typeColorChaines};
+    EnumMap<TypeMarquage, Unite[]> unites = new EnumMap<TypeMarquage, Unite[]>(TypeMarquage.class);
+    unites.put(typeColorChaines, units);
+    marquerUnites(marquage, typesMarq, unites);
+  }
+
+  protected static class ListenerSourisTexte extends MouseAdapter {
+    private PanneauAffChainesTexte panneauTexte;
+    private VisuChaines visuChaines;
+    public ListenerSourisTexte(PanneauAffChainesTexte pTexte, VisuChaines vChaines) {
+      this.panneauTexte = pTexte;
+      this.visuChaines = vChaines;
+    }
+    @Override
+    public void mouseClicked(MouseEvent e) {
+ try {
+   Unite uniteVisee = panneauTexte.getUniteVisee(panneauTexte.marquage, e.getPoint());
+      if (uniteVisee == null)  visuChaines.traiterAffTexteClicVide();
+      else  if (e.getClickCount() == 2) visuChaines.traiterAffTexteDoubleClic(uniteVisee);
+     } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+   }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/texte/PanneauAffChainesTexte.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/chaines/ModeleChaines.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/chaines/ModeleChaines.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/chaines/ModeleChaines.java	(revision 3653)
@@ -0,0 +1,258 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.chaines;
+
+import java.awt.*;
+import java.util.*;
+import java.util.ArrayList;
+import visuAnalec.elements.*;
+import visuAnalec.texte.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class ModeleChaines {
+  static class Chainon {
+    Unite unite;
+    String texte;
+    Schema chaine = null;
+    int nbEltsChaine = 0;
+    String idChaine = "";
+    int noChaine = 0;
+    Chainon(Unite unite, String texte) {
+      this.unite = unite;
+      this.texte = texte;
+    }
+  }
+  private Vue vue;
+  private GChaines panneauGraphique;
+  private Unite[] listeUnites;
+  private HashMap<Unite, Schema> chainesUnitesNonFiltrees =
+          new HashMap<Unite, Schema>();
+  private int[] seuilsValsNbElements = new int[0];
+  private HashMap<Unite, Chainon> chainonsUnites = new HashMap<Unite, Chainon>();
+  private HashMap<Schema, ArrayList<Unite>> unitesChaines =
+          new HashMap<Schema, ArrayList<Unite>>();
+  private HashMap<String, HashSet<String>> valsMasqueesChamp =
+          new HashMap<String, HashSet<String>>();
+  private HashSet<String> valNulleMasqueeChamp = new HashSet<String>();
+  private boolean[] valsMasqueesNbElements = new boolean[0];
+  public ModeleChaines(Vue vue, GChaines panneauGraphique) {
+    this.vue = vue;
+    this.panneauGraphique = panneauGraphique;
+  }
+  Schema getChaine(Unite unit) {
+    return chainonsUnites.get(unit).chaine;
+  }
+  Unite[] getUnites() {
+    return listeUnites;
+  }
+  Unite[] getUnitesChaine(Schema chaine) {
+    ArrayList<Unite> units = unitesChaines.get(chaine);
+    return units.toArray(new Unite[0]);
+  }
+  boolean isMasqueeValChamp(String champ, String val) {
+    return valsMasqueesChamp.containsKey(champ)
+            &&valsMasqueesChamp.get(champ).contains(val);
+  }
+  boolean isMasqueeValNulleChamp(String champ) {
+    return valNulleMasqueeChamp.contains(champ);
+  }
+  boolean isMasqueeValNbElements(int i) {
+    return valsMasqueesNbElements[i];
+  }
+  void demasquerToutesValsChamp(String champ) {
+    valsMasqueesChamp.get(champ).clear();
+    valNulleMasqueeChamp.remove(champ);
+  }
+  void demasquerToutesValsNbElts(String champ) {
+    for (int i = 0; i<valsMasqueesNbElements.length; i++) {
+      valsMasqueesNbElements[i] = false;  
+    }
+  }
+ void masquerAutresValsChamp(String typeunite, String champ, String val) {
+    for(String v: vue.getValeursChamp(Unite.class, typeunite, champ)) 
+      valsMasqueesChamp.get(champ).add(v);
+     valsMasqueesChamp.get(champ).remove(val);
+     valNulleMasqueeChamp.add(champ);
+  }
+ void masquerValChamp(boolean yes, String champ, String val) {
+    if (yes) valsMasqueesChamp.get(champ).add(val);
+    else valsMasqueesChamp.get(champ).remove(val);
+  }
+ void masquerValsNonNullesChamp(String typeunite, String champ) {
+    for(String v: vue.getValeursChamp(Unite.class, typeunite, champ)) 
+      valsMasqueesChamp.get(champ).add(v);
+     valNulleMasqueeChamp.remove(champ);
+  }
+  void masquerValNulleChamp(boolean yes, String champ) {
+    if (yes) valNulleMasqueeChamp.add(champ);
+    else valNulleMasqueeChamp.remove(champ);
+  }
+  void masquerAutresValsNbElts(String champ, int i0) {
+    for (int i = 0; i<valsMasqueesNbElements.length; i++) {
+      valsMasqueesNbElements[i] = i!=i0;  
+    }
+  }
+  void masquerValNbElements(boolean yes, int i) {
+    valsMasqueesNbElements[i] = yes;
+  }
+  void init(String typeChaines, String typeUnites, int[] seuils)
+          throws UnsupportedOperationException {
+    seuilsValsNbElements = seuils;
+    String[] champs = vue.getNomsChamps(Unite.class, typeUnites);
+    valsMasqueesChamp.clear();
+    for (String champ : champs)
+      valsMasqueesChamp.put(champ, new HashSet<String>());
+    valNulleMasqueeChamp.clear();
+    valsMasqueesNbElements = new boolean[seuils.length+3];
+    calculerChainesUnitesNonFiltrees(typeChaines, typeUnites);
+    calculerDonnees(typeChaines, typeUnites);
+  }
+  private void calculerChainesUnitesNonFiltrees(String typeChaines,
+          String typeUnites) throws UnsupportedOperationException {
+    chainesUnitesNonFiltrees.clear();
+    for (Schema chaine : vue.getSchemasAVoir(typeChaines))
+      for (Element elt : chaine.getContenu()) {
+        if (elt.getClass()==Unite.class&&elt.getType().equals(typeUnites)) {
+          if (chainesUnitesNonFiltrees.containsKey(elt)) {
+            throw new UnsupportedOperationException("L'unité "+vue.getIdElement(elt)
+                    +" appartient à deux chaînes : "+vue.getIdElement(chaine)+" et "
+                    +vue.getIdElement(chainesUnitesNonFiltrees.get((Unite) elt)));
+          } else
+            chainesUnitesNonFiltrees.put((Unite) elt, chaine);
+        }
+      }
+  }
+  void modifMasqueVals(String typeChaines, String typeUnites) {
+    calculerDonnees(typeChaines, typeUnites);
+  }
+  private void filtrerListeUnites(String typeUnites, String typeChaines) {
+    Unite[] unites = vue.getUnitesAVoir(typeUnites);
+    Schema[] chaines = vue.getSchemasAVoir(typeChaines);
+    unitesChaines.clear();
+    for (Schema chaine : chaines) unitesChaines.put(chaine, new ArrayList<Unite>());
+    ArrayList<Integer> indFiltrees = new ArrayList<Integer>();
+    String[] champs = vue.getNomsChamps(Unite.class, typeUnites);
+    boolean agarder;
+    for (int i = 0; i<unites.length; i++) {
+      agarder = true;
+      for (String champ : champs) {
+        String val = vue.getValeurChamp(unites[i], champ);
+        if (val.isEmpty()) {
+          if (valNulleMasqueeChamp.contains(champ)) {
+            agarder = false;
+            break;
+          }
+        } else {
+          if (valsMasqueesChamp.get(champ).contains(val)) {
+            agarder = false;
+            break;
+          }
+        }
+      }
+      if (agarder) {
+        indFiltrees.add(i);
+        if (chainesUnitesNonFiltrees.containsKey(unites[i])) {
+          Schema chaine = chainesUnitesNonFiltrees.get(unites[i]);
+          unitesChaines.get(chaine).add(unites[i]);
+        }
+      }
+    }
+    ArrayList<Integer> indIndFiltrees = new ArrayList<Integer>();
+    for(int k=0; k<indFiltrees.size(); k++) {
+      Unite unit = unites[indFiltrees.get(k)];
+      if(chainesUnitesNonFiltrees.containsKey(unit)) {
+        if(!isMasqueeValNbElements(calculerValNbElements(
+                unitesChaines.get(chainesUnitesNonFiltrees.get(unit)).size())))
+          indIndFiltrees.add(k);
+      } else {
+        if(!isMasqueeValNbElements(0)) indIndFiltrees.add(k);
+      }      
+    }
+    listeUnites = new Unite[indIndFiltrees.size()];
+    for (int k = 0; k<listeUnites.length; k++) {
+      listeUnites[k] = unites[indFiltrees.get(indIndFiltrees.get(k))];
+    }
+        for (Schema chaine : chaines) {
+          int nb = unitesChaines.get(chaine).size();
+          if(nb==0||isMasqueeValNbElements(calculerValNbElements(nb)))
+            unitesChaines.remove(chaine);
+        }
+  }
+  private void calculerDonnees(String typeChaines, String typeUnites) {
+     filtrerListeUnites(typeUnites, typeChaines);
+    Chainon[] chainons = new Chainon[listeUnites.length];
+    for (int i = 0; i<listeUnites.length; i++) {
+      Unite unit = listeUnites[i];
+      chainons[i] = new Chainon(unit, vue.getTexteUnite(unit));
+      if(chainesUnitesNonFiltrees.containsKey(unit)) {
+        Schema chaine = chainesUnitesNonFiltrees.get(unit);
+        chainons[i].chaine = chaine;
+        chainons[i].nbEltsChaine = unitesChaines.get(chaine).size();
+        chainons[i].idChaine = vue.getIdElement(chaine);
+      } 
+      chainonsUnites.put(listeUnites[i], chainons[i]);
+    }
+    HashMap<Schema, Integer> noChaine = new HashMap<Schema, Integer>();
+    int no = 0;
+    for (Schema chaine : vue.getSchemasAVoir(typeChaines)) {
+      if(unitesChaines.containsKey(chaine)) {
+        int nbElts = unitesChaines.get(chaine).size(); 
+       noChaine.put(chaine, nbElts>1 ? ++no : 0);
+    }
+    }
+    for (Unite unit : listeUnites) {
+      Chainon chainon = chainonsUnites.get(unit);
+      if (chainon.chaine!=null) chainon.noChaine = noChaine.get(chainon.chaine);
+    }
+    int[] noPar = vue.getCorpus().calculerNoParagraphe(listeUnites);
+    panneauGraphique.setDonnees(chainons, noPar);
+  }
+  void initVide() {
+    listeUnites = new Unite[0];
+    chainesUnitesNonFiltrees.clear();
+    seuilsValsNbElements = new int[0];
+    chainonsUnites.clear();
+    unitesChaines.clear();
+    panneauGraphique.setDonnees(new Chainon[0], new int[0]);
+    panneauGraphique.setCouleurs(new Color[0]);
+    valNulleMasqueeChamp.clear();
+    valsMasqueesChamp.clear();
+    valsMasqueesNbElements = new boolean[0];
+  }
+  void setChampAffiche(String champ, HashMap<String, Color> couleursValeursChamp) {
+    panneauGraphique.setCouleurs(colorerChamp(champ, couleursValeursChamp));
+  }
+  void setChampAfficheNbElts(Color[] couleurs) {
+    panneauGraphique.setCouleurs(colorerNbElts(couleurs));
+  }
+  private Color[] colorerNbElts(Color[] couleurs) {
+    Color[] couls = new Color[listeUnites.length];
+    for (int i = 0; i<listeUnites.length; i++) {
+      Chainon ch = chainonsUnites.get(listeUnites[i]);
+      if (ch.chaine==null) couls[i] = couleurs[0];
+      else {
+        int nbElts = ch.nbEltsChaine;
+        couls[i] = couleurs[calculerValNbElements(nbElts)];
+      }
+    }
+    return couls;
+  }
+  private Color[] colorerChamp(String champ, HashMap<String, Color> couleursValeursChamp) {
+    Color[] couls = new Color[listeUnites.length];
+    for (int i = 0; i<listeUnites.length; i++) {
+      Chainon ch = chainonsUnites.get(listeUnites[i]);
+      couls[i] = couleursValeursChamp.get(vue.getValeurChamp(ch.unite, champ));
+    }
+    return couls;
+  }
+  private int calculerValNbElements(int nbElts) {
+    return nbElts==1 ? 1 : nbElts<=seuilsValsNbElements[0] ? 2 : 
+            nbElts<=seuilsValsNbElements[1] ? 3 : 4;
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/chaines/ModeleChaines.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/chaines/GChaines.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/chaines/GChaines.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/chaines/GChaines.java	(revision 3653)
@@ -0,0 +1,252 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.chaines;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.chaines.ModeleChaines.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class GChaines extends JPanel {
+  final static Font FONTE_ID = Font.decode("Arial bold 10");
+  final static int RAYON_DISQUES = 6;
+  final static int MARGE_DISQUES = 2;
+  final static int LARGEUR_INTER_CHAINONS = 10;
+  final static int MARGE_DEBUT_LIGNE = 15;
+  final static int HAUTEUR_LIGNES = 80;
+  final static int HAUTEUR_SEGMENT = 40;
+  final static int HAUTEUR_CHAINONS = 60;
+  final static String SYMBOLE_SEGMENT = "§";
+//    final static int hauteurinfLien = 25;
+//    final static int deltahauteurLien = 5;
+//    final static int deltasupArcs = 95;
+//    final static int hauteurinfArcs = 5;
+//  final static int HAUTEUR_PANNEAU = 120;
+  final static String PAS_DE_NUMERO = "~";
+
+  static class GChainon extends JButton {
+    VisuChaines visu;
+    Chainon chainon;
+    public GChainon(Chainon ch, VisuChaines vis) {
+      super();
+      this.visu = vis;
+      this.chainon = ch;
+      Icon d = new DisqueCouleurIcone(Color.WHITE, RAYON_DISQUES, MARGE_DISQUES);
+      setAction(new GAction(null, d) {
+        public void executer() {
+          visu.afficherOccurrences(chainon.unite, chainon.chaine);
+        }
+      });
+      setSize(2*(RAYON_DISQUES+MARGE_DISQUES), 2*(RAYON_DISQUES+MARGE_DISQUES));
+      setBorderPainted(false);
+      String t2 = "<html><div style=\"font-size:11pt\"><span style=\"font-style:italic\">"+chainon.texte
+              +"</span><p>"+chainon.idChaine+"<p>"+chainon.nbEltsChaine+" occurences </div>";
+      setToolTipText(t2);
+      setBackground(Color.WHITE);
+      setFocusPainted(false);
+    }
+    @Override
+    public JToolTip createToolTip() {
+      JToolTip jt = new JToolTip();
+      jt.setBackground(Color.WHITE);
+      return jt;
+    }
+    void changerCouleur(Color couleur) {
+      setIcon(new DisqueCouleurIcone(couleur, RAYON_DISQUES, MARGE_DISQUES));
+    }
+  }
+
+  static class GNoChainon extends JLabel {
+    public GNoChainon(int noChaine) {
+      super(noChaine==0 ? PAS_DE_NUMERO : Integer.toString(noChaine));
+      setFont(FONTE_ID);
+      setSize(getPreferredSize());
+    }
+    void localiser(Point chainonPosition, Dimension chainonTaille) {
+      int x = chainonPosition.x+chainonTaille.width/2-getSize().width/2;
+      int y = chainonPosition.y-getSize().height;
+      setLocation(x, y);
+    }
+  }
+
+  private enum TypeSegment {
+    COMPLET("", ""),
+    DEBUT("", "-"),
+    MILIEU("-", "-"),
+    FIN("-", "");
+    String marqueAvant, marqueApres;
+    private TypeSegment(String avant, String apres) {
+      marqueAvant = avant;
+      marqueApres = apres;
+    }
+  }
+
+  static class GSegment extends JLabel {
+    int xmin, xmax;
+    int ybas, yhaut;
+    int no;
+    TypeSegment type;
+    GSegment(int xmin, int xmax, int ybas, int yhaut, int no, TypeSegment type) {
+      super(type.marqueAvant+SYMBOLE_SEGMENT+Integer.toString(no)+type.marqueApres);
+      setFont(FONTE_ID);
+      this.xmin = xmin;
+      this.xmax = xmax;
+      this.ybas = ybas;
+      this.yhaut = yhaut;
+      this.type = type;
+      setSize(getPreferredSize());
+    }
+    void localiser() {
+      setLocation((xmin+xmax)/2-getSize().width/2, yhaut-getSize().height);
+    }
+    void dessinerTraits(Graphics graphics) {
+      Graphics2D g = (Graphics2D) graphics;
+      g.setColor(Color.BLACK);
+      Point p0 = new Point(xmin, ybas);
+      Point p1 = new Point(xmin, yhaut);
+      Point p2 = new Point(xmax, yhaut);
+      Point p3 = new Point(xmax, ybas);
+      switch (type) {
+        case COMPLET:
+          g.draw(new Line2D.Float(p0, p1));
+          g.draw(new Line2D.Float(p1, p2));
+          g.draw(new Line2D.Float(p2, p3));
+          break;
+        case DEBUT:
+          g.draw(new Line2D.Float(p0, p1));
+          g.draw(new Line2D.Float(p1, p2));
+          break;
+        case FIN:
+          g.draw(new Line2D.Float(p1, p2));
+          g.draw(new Line2D.Float(p2, p3));
+          break;
+        case MILIEU:
+          g.draw(new Line2D.Float(p1, p2));
+          break;
+      }
+    }
+  }
+  /*
+   * Champs de la classeGChaines
+   */
+  VisuChaines visu;
+  Chainon[] chainons = new Chainon[0];
+  int[] noSegments = new int[0];
+  Color[] couleurs = new Color[0];
+  GChainon[] gChainons;
+  ArrayList<GSegment> gSegments = new ArrayList<GSegment>();
+  private int nbChainonsParLigne;
+  GChaines(VisuChaines vc) {
+    super((LayoutManager) null);
+    setBackground(Color.WHITE);
+    this.visu = vc;
+    addMouseListener(new MouseAdapter() {
+      @Override
+      public void mouseClicked(MouseEvent e) {
+        visu.traiterAffTexteClicVide();
+      }
+    });
+  }
+  void setNbChainonsParLigne(int nb) {
+    nbChainonsParLigne = nb;
+    afficher();
+    colorer();
+  }
+  void setDonnees(Chainon[] chainons, int[] noSegments) {
+    this.chainons = chainons;
+    this.noSegments = noSegments;
+    afficher();
+  }
+  private void afficher() {
+    effacerTout();
+    if (chainons.length==0) return;
+    gChainons = new GChainon[chainons.length];
+    int xCourant = MARGE_DEBUT_LIGNE+LARGEUR_INTER_CHAINONS;
+    int yCourant = 0;
+    GNoChainon gNoChainon;
+    int xminSeg = MARGE_DEBUT_LIGNE+LARGEUR_INTER_CHAINONS/2+2;
+    GSegment gseg;
+    int xmaxSeg = 0;
+    int xmaxligne = 0;
+    for (int i = 0; i<chainons.length; i++) {
+      gChainons[i] = new GChainon(chainons[i], visu);
+      add(gChainons[i]);
+      gChainons[i].setLocation(xCourant, yCourant+HAUTEUR_CHAINONS);
+      add(gNoChainon = new GNoChainon(chainons[i].noChaine));
+      gNoChainon.localiser(gChainons[i].getLocation(), gChainons[i].getSize());
+      xCourant += gChainons[i].getWidth()+LARGEUR_INTER_CHAINONS;
+      xmaxligne = Math.max(xCourant, xmaxligne);
+      xmaxSeg = xCourant-LARGEUR_INTER_CHAINONS/2-2;
+      if (i+1==chainons.length||noSegments[i+1]>noSegments[i]) {
+        // fin de paragraphe, donc on trace un segment terminal  
+        if (xminSeg>0) {  // le paragraphe a commencé sur cette ligne
+          add(gseg = new GSegment(xminSeg, xmaxSeg, yCourant+HAUTEUR_CHAINONS,
+                  yCourant+HAUTEUR_SEGMENT, noSegments[i], TypeSegment.COMPLET));
+        } else {  // le paragraphe a commencé avant cette ligne
+          xminSeg = MARGE_DEBUT_LIGNE+LARGEUR_INTER_CHAINONS/2+2;
+          add(gseg = new GSegment(xminSeg, xmaxSeg, yCourant+HAUTEUR_CHAINONS,
+                  yCourant+HAUTEUR_SEGMENT, noSegments[i], TypeSegment.FIN));
+        }
+        gseg.localiser();
+        gSegments.add(gseg);
+        xminSeg = xmaxSeg+4;
+      }
+      if (i+1!=chainons.length&&(i+1)%nbChainonsParLigne==0) {  // on va changer de ligne
+        if (xminSeg>xmaxSeg) {  // ça tombe bien : on change aussi de segment
+          xminSeg = MARGE_DEBUT_LIGNE+LARGEUR_INTER_CHAINONS/2+2;
+        } else { // ca tombe pas bien : il faut tracer un segment non terminal
+          if (xminSeg>0) { // le paragraphe a commencé sur cette ligne
+            add(gseg = new GSegment(xminSeg, xmaxSeg, yCourant+HAUTEUR_CHAINONS,
+                    yCourant+HAUTEUR_SEGMENT, noSegments[i], TypeSegment.DEBUT));
+          } else {  // le paragraphe a commencé avant cette ligne
+            xminSeg = MARGE_DEBUT_LIGNE+LARGEUR_INTER_CHAINONS/2+2;
+            add(gseg = new GSegment(xminSeg, xmaxSeg, yCourant+HAUTEUR_CHAINONS,
+                    yCourant+HAUTEUR_SEGMENT, noSegments[i], TypeSegment.MILIEU));
+          }
+          gseg.localiser();
+          gSegments.add(gseg);
+          xminSeg = -1;
+        }
+        xCourant = MARGE_DEBUT_LIGNE+LARGEUR_INTER_CHAINONS;
+        yCourant += HAUTEUR_LIGNES;
+      }
+    }
+    setPreferredSize(new Dimension(xmaxligne+30, yCourant+HAUTEUR_LIGNES+30));
+  }
+  void setCouleurs(Color[] couleurs) {
+    this.couleurs = couleurs;
+    colorer();
+  }
+  private void colorer() {
+    for (int i = 0; i<gChainons.length; i++) {
+      gChainons[i].changerCouleur(couleurs[i]);
+    }
+    revalidate();
+    repaint();
+  }
+  private void effacerTout() {
+    removeAll();
+    gChainons = new GChainon[0];
+    gSegments.clear();
+    repaint();
+  }
+  private void effacer(Graphics graphics) {
+    graphics.setColor(Color.WHITE);
+    graphics.fillRect(0, 0, getWidth(), getHeight());
+  }
+  @Override
+  protected void paintComponent(Graphics graphics) {
+    effacer(graphics);
+    for (GSegment gs : gSegments) gs.dessinerTraits(graphics);
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/chaines/GChaines.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/chaines/VisuChaines.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/chaines/VisuChaines.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/chaines/VisuChaines.java	(revision 3653)
@@ -0,0 +1,352 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.chaines;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.*;
+import visuAnalec.Message.*;
+import visuAnalec.elements.*;
+import visuAnalec.texte.*;
+import visuAnalec.texte.PanneauTexte.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.vue.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class VisuChaines extends JFrame implements VueListener, ActionListener {
+  private static int[] seuilsValsNbElts = {3, 10};
+  private static Color[] couleursNbElts = {Color.WHITE, GVisu.getCouleurSansValeur(),
+    GVisu.getCouleur(0), GVisu.getCouleur(3), GVisu.getCouleur(1)};
+  private static String[] labelsNbElements = {
+    "pas de chaîne associée",
+    "chaîne d'un seul chaînon",
+    "chaîne de 2-"+Integer.toString(seuilsValsNbElts[0])+" chaînons",
+    "chaîne de "+Integer.toString(seuilsValsNbElts[0]+1)+"-"
+    +Integer.toString(seuilsValsNbElts[1])+"  chaînons",
+    "chaîne de plus de "+Integer.toString(seuilsValsNbElts[1])+" chaînons"
+  };
+  private Vue vue;
+  private ModeleChaines donneesChaines;
+  private String typeChaines;
+  private String typeUnites;
+  private String[] valsAffichees;
+  private TypeComboBox saisieTypeChaines;
+  private TypeComboBox saisieTypeUnites;
+  private Val0ComboBox saisieChampAffiche;
+  private JComboBox saisieTailleLigne;
+  private JList legendeChampAffiche;
+  private JPopupMenu popupChamp = new JPopupMenu();
+  private GChaines panneauGraphique;
+  private PanneauAffChainesTexte panneauTexte;
+  private PanneauEditeur panneauEditeur;
+  public VisuChaines(Container fenetre, Vue vue, PanneauEditeur pEditeur) {
+    super("Représentation des chaînes");
+    Point pos = new Point(fenetre.getX()+20, fenetre.getY()+20);
+    Dimension dim = new Dimension(fenetre.getWidth(), fenetre.getHeight());
+    setLocation(pos);
+    setSize(dim);
+    this.vue = vue;
+    vue.addEventListener(this);
+    this.panneauEditeur = pEditeur;
+    saisieTypeChaines = new TypeComboBox(Schema.class);
+    saisieTypeChaines.setModele(vue.getTypesSchemasAVoir());
+    saisieTypeChaines.addActionListener(this);
+    saisieTypeUnites = new TypeComboBox(Unite.class);
+    saisieTypeUnites.setModele(vue.getTypesUnitesAVoir());
+    saisieTypeUnites.addActionListener(this);
+    saisieTailleLigne = new JComboBox(
+            new String[]{"<tous>", "10", "20", "30", "40", "50"});
+    saisieTailleLigne.setEditable(true);
+   // saisieTailleLigne.setMaximumSize(getPreferredSize());
+    saisieTailleLigne.addActionListener(this);
+    saisieTypeChaines.setModele(vue.getTypesSchemasAVoir());
+    saisieChampAffiche = new Val0ComboBox("Nombre de chaînons");
+    saisieChampAffiche.addActionListener(this);
+    // Panneau de présentation du graphique
+    JPanel pGraphique = new JPanel(new BorderLayout());
+    Box commandes = Box.createHorizontalBox();
+    commandes.add(Box.createHorizontalGlue());
+    commandes.add(new JLabel("Chaînes : "));
+    commandes.add(saisieTypeChaines);
+    commandes.add(Box.createHorizontalGlue());
+    commandes.add(new JLabel("Unites : "));
+    commandes.add(saisieTypeUnites);
+    commandes.add(Box.createHorizontalGlue());
+    commandes.add(new JLabel("Nb de chainons par ligne : "));
+    commandes.add(saisieTailleLigne);
+    commandes.add(Box.createHorizontalGlue());
+    commandes.add(new JLabel("Champ à afficher : "));
+    commandes.add(saisieChampAffiche);
+    pGraphique.add(commandes, BorderLayout.SOUTH);
+    panneauGraphique = new GChaines(this);
+    JScrollPane scrollGraphique = new JScrollPane(panneauGraphique);
+    pGraphique.add(scrollGraphique, BorderLayout.CENTER);
+    panneauTexte = new PanneauAffChainesTexte(vue.getCorpus(), this);
+    panneauTexte.setTexteVisu();
+    JScrollPane scrollTexte = new JScrollPane(panneauTexte);
+    legendeChampAffiche = new JList();
+    legendeChampAffiche.setCellRenderer(new LegendeCellRenderer());
+    legendeChampAffiche.addMouseListener(new MouseAdapter() {
+      public void mousePressed(MouseEvent e) {
+        check(e);
+      }
+      public void mouseReleased(MouseEvent e) {
+        check(e);
+      }
+      public void check(MouseEvent e) {
+        if (e.isPopupTrigger()) {//if the event shows the menu
+          popupChampInit(legendeChampAffiche.locationToIndex(e.getPoint()));
+          popupChamp.show(legendeChampAffiche, e.getX(), e.getY());
+        }
+      }
+    });
+    JScrollPane scrollLegende = new JScrollPane(legendeChampAffiche);
+    JSplitPane split1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollTexte, scrollLegende);
+    JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, pGraphique, split1);
+    getContentPane().add(split);
+    setVisible(true);
+    split.setDividerLocation(1./3);
+    split1.setDividerLocation(3./4);
+    // Fermeture de la fenêtre
+    setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+    addWindowListener(new WindowAdapter() {
+      @Override
+      public void windowClosing(WindowEvent evt) {
+        fermerFenetre();
+      }
+    });
+    // Initialisation
+    saisieTailleLigne.setSelectedIndex(0);
+    saisieTailleLigne.setMaximumSize(getPreferredSize());
+    donneesChaines = new ModeleChaines(vue, panneauGraphique);
+    if (saisieTypeChaines.nbItems()==1) {
+      saisieTypeChaines.setSelection(0);
+      if (saisieTypeUnites.nbItems()==1) saisieTypeUnites.setSelection(0);
+      else saisieTypeUnites.effSelection();
+    } else {
+      saisieTypeChaines.effSelection();
+      saisieTypeUnites.effSelection();
+    }
+  }
+  void afficherOccurrences(Unite unite, Schema chaine) {
+    if (chaine!=null)
+      panneauTexte.montrerUnite(unite, TypeMarquage.SELECT1_2,
+              donneesChaines.getUnitesChaine(chaine), TypeMarquage.SELECT1);
+    else
+      panneauTexte.montrerUnite(unite, TypeMarquage.SELECT2);
+
+  }
+  private void fermerFenetre() {
+    vue.removeEventListener(this);
+    dispose();
+  }
+  public void traiterEvent(Message evt) { // très grossier : à améliorer
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        fermerFenetre();
+        return;
+      case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+        throw new UnsupportedOperationException("Fenêtre chaines présente lors d'un message NEW_CORPUS ???");
+      case MODIF_TEXTE:
+        fermerFenetre();
+        return;
+      case MODIF_VUE:
+        fermerFenetre();
+        return;
+      case MODIF_STRUCTURE:
+        fermerFenetre();
+        return;
+      case MODIF_ELEMENT:
+//        ElementEvent evtE = (ElementEvent) evt;
+//        if (evtE.getModif() != TypeModifElement.BORNES_UNITE) fermerFenetre();
+        fermerFenetre();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+  }
+  public void traiterAffTexteDoubleClic(Unite unit) {
+    Schema chaine;
+    if ((chaine = donneesChaines.getChaine(unit))!=null)
+      panneauEditeur.editerUniteChaine(unit, chaine);
+    else
+      panneauEditeur.editerUniteTypeChaine(unit, typeChaines);
+  }
+  public void traiterAffTexteClicVide() {
+    panneauTexte.colorerUnites(donneesChaines.getUnites(), TypeMarquage.FOND1);
+  }
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource().equals(saisieTypeChaines)
+              ||evt.getSource().equals(saisieTypeUnites)) {
+        if (saisieTypeChaines.pasdeSelection()||saisieTypeUnites.pasdeSelection()) {
+          initVide();
+          return;
+        }
+        try {
+          init();
+        } catch (UnsupportedOperationException ex) {
+          GMessages.impossibiliteAction("Erreur de type : "+ex.getMessage());
+          initVide();
+          return;
+        }
+        return;
+      }
+      if (evt.getSource().equals(saisieChampAffiche)) {
+        if (saisieChampAffiche.pasdeSelection()) initCouleursNbElts();
+        else initCouleursChamp(saisieChampAffiche.getSelection());
+        return;
+      }
+      if (evt.getSource().equals(saisieTailleLigne)) {
+        int taille = saisieTailleLigne.getSelectedIndex()==0 ? Integer.MAX_VALUE :
+                Integer.parseInt((String)saisieTailleLigne.getSelectedItem());
+        panneauGraphique.setNbChainonsParLigne(taille);
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  private void initVide() {
+    typeChaines = null;
+    typeUnites = null;
+    donneesChaines.initVide();
+    saisieChampAffiche.setModeleVide();
+    panneauTexte.pasDeMarquage();
+    panneauTexte.setCurseur(0);
+    legendeChampAffiche.setListData(new LegendeLabel[0]);
+  }
+  private void init() throws UnsupportedOperationException {
+    typeChaines = saisieTypeChaines.getTypeSelection();
+    typeUnites = saisieTypeUnites.getTypeSelection();
+    donneesChaines.init(typeChaines, typeUnites, seuilsValsNbElts);
+    initCouleursNbElts();
+    saisieChampAffiche.removeActionListener(this);
+    saisieChampAffiche.setModele(vue.getNomsChamps(Unite.class, typeUnites));
+    saisieChampAffiche.addActionListener(this);
+    panneauTexte.colorerUnites(donneesChaines.getUnites(), TypeMarquage.FOND1);
+  }
+  private void initCouleursNbElts() {
+    donneesChaines.setChampAfficheNbElts(couleursNbElts);
+    legendeChampAffiche.setListData(creerLegendesNbElements());
+  }
+  private LegendeLabel[] creerLegendesNbElements() {
+    LegendeLabel[] legendes = new LegendeLabel[couleursNbElts.length];
+    for (int i = 0; i<legendes.length; i++)
+      legendes[i] = new LegendeLabel(labelsNbElements[i],
+              donneesChaines.isMasqueeValNbElements(i) ? null : couleursNbElts[i]);
+    return legendes;
+  }
+  private void initCouleursChamp(String champ) {
+    valsAffichees = vue.getValeursChamp(Unite.class, typeUnites, champ);
+    HashMap<String, Color> couleursValeursChamp = new HashMap<String, Color>();
+    for (int i = 0, nocolor = 0; i<valsAffichees.length; i++)
+      if (!donneesChaines.isMasqueeValChamp(champ, valsAffichees[i]))
+        couleursValeursChamp.put(valsAffichees[i], GVisu.getCouleur(nocolor++));
+    if (!donneesChaines.isMasqueeValNulleChamp(champ))
+      couleursValeursChamp.put("", GVisu.getCouleurSansValeur());
+    donneesChaines.setChampAffiche(champ, couleursValeursChamp);
+    legendeChampAffiche.setListData(creerLegendesChamp(valsAffichees,
+            couleursValeursChamp));
+  }
+  private LegendeLabel[] creerLegendesChamp(String[] valsAffichees,
+          HashMap<String, Color> couleursValeursChamp) {
+    LegendeLabel[] legendes = new LegendeLabel[valsAffichees.length+1];
+    for (int i = 0; i<valsAffichees.length; i++)
+      legendes[i] = new LegendeLabel(valsAffichees[i],
+              couleursValeursChamp.get(valsAffichees[i]));
+    legendes[valsAffichees.length] = new LegendeLabel("<aucune valeur>",
+            couleursValeursChamp.get(""));
+    return legendes;
+  }
+  private void popupChampInit(final int index) {
+    final boolean masquee;
+    popupChamp.removeAll();
+    if (saisieChampAffiche.pasdeSelection()) {
+      masquee = donneesChaines.isMasqueeValNbElements(index);
+      popupChamp.add(new GAction(masquee ? "Montrer cette valeur" : 
+              "Masquer cette valeur") {
+        public void executer() {
+          modifierStatutValNbElements(masquee, index, false);
+        }
+      });
+      popupChamp.add(new GAction(masquee ? "Montrer toutes les valeurs" : 
+              "Ne montrer que cette valeur") {
+        public void executer() {
+          modifierStatutValNbElements(masquee, index, true);
+        }
+      });
+    } else if (index==valsAffichees.length) {
+      masquee = donneesChaines.isMasqueeValNulleChamp(saisieChampAffiche.getSelection());
+      popupChamp.add(new GAction(masquee ? "Montrer cette valeur" : 
+              "Masquer cette valeur") {
+        public void executer() {
+          modifierStatutValNulleChamp(masquee, false);
+        }
+      });
+     popupChamp.add(new GAction(masquee ? "Montrer toutes les valeurs" : 
+              "Ne montrer que cette valeur") {
+        public void executer() {
+          modifierStatutValNulleChamp(masquee, true);
+        }
+      });
+    } else {
+      masquee = donneesChaines.isMasqueeValChamp(saisieChampAffiche.getSelection(),
+              valsAffichees[index]);
+      popupChamp.add(new GAction(masquee ? "Montrer cette valeur" : 
+              "Masquer cette valeur") {
+        public void executer() {
+          modifierStatutValChamp(masquee, index, false);
+        }
+      });
+      popupChamp.add(new GAction(masquee ? "Montrer toutes les valeurs" : 
+              "Ne montrer que cette valeur") {
+        public void executer() {
+          modifierStatutValChamp(masquee, index, true);
+        }
+      });
+    }
+  }
+  private void modifierStatutValChamp(boolean masquee, int index, boolean tous) {
+    if(!tous) donneesChaines.masquerValChamp(!masquee, 
+            saisieChampAffiche.getSelection(), valsAffichees[index]);
+    else if(masquee) donneesChaines.demasquerToutesValsChamp( 
+            saisieChampAffiche.getSelection());
+    else donneesChaines.masquerAutresValsChamp(typeUnites, 
+            saisieChampAffiche.getSelection(), valsAffichees[index]);
+    donneesChaines.modifMasqueVals(typeChaines, typeUnites);
+    initCouleursChamp(saisieChampAffiche.getSelection());
+    panneauTexte.colorerUnites(donneesChaines.getUnites(), TypeMarquage.FOND1);
+  }
+  private void modifierStatutValNulleChamp(boolean masquee, boolean tous) {
+    if(!tous) donneesChaines.masquerValNulleChamp(!masquee, saisieChampAffiche.getSelection());
+   else if(masquee) donneesChaines.demasquerToutesValsChamp( 
+            saisieChampAffiche.getSelection());
+    else donneesChaines.masquerValsNonNullesChamp(typeUnites, 
+            saisieChampAffiche.getSelection());
+    donneesChaines.modifMasqueVals(typeChaines, typeUnites);
+    initCouleursChamp(saisieChampAffiche.getSelection());
+    panneauTexte.colorerUnites(donneesChaines.getUnites(), TypeMarquage.FOND1);
+  }
+  private void modifierStatutValNbElements(boolean masquee, int index, boolean tous) {
+    if(!tous) donneesChaines.masquerValNbElements(!masquee, index);
+   else if(masquee) donneesChaines.demasquerToutesValsNbElts( 
+            saisieChampAffiche.getSelection());
+    else donneesChaines.masquerAutresValsNbElts( 
+            saisieChampAffiche.getSelection(), index);
+    donneesChaines.modifMasqueVals(typeChaines, typeUnites);
+    initCouleursNbElts();
+    panneauTexte.colorerUnites(donneesChaines.getUnites(), TypeMarquage.FOND1);
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/chaines/VisuChaines.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/VisuMain.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/VisuMain.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/VisuMain.java	(revision 3653)
@@ -0,0 +1,506 @@
+package visuAnalec;
+
+/**
+ *
+ * @author bernard
+ */
+import javax.swing.*;
+import java.awt.event.*;
+import java.awt.*;
+import java.io.*;
+import javax.swing.table.TableModel;
+import visuAnalec.Message.*;
+import visuAnalec.chaines.*;
+import visuAnalec.donnees.*;
+import visuAnalec.fichiers.*;
+import visuAnalec.statistiques.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.vue.*;
+import visuAnalec.vue.Vue.*;
+
+@SuppressWarnings("serial")
+public class VisuMain extends JFrame implements VueListener {
+  private Corpus corpus;
+  private Vue vue;
+  private PanneauEditeur panneauEditeur;
+  private String nomCorpus = "";
+  private String nomVue = "";
+  private static String[] args;
+  VisuMain() {
+    super();
+    corpus = new Corpus();
+    vue = new Vue(corpus);
+    panneauEditeur = new PanneauEditeur(vue);
+    vue.addEventListener(this);
+    // Cadre global de la fenêtre
+    setContentPane(panneauEditeur);
+    // Menus
+    JMenuBar menuBar = new JMenuBar();
+    setJMenuBar(menuBar);
+
+    // Menu corpus
+    JMenu corpusMenu = new JMenu("Documents");
+    menuBar.add(corpusMenu);
+    corpusMenu.add(new GAction("Ouvrir...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersJava.ouvrirCorpusVue(corpus, vue, "");
+        //       System.out.println(corpus.getStructure());
+      }
+    });
+    JMenuItem item;
+    corpusMenu.add(item = new JMenuItem(new GAction("Enregistrer") {
+      public void executer() {
+        if (corpus.isVide()) return;
+        if (!nomCorpus.isEmpty()) {
+          File fichier = Fichiers.getFichierCourant(Fichiers.TypeFichier.DOC_ANALEC);
+          if (FichiersJava.enregistrerCorpus(corpus, fichier)) setTitre();
+        } else if (FichiersJava.enregistrerCorpusSous(corpus)) {
+          nomCorpus = Fichiers.getNomFichierCourant(Fichiers.TypeFichier.DOC_ANALEC);
+          setTitre();
+        }
+      }
+    }));
+    corpusMenu.add(new GAction("Enregistrer sous...") {
+      public void executer() {
+        if (FichiersJava.enregistrerCorpusSous(corpus)) {
+          nomCorpus = Fichiers.getNomFichierCourant(Fichiers.TypeFichier.DOC_ANALEC);
+          setTitre();
+        }
+      }
+    });
+    corpusMenu.add(new GAction("Fermer") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+      }
+    });
+    corpusMenu.insertSeparator(corpusMenu.getMenuComponentCount());
+    corpusMenu.add(new GAction("Fusionner des annotations") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        FichiersJava.fusionnerAnnot(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Concaténer deux documents") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        FichiersJava.concatenerDocuments(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Concaténer un corpus") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersJava.concatenerCorpus(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Extraire un type d'un corpus") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        String type = JOptionPane.showInputDialog("Nom du type d'unité à extraire");
+        if (type==null) return;
+        corpus.fermer();
+        FichiersJava.extraireTypeCorpus(type, corpus);
+      }
+    });
+    corpusMenu.insertSeparator(corpusMenu.getMenuComponentCount());
+    corpusMenu.add(new GAction("Importer du texte brut...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        int rep = 0;
+        if (!corpus.getStructure().isVide()) {
+          rep = JOptionPane.showOptionDialog(null, "Utiliser la structure actuelle pour le nouveau document ?",
+                  "Structure déjà présente", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+                  null, new Object[]{"Oui", "Non", "Annuler"}, "Oui");
+          if (rep==2) return;
+        }
+        if (rep==0) corpus.fermerConserverStructure();
+        else corpus.fermer();
+        FichiersTexte.importerTexte(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Importer des données Excel...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersTableur.importerExcel(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Importer des données Syntex...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersSyntex.importerSyntex(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Importer des données Glozz...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersGlozz.importerGlozz(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Exporter des données Glozz...") {
+      public void executer() {
+        FichiersGlozz.exporterGlozz(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Convertir un corpus Glozz...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersGlozz.convertirCorpusGlozz(corpus);
+      }
+    });
+   corpusMenu.add(new GAction("Exporter un corpus TEI...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersTEI.exporterCorpusTEI(corpus);
+      }
+    });
+   corpusMenu.add(new GAction("Convertir un corpus TEI...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersTEI.convertirCorpusTEI(corpus);
+     }
+    });
+   corpusMenu.add(new GAction("Importer un document CoNLL...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersCoNLL.importerCoNLL(corpus);
+     }
+    });
+    corpusMenu.insertSeparator(corpusMenu.getMenuComponentCount());
+    corpusMenu.add(new GAction("Quitter") {
+      public void executer() {
+        fermerFenetre();
+      }
+    });
+
+    // Menu structure
+    JMenu structureMenu = new JMenu("Structure");
+    menuBar.add(structureMenu);
+    structureMenu.add(new GAction("Gestion de la structure...") {
+      public void executer() {
+        VisuStructure visuStructure = VisuStructure.newVisuStructure(getContentPane(), corpus);
+        visuStructure.setExtendedState(NORMAL);
+        visuStructure.setVisible(true);
+        visuStructure.agencer();
+      }
+    });
+    structureMenu.add(new GAction("Ouvrir...") {
+      public void executer() {
+        if (!fusionStructure()) return;
+        FichiersJava.ouvrirStructure(corpus);
+      }
+    });
+    structureMenu.add(item = new JMenuItem(new GAction("Enregistrer...") {
+      public void executer() {
+        FichiersJava.enregistrerStructure(corpus);
+        setTitre();
+      }
+    }));
+    structureMenu.add(new GAction("Importer un modèle Glozz...") {
+      public void executer() {
+        if (!fusionStructure()) return;
+        FichiersGlozz.importerModeleGlozz(corpus);
+        //       System.out.println(corpus.getStructure());
+      }
+    });
+    structureMenu.add(new GAction("Exporter un modèle Glozz...") {
+      public void executer() {
+        FichiersGlozz.exporterModeleGlozz(corpus.getStructure());
+      }
+    });
+
+    // Menu vue
+    JMenu vueMenu = new JMenu("Vue");
+    menuBar.add(vueMenu);
+    vueMenu.add(new GAction("Gestion de la vue...") {
+      public void executer() {
+        VisuVue.newVisuVue(getContentPane(), vue);
+      }
+    });
+    vueMenu.add(new GAction("Ouvrir (.ecv)...") {
+      public void executer() {
+        FichiersJava.ouvrirVue(vue);
+      }
+    });
+    vueMenu.add(new GAction("Enregistrer (.ecv)...") {
+      public void executer() {
+        if (FichiersJava.enregistrerVue(vue)) {
+          nomVue = Fichiers.getNomFichierCourant(Fichiers.TypeFichier.VUE);
+          setTitre();
+        }
+      }
+    });
+    vueMenu.add(new GAction("Rétablir la vue par défaut") {
+      public void executer() {
+        nomVue = "";
+        vue.retablirVueParDefaut();
+      }
+    });
+
+    // Menu texte
+    JMenu texteMenu = new JMenu("Texte");
+    menuBar.add(texteMenu);
+    texteMenu.add(new GAction("Modifier le texte") {
+      public void executer() {
+        panneauEditeur.initModifierTexte();
+      }
+    });
+    texteMenu.insertSeparator(texteMenu.getMenuComponentCount());
+    texteMenu.add(item = new JMenuItem(new GAction("Rechercher...") {
+      public void executer() {
+        panneauEditeur.initRechercherTexte();
+      }
+    }));
+    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, ActionEvent.CTRL_MASK));
+    texteMenu.add(item = new JMenuItem(new GAction("Suivant") {
+      public void executer() {
+        panneauEditeur.rechercherSuivantTexte();
+      }
+    }));
+    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, ActionEvent.CTRL_MASK));
+    texteMenu.insertSeparator(texteMenu.getMenuComponentCount());
+    texteMenu.add(new GAction("Style du document...") {
+      public void executer() {
+        panneauEditeur.saisirStyleTexte(vue);
+      }
+    });
+    texteMenu.add(new GAction("Exporter format RTF...") {
+      public void executer() {
+        FichiersTexte.exporterTexteRTF(panneauEditeur);
+      }
+    });
+    texteMenu.add(new GAction("Exporter format HTML...") {
+      public void executer() {
+        FichiersTexte.exporterTexteHTML(panneauEditeur);
+      }
+    });
+
+
+    // Menu unités
+    JMenu unitesMenu = new JMenu("Unités");
+    menuBar.add(unitesMenu);
+    unitesMenu.add(new GAction("Gestion des unités") {
+      public void executer() {
+        panneauEditeur.initGestionUnites();
+      }
+    });
+    unitesMenu.add(new GAction("Export des unités") {
+      public void executer() {
+        String type;
+        String[] types = vue.getTypesUnitesAVoir();
+        if(types==null||types.length==0) return;
+        if(types.length==1) type = types[0];
+        else type = (String) JOptionPane.showInputDialog(VisuMain.this, 
+       "Type des unités à exporter", "Choix du type d'unités",
+       JOptionPane.QUESTION_MESSAGE, null, types, "");
+        if(type==null) return;
+        type = type.trim();
+        if(type.isEmpty()) return;       
+        TableModel donnees = vue.tableauUnites(type);
+        if(donnees!=null)  FichiersTableur.exporterTable(donnees);
+      }
+    });
+    unitesMenu.insertSeparator(unitesMenu.getMenuComponentCount());
+    unitesMenu.add(new GAction("Création d'unités typographiques") {
+      public void executer() {
+        GMessages.pasImplemente();
+      }
+    });
+    unitesMenu.add(new GAction("Création d'unités de constituance") {
+      public void executer() {
+        GMessages.pasImplemente();
+      }
+    });
+
+    // Menu relations
+    JMenu relationsMenu = new JMenu("Relations");
+    menuBar.add(relationsMenu);
+    relationsMenu.add(new GAction("Gestion des relations") {
+      public void executer() {
+        panneauEditeur.initGestionRelations();
+      }
+    });
+    relationsMenu.add(new GAction("Visualisation d'arborescences") {
+      public void executer() {
+        GMessages.pasImplemente();
+      }
+    });
+    relationsMenu.add(new GAction("Saisie d'arborescences") {
+      public void executer() {
+        GMessages.pasImplemente();
+      }
+    });
+    relationsMenu.add(new GAction("Création d'arborescences") {
+      public void executer() {
+        GMessages.pasImplemente();
+      }
+    });
+
+    // Menu schémas
+    JMenu schemasMenu = new JMenu("Schémas");
+    menuBar.add(schemasMenu);
+    schemasMenu.add(new GAction("Gestion des schémas") {
+      public void executer() {
+        panneauEditeur.initGestionSchemas();
+      }
+    });
+    schemasMenu.add(new GAction("Visualisation de chaînes") {
+      public void executer() {
+        new VisuChaines(getContentPane(), vue, panneauEditeur);
+      }
+    });
+
+    // Menu règles
+    JMenu reglesMenu = new JMenu("Règles");
+    menuBar.add(reglesMenu);
+    // Menu Stats
+    JMenu statsMenu = new JMenu("Statistiques");
+    menuBar.add(statsMenu);
+    statsMenu.add(new GAction("Fréquences...") {
+      public void executer() {
+        new VisuStatsFrequences(getContentPane(), vue, panneauEditeur);
+      }
+    });
+    statsMenu.add(new GAction("Corrélations...") {
+      public void executer() {
+        new VisuStatsCorrelations(getContentPane(), vue, panneauEditeur);
+      }
+    });
+    statsMenu.add(new GAction("Représentations géométriques...") {
+      @SuppressWarnings("ResultOfObjectAllocationIgnored")
+      public void executer() {
+        new VisuStatsGeometrie(getContentPane(), vue, panneauEditeur);
+      }
+    });
+    // Fermeture de la fenêtre
+    setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+    addWindowListener(new WindowAdapter() {
+      @Override
+      public void windowClosing(WindowEvent evt) {
+        fermerFenetre();
+      }
+    });
+
+  }
+  public void premierPlan() {
+    if ((getExtendedState()&Frame.ICONIFIED)>0) {
+      setExtendedState(getExtendedState()&~Frame.ICONIFIED);
+    }
+    toFront();
+
+  }
+  private void fermerFenetre() {
+    sauvegarde();
+  }
+  boolean sauvegarde() {
+    if (!corpus.isModifie()) return true;
+    int rep = JOptionPane.showOptionDialog(this, "Sauvegarder le document en cours ?",
+            "Document modifié", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+            null, new Object[]{"Oui", "Non", "Annuler"}, "Non");
+    if (rep==2) {
+      return false;
+    }
+    if (rep==0) {
+      FichiersJava.enregistrerCorpusSous(corpus);
+    }
+    return true;
+  }
+  boolean fusionStructure() {
+    if (corpus.getStructure().isVide()) return true;
+    int rep = JOptionPane.showOptionDialog(this, "La nouvelle structure va être fusionnée avec la structure courante",
+            "Structure déjà présente", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+            null, new Object[]{"Poursuivre", "Annuler"}, "Poursuivre");
+    return rep==0;
+  }
+  public void traiterEvent(Message evt) {
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        nomCorpus = "";
+        Fichiers.removeFichierCourant(Fichiers.TypeFichier.DOC_ANALEC);
+        setTitre();
+        return;
+      case NEW_CORPUS:
+        nomCorpus = Fichiers.getNomFichierCourant(Fichiers.TypeFichier.DOC_ANALEC);
+        setTitre();
+        return;
+      case MODIF_VUE:
+        switch (((VueEvent) evt).getModif()) {
+          case VUE_DEFAUT:
+            nomVue = "";
+            setTitre();
+            return;
+          case NEW_VUE:
+            nomVue = Fichiers.getNomFichierCourant(Fichiers.TypeFichier.VUE);
+            setTitre();
+            return;
+          case EXTRACTION:
+            setTitre();
+            return;
+          default:
+            throw new UnsupportedOperationException("Cas "+((VueEvent) evt).getModif()+" oublié dans un switch");
+        }
+      case MODIF_TEXTE:
+      case MODIF_STRUCTURE:
+      case MODIF_ELEMENT:
+        setTitre();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+  }
+  private void setTitre() {
+    String titre = "Analec 1.5";
+    if (!nomCorpus.isEmpty()) {
+      titre += " : "+nomCorpus;
+      if (corpus.isModifie()) titre += "*";
+      if (nomVue.isEmpty()) {
+        if (vue.isModifiee()) titre += " - vue modifiée*";
+        else titre += " - vue par défaut";
+      } else {
+        titre += " - vue : "+nomVue;
+        if (vue.isModifiee()) titre += "*";
+      }
+    }
+    setTitle(titre);
+  }
+  public static void main(String[] args) {
+    VisuMain.args = args;
+    javax.swing.SwingUtilities.invokeLater(new Runnable() {
+      public void run() {
+        try {
+          // Fenêtre
+          lancerVisuAnalec();
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    });
+  }
+  public static void lancerVisuAnalec() throws IOException, ClassNotFoundException {
+    // Fenêtre
+    VisuMain fenetre = new VisuMain();
+    fenetre.setTitre();
+    Rectangle rmax = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
+    fenetre.setLocation(50, 50);
+    fenetre.setSize(rmax.width-100, rmax.height-100);
+    fenetre.setVisible(true);
+    fenetre.panneauEditeur.agencerPanneaux();
+    fenetre.traiterArguments(args);
+//    System.out.println(fenetre.corpus.getStructure().toString());
+//   new GMessages.GProgression(fenetre);
+  }
+  private void traiterArguments(String[] args) throws IOException, ClassNotFoundException {
+    if (args.length==0) return;
+    FichiersJava.ouvrirCorpusVue(corpus, vue, args[0]);
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/VisuMain.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/donnees/Corpus.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/donnees/Corpus.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/donnees/Corpus.java	(revision 3653)
@@ -0,0 +1,1013 @@
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.donnees;
+
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import java.util.ArrayList;
+import javax.swing.*;
+import visuAnalec.*;
+import visuAnalec.elements.*;
+import visuAnalec.Message.*;
+import visuAnalec.texte.PanneauTexte;
+import visuAnalec.util.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class Corpus {
+  public static interface CorpusListener extends EventListener {  // VisuAnalec, Vue et VisuStructure sont les seuls destinaires
+    void traiterEvent(Message e);
+  }
+  private ArrayList<CorpusListener> listeCorrespondants = new ArrayList<CorpusListener>();
+  private boolean modifie = false;
+  private String texte = "";
+  private ArrayList<Integer> finParagraphes = new ArrayList<Integer>();
+  private Structure structure = new Structure();
+  private HashMap<String, ArrayList<Unite>> unites = new HashMap<String, ArrayList<Unite>>();
+  private HashMap<String, ArrayList<Relation>> relations = new HashMap<String, ArrayList<Relation>>();
+  private HashMap<String, ArrayList<Schema>> schemas = new HashMap<String, ArrayList<Schema>>();
+  public void addEventListener(CorpusListener correspondant) {
+    listeCorrespondants.add(correspondant);
+  }
+  public void removeEventListener(CorpusListener correspondant) {
+    listeCorrespondants.remove(correspondant);
+  }
+  public ArrayList<CorpusListener> getListeDesCorrespondants() {
+	  return listeCorrespondants;
+  }
+  private void fireMessage(Message evt) {
+    modifie = !EnumSet.of(TypeMessage.CLEAR_CORPUS, TypeMessage.NEW_CORPUS).
+            contains(evt.getType());
+
+    for (Object corresp : listeCorrespondants.toArray()) {
+      ((CorpusListener) corresp).traiterEvent(evt);
+    }
+  }
+  public Structure getStructure() {
+    return structure;
+  }
+  public String getTexte() {
+    return texte;
+  }
+  public void setTexte(String texte) {
+    this.texte = texte;
+  }
+  public Integer[] getFinParagraphes() {
+    return finParagraphes.toArray(new Integer[0]);
+  }
+  public void setFinParagraphes(ArrayList<Integer> finpars) {
+    finParagraphes = finpars;
+  }
+  public String getTexteUnite(Unite unit) {
+    int deb = unit.getDeb();
+    int fin = unit.getFin();
+    return PanneauTexte.insereCarFinParagraphe(getTexte().substring(deb, fin),
+            getFinParagraphes(), deb);
+  }
+  public void modifTexte(String texte, ArrayList<Integer> finparag) {
+    this.texte = texte;
+    this.finParagraphes = finparag;
+    verifierFormesUnites();
+    fireMessage(new Message(this, TypeMessage.MODIF_TEXTE));
+  }
+  private void verifierFormesUnites() {
+    for (String type : structure.getTypes(Unite.class)) {
+      if (structure.getNomsProps(Unite.class, type).contains(Structure.FORME)) {
+        boolean modif = false;
+        for (Unite unit : getUnites(type)) {
+          String forme = getTexteUnite(unit);
+          if (!forme.equals(unit.getProp(Structure.FORME))) {
+            setValeurPropElement(unit, Structure.FORME, forme);
+          }
+        }
+      }
+    }
+  }
+  public void addFinParagraphe(int ind) {
+    finParagraphes.add(ind);
+  }
+  public void verifierFinParagrapheFinTexte() {
+    if (finParagraphes.isEmpty()
+            ||finParagraphes.get(finParagraphes.size()-1)<texte.length())
+      finParagraphes.add(texte.length());
+  }
+  public void trierFinParagraphes() {
+    Integer[] fins = getFinParagraphes();
+    Arrays.sort(fins);
+    finParagraphes = new ArrayList<Integer>(Arrays.asList(fins));
+  }
+  public void verifierFinParagraphesTypesUnites(String[] types) {
+    // Attention : les fins de paragraphes sont en désordre à la fin de la fonction
+    Integer[] fins = getFinParagraphes();
+    Arrays.sort(fins);
+    ArrayList<Integer> newFinPars = new ArrayList<Integer>();
+    for (String type : types) for (Unite unit : getUnites(type)) {
+        Integer fin = unit.getFin();
+        if (Arrays.binarySearch(fins, fin)<0) newFinPars.add(fin);
+      }
+    finParagraphes.addAll(newFinPars);
+  }
+  public int[] calculerNoParagraphe(Unite[] unites) {
+    // les unites sont triées
+    // les numéros de paragraphe commencent à 1 
+    int[] nosPar = new int[unites.length];
+    Integer[] finPar = getFinParagraphes();
+    Arrays.sort(finPar);
+    int nopar = 0;
+    for (int i = 0; i<unites.length; i++) {
+      while (unites[i].getDeb()>=finPar[nopar]) nopar++;
+      nosPar[i] = nopar+1;
+    }
+    return nosPar;
+  }
+  public String[][] getConcordances(Element[] elts, int empan) {
+    Integer[] finPar = getFinParagraphes();
+    String[][] concordances = new String[elts.length][3];
+    for (int i = 0; i<elts.length; i++) {
+      Unite unite0 = elts[i].getUnite0();
+      int debElt = unite0.getDeb();
+      int finElt = unite0.getFin();
+      int deb;
+      if (debElt-empan>0) {
+        concordances[i][0] = "[...]";
+        deb = debElt-empan;
+      } else {
+        concordances[i][0] = "";
+        deb = 0;
+      }
+      concordances[i][0] += PanneauTexte.insereCarFinParagraphe(
+              texte.substring(deb, debElt), finPar, deb);
+      concordances[i][1] = PanneauTexte.insereCarFinParagraphe(
+              texte.substring(debElt, finElt), finPar, debElt);
+      if (finElt+empan<texte.length()) {
+        concordances[i][2] = PanneauTexte.insereCarFinParagraphe(
+                texte.substring(finElt, finElt+empan), finPar, finElt)+"[...]";
+      } else
+        concordances[i][2] = PanneauTexte.insereCarFinParagraphe(
+                texte.substring(finElt), finPar, finElt);
+    }
+    return concordances;
+  }
+  public Unite addUniteSaisie(String type, int deb, int fin) { // ajout d'une unité saisie
+    Unite unite = new Unite(type, deb, fin);
+    addValeursDefauts(unite);
+    if (!unites.containsKey(type)) {
+      unites.put(type, new ArrayList<Unite>());
+    }
+    unites.get(type).add(unite);
+    fireMessage(new ElementEvent(this, TypeModifElement.AJOUT_UNITE, unite));
+    return unite;
+  }
+  public void addUniteLue(Unite unite) { // ajout d'une unité créée par la lecture d'un corpus: pas de message 
+    // et mise à jour éventuelle de la structure et de la HashMap unites
+    String type = unite.getType();
+    if (type==null||type.isEmpty()) return;
+    structure.majNewElement(unite);
+    if (!unites.containsKey(type)) {
+      unites.put(type, new ArrayList<Unite>());
+    }
+    unites.get(type).add(unite);
+  }
+  public void modifBornesUnite(Unite unite, int deb, int fin) {
+    unite.setDeb(deb);
+    unite.setFin(fin);
+    fireMessage(new ElementEvent(this, TypeModifElement.BORNES_UNITE, unite));
+  }
+  public void supUnite(Unite unite) {
+    String type = unite.getType();
+    unites.get(type).remove(unite);
+    fireMessage(new ElementEvent(this, TypeModifElement.SUP_UNITE, unite));
+    supLiensElement(unite);
+  }
+  public boolean checkPresenceUnite(String type, int deb, int fin) { // pas très efficace
+    if (!unites.containsKey(type)) return false;
+    for (Unite unit : getUnites(type))
+      if (unit.getDeb()==deb&&unit.getFin()==fin) return true;
+    return false;
+
+  }
+  private int checkFusionnerUnites(HashMap<String, ArrayList<Unite>> newunites, HashSet<Unite> unitesAajouter,
+          HashMap<Unite, Unite> unitesAfusionner) {
+    int nbEcrases = 0;
+    for (String type : newunites.keySet()) {
+      if (!unites.containsKey(type)) {
+        unitesAajouter.addAll(newunites.get(type));
+        continue;
+      }
+      for (Unite newunite : newunites.get(type)) {
+        Unite unit = chercherUniteCoincidente(newunite, unites.get(type));
+        if (unit==null) unitesAajouter.add(newunite);
+        else {
+          unitesAfusionner.put(newunite, unit);
+          for (String prop : newunite.getProps().keySet())
+            if (!unit.getProp(prop).isEmpty()&&!newunite.getProp(prop).isEmpty()
+                    &&!unit.getProp(prop).equals(newunite.getProp(prop))) {
+              nbEcrases++;
+              break;
+            }
+        }
+      }
+    }
+    return nbEcrases;
+  }
+  private Unite chercherUniteCoincidente(Unite unite, ArrayList<Unite> lunites) {
+    for (Unite unit : lunites) if (unite.coincide(unit)) return unit;
+    return null;
+  }
+  public void addRelationSaisie(String type, Element elt1, Element elt2) {
+    Relation relation = new Relation(type, elt1, elt2);
+    addValeursDefauts(relation);
+    if (!relations.containsKey(type)) {
+      relations.put(type, new ArrayList<Relation>());
+    }
+    relations.get(type).add(relation);
+    relation.getElt2().addRelationEntrante(relation);
+    relation.getElt1().addRelationSortante(relation);
+    fireMessage(new ElementEvent(this, TypeModifElement.AJOUT_RELATION, relation));
+  }
+  public void addRelationLue(Relation relation) { // ajout d'une relation créée par la lecture d'un corpus: pas de message
+    // et mise à jour éventuelle de la structure et de la HashMap relations
+    String type = relation.getType();
+    if (type==null||type.isEmpty()) return;
+    structure.majNewElement(relation);
+    if (!relations.containsKey(type)) {
+      relations.put(type, new ArrayList<Relation>());
+    }
+    relations.get(type).add(relation);
+    relation.getElt2().addRelationEntrante(relation);
+    relation.getElt1().addRelationSortante(relation);
+  }
+  public void supRelation(Relation rel) {
+    String type = rel.getType();
+    relations.get(type).remove(rel);
+    rel.getElt1().oteRelationSortante(rel);
+    rel.getElt2().oteRelationEntrante(rel);
+    fireMessage(new ElementEvent(this, TypeModifElement.SUP_RELATION, rel));
+    supLiensElement(rel);
+  }
+  private int checkFusionnerRelations(HashMap<String, ArrayList<Relation>> newrels, HashSet<Relation> relsAajouter,
+          HashMap<Relation, Relation> relsAfusionner) {
+    int nbEcrases = 0;
+    for (String type : newrels.keySet()) {
+      if (!relations.containsKey(type)) {
+        relsAajouter.addAll(newrels.get(type));
+        continue;
+      }
+      for (Relation newrel : newrels.get(type)) {
+        Relation rel = chercherRelationCoincidente(newrel, relations.get(type));
+        if (rel==null) relsAajouter.add(newrel);
+        else {
+          relsAfusionner.put(newrel, rel);
+          for (String prop : newrel.getProps().keySet())
+            if (!rel.getProp(prop).isEmpty()&&!newrel.getProp(prop).isEmpty()
+                    &&!rel.getProp(prop).equals(newrel.getProp(prop))) {
+              nbEcrases++;
+              break;
+            }
+        }
+      }
+    }
+    return nbEcrases;
+  }
+  private Relation chercherRelationCoincidente(Relation rel, ArrayList<Relation> lrels) {
+    for (Relation rel1 : lrels) if (rel.coincide(rel1)) return rel1;
+    return null;
+  }
+  private static void fusionnerElementsRelation(Relation relation, HashMap<Unite, Unite> unitesAfusionner,
+          HashMap<Relation, Relation> relationsAfusionner, HashMap<Schema, Schema> schemasAfusionner) {
+    if (relation.getElt1().getClass()==Unite.class&&unitesAfusionner.containsKey(relation.getElt1()))
+      relation.setElt1(unitesAfusionner.get(relation.getElt1()));
+    else if (relation.getElt1().getClass()==Relation.class&&relationsAfusionner.containsKey(relation.getElt1()))
+      relation.setElt1(relationsAfusionner.get(relation.getElt1()));
+    else if (relation.getElt1().getClass()==Schema.class&&schemasAfusionner.containsKey(relation.getElt1()))
+      relation.setElt1(schemasAfusionner.get(relation.getElt1()));
+    if (relation.getElt2().getClass()==Unite.class&&unitesAfusionner.containsKey(relation.getElt2()))
+      relation.setElt2(unitesAfusionner.get(relation.getElt2()));
+    else if (relation.getElt2().getClass()==Relation.class&&relationsAfusionner.containsKey(relation.getElt2()))
+      relation.setElt2(relationsAfusionner.get(relation.getElt2()));
+    else if (relation.getElt2().getClass()==Schema.class&&schemasAfusionner.containsKey(relation.getElt2()))
+      relation.setElt2(schemasAfusionner.get(relation.getElt2()));
+  }
+  public void addSchemaSaisi(String type, Element elt) {
+    Schema schema = new Schema(type);
+    addValeursDefauts(schema);
+    if (!schemas.containsKey(type)) {
+      schemas.put(type, new ArrayList<Schema>());
+    }
+    schemas.get(type).add(schema);
+    if (elt!=null) {
+      schema.ajouter(elt);
+      elt.addSchemaContenant(schema);
+    }
+    fireMessage(new ElementEvent(this, TypeModifElement.AJOUT_SCHEMA, schema));
+  }
+  public void addSchemaLu(Schema schema) {  // ajout d'un schéma créé par la lecture d'un corpus: pas de message
+    // et mise à jour éventuelle de la structure et de la HashMap schemas
+    String type = schema.getType();
+    if (type==null||type.isEmpty()) return;
+    structure.majNewElement(schema);
+    if (!schemas.containsKey(type)) {
+      schemas.put(type, new ArrayList<Schema>());
+    }
+    schemas.get(type).add(schema);
+    for (Element elt : schema.getContenu()) {
+      elt.addSchemaContenant(schema);
+    }
+  }
+  public void ajouterElementSchemaSaisi(Element elt, Schema sch) {
+    if (!sch.ajouter(elt)) {
+      GMessages.impossibiliteAction("Impossible d'ajouter cet élément "
+              +"au schéma courant :\n problème de récursivité infinie");
+    }
+    elt.addSchemaContenant(sch);
+    fireMessage(new ElementEvent(this, TypeModifElement.MODIF_SCHEMA, sch));
+  }
+  public void oterElementSchema(Element elt, Schema sch) {
+    sch.oter(elt);
+    elt.oteSchemaContenant(sch);
+    fireMessage(new ElementEvent(this, TypeModifElement.MODIF_SCHEMA, sch));
+  }
+  public void supSchema(Schema sch) {
+    String type = sch.getType();
+    schemas.get(type).remove(sch);
+    fireMessage(new ElementEvent(this, TypeModifElement.SUP_SCHEMA, sch));
+    supLiensElement(sch);
+  }
+  private int checkFusionnerSchemas(HashMap<String, ArrayList<Schema>> newschs, HashSet<Schema> schsAajouter,
+          HashMap<Schema, Schema> schsAfusionner) {
+    int nbEcrases = 0;
+    for (String type : newschs.keySet()) {
+      if (!schemas.containsKey(type)) {
+        schsAajouter.addAll(newschs.get(type));
+        continue;
+      }
+      for (Schema newsch : newschs.get(type)) {
+        Schema sch = chercherSchemaCoincident(newsch, schemas.get(type));
+        if (sch==null) schsAajouter.add(newsch);
+        else {
+          schsAfusionner.put(newsch, sch);
+          for (String prop : newsch.getProps().keySet())
+            if (!sch.getProp(prop).isEmpty()&&!newsch.getProp(prop).isEmpty()
+                    &&!sch.getProp(prop).equals(newsch.getProp(prop))) {
+              nbEcrases++;
+              break;
+            }
+        }
+      }
+    }
+    return nbEcrases;
+  }
+  private Schema chercherSchemaCoincident(Schema sch, ArrayList<Schema> lschs) {
+    for (Schema sch1 : lschs) if (sch.coincide(sch1)) return sch1;
+    return null;
+  }
+  private static void fusionnerElementsSchema(Schema schema, HashMap<Unite, Unite> unitesAfusionner,
+          HashMap<Relation, Relation> relationsAfusionner, HashMap<Schema, Schema> schemasAfusionner) {
+    for (Element elt : schema.getContenu()) {
+      if (elt.getClass()==Unite.class&&unitesAfusionner.containsKey(elt)) {
+        schema.oter(elt);
+        schema.ajouter(unitesAfusionner.get(elt));
+      } else if (elt.getClass()==Relation.class&&relationsAfusionner.containsKey(elt)) {
+        schema.oter(elt);
+        schema.ajouter(relationsAfusionner.get(elt));
+      } else if (elt.getClass()==Schema.class&&schemasAfusionner.containsKey(elt)) {
+        schema.oter(elt);
+        schema.ajouter(schemasAfusionner.get(elt));
+      }
+    }
+  }
+  private void supLiensElement(Element elt) {
+    ArrayList<Relation> rels = elt.getRelations();
+    for (Relation rel : rels) {
+      supRelation(rel);
+    }
+    ArrayList<Schema> schs = elt.getSchemas();
+    for (Schema sch : schs) {
+      oterElementSchema(elt, sch);
+    }
+  }
+  public void addValeur(Class<? extends Element> classe, String type, String prop, String valeur) {
+    structure.ajouterVal(classe, type, prop, valeur);
+    fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_VALEUR, classe, type, prop, valeur));
+  }
+  public void addValeursDefauts(Element elt) {
+    for (String prop : structure.getNomsProps(elt.getClass(), elt.getType())) {
+      elt.putProp(prop, structure.getValeurParDefaut(elt.getClass(), elt.getType(), prop));
+    }
+  }
+  public void ajouterFormeUnite(String type) {
+    structure.ajouterProp(Unite.class, type, Structure.FORME);
+    fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_FORME_UNITE,
+            Unite.class, type));
+  }
+  public void instancierFormeUnite(String type) {
+    ArrayList<Unite> units = getUnites(type);
+    for (Unite unit : units) {
+      String forme = getTexteUnite(unit);
+      setValeurPropElement(unit, Structure.FORME, forme);
+    }
+  }
+  public void modifierValParDefaut(Class<? extends Element> classe, String type, String prop, String val) {
+    structure.modifierValParDefaut(classe, type, prop, val);
+    if (!val.isEmpty()) instancierParValeurDefaut(classe, type, prop, val);
+    fireMessage(new StructureEvent(this, TypeModifStructure.VALEUR_PAR_DEFAUT, classe, type, prop, val));
+  }
+  private void instancierParValeurDefaut(Class<? extends Element> classe, String type, String prop, String val) {
+    ArrayList<? extends Element> elts = getElements(classe, type);
+    boolean noninstancies = false;
+    for (Element elt : elts) if (elt.getProp(prop).isEmpty()) {
+        noninstancies = true;
+        break;
+      }
+    if (noninstancies&&JOptionPane.showConfirmDialog(null, "Voulez-vous donner "
+            +"cette valeur par défaut aux éléments existants non encore instanciés",
+            "Action optionnelle", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE)
+            !=JOptionPane.NO_OPTION)
+      for (Element elt : elts) if (elt.getProp(prop).isEmpty())
+          elt.putProp(prop, val);
+  }
+  public void setValeurPropElement(Element elt, String prop, String newval) {
+    if (newval.isEmpty()) {
+      elt.supProp(prop);
+    } else {
+      if (!structure.getValeursProp(elt.getClass(), elt.getType(), prop).contains(newval)) {
+        addValeur(elt.getClass(), elt.getType(), prop, newval);
+      }
+      elt.putProp(prop, newval);
+    }
+    fireMessage(new ElementEvent(this, TypeModifElement.MODIF_VALEUR, elt, prop, newval));
+
+  }
+  public ArrayList<? extends Element> getElements(Class<? extends Element> classe, String type) {
+    if (classe==Unite.class) return getUnites(type);
+    if (classe==Relation.class) return getRelations(type);
+    if (classe==Schema.class) return getSchemas(type);
+    throw new UnsupportedOperationException("sous-classe non traitée");
+  }
+  public ArrayList<Unite> getUnites(String type) {
+    if (unites.get(type)==null) {
+      return new ArrayList<Unite>();
+    }
+    return unites.get(type);
+  }
+  public ArrayList<Unite> getToutesUnites() {
+    ArrayList<Unite> ttesUnites = new ArrayList<Unite>();
+    for (String type : structure.getTypes(Unite.class)) {
+      ttesUnites.addAll(getUnites(type));
+    }
+    return ttesUnites;
+  }
+  public ArrayList<Relation> getRelations(String type) {
+    if (relations.get(type)==null) {
+      return new ArrayList<Relation>();
+    }
+    return relations.get(type);
+  }
+  public ArrayList<Relation> getToutesRelations() {
+    ArrayList<Relation> ttesRelations = new ArrayList<Relation>();
+    for (String type : structure.getTypes(Relation.class)) {
+      ttesRelations.addAll(getRelations(type));
+    }
+    return ttesRelations;
+  }
+  public ArrayList<Schema> getSchemas(String type) {
+    if (schemas.get(type)==null) {
+      return new ArrayList<Schema>();
+    }
+    return schemas.get(type);
+  }
+  public ArrayList<Schema> getTousSchemas() {
+    ArrayList<Schema> tsSchemas = new ArrayList<Schema>();
+    for (String type : structure.getTypes(Schema.class)) {
+      tsSchemas.addAll(getSchemas(type));
+    }
+    return tsSchemas;
+  }
+// Modifs de la structure provenant de VisuStructure
+  public String saisirAjouterType(Container fenetre, Class<? extends Element> classe) {
+    String newNom = JOptionPane.showInputDialog(fenetre, "Nom du nouveau type ",
+            "Ajouter un type "+GVisu.getNomDeClasse(classe),
+            JOptionPane.PLAIN_MESSAGE);
+    if (newNom==null) return null;
+    newNom = newNom.trim();
+    if (newNom.isEmpty()) return null;
+    if (structure.getTypes(classe).contains(newNom)) {
+      JOptionPane.showMessageDialog(fenetre, "Ajout impossible : le type "+"\""+newNom+"\""+" existe déjà",
+              "Erreur d'ajout de type", JOptionPane.ERROR_MESSAGE);
+      return null;
+    }
+    ajouterType(classe, newNom);
+    fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_TYPE, classe, newNom));
+    return newNom;
+  }
+  private void ajouterType(Class<? extends Element> classe, String type) {
+    structure.ajouterType(classe, type);
+    if (classe==Unite.class) {
+      unites.put(type, new ArrayList<Unite>());
+    } else if (classe==Relation.class) {
+      relations.put(type, new ArrayList<Relation>());
+    } else if (classe==Schema.class) {
+      schemas.put(type, new ArrayList<Schema>());
+    }
+  }
+  public String saisirAjouterProp(Container fenetre, Class<? extends Element> classe, String type) {
+    String newNom = JOptionPane.showInputDialog(fenetre, "Nom de la nouvelle propriété",
+            "Ajouter une propriété au type "+"\""+type+"\"", JOptionPane.PLAIN_MESSAGE);
+    if (newNom==null) return null;
+    newNom = newNom.trim();
+    if (newNom.isEmpty()) return null;
+    if (Structure.FORME.equals(newNom)) {
+      GMessages.impossibiliteAction("Le nom "+Structure.FORME+" est réservé par le système");
+      return null;
+    }
+    if (structure.getNomsProps(classe, type).contains(newNom)) {
+      JOptionPane.showMessageDialog(fenetre, "Ajout impossible :la propriété "+"\""+newNom+"\""+" existe déjà",
+              "Erreur d'ajout de propriété", JOptionPane.ERROR_MESSAGE);
+      return null;
+    }
+    structure.ajouterProp(classe, type, newNom);
+    fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_PROP, classe, type, newNom));
+    return newNom;
+  }
+  public String saisirAjouterVal(Container fenetre, Class<? extends Element> classe, String type, String prop) {
+    String newNom = JOptionPane.showInputDialog(fenetre, "Nom de la nouvelle valeur",
+            "Ajouter une valeur pour la propriété "+"\""+prop+"\"", JOptionPane.PLAIN_MESSAGE);
+    if (newNom==null) return null;
+    newNom = newNom.trim();
+    if (newNom.isEmpty()) return null;
+    if (structure.getValeursProp(classe, type, prop).contains(newNom)) {
+      JOptionPane.showMessageDialog(fenetre, "Ajout impossible : la valeur "+"\""+newNom+"\""+" existe déjà",
+              "Erreur d'ajout de valeur", JOptionPane.ERROR_MESSAGE);
+      return null;
+    }
+    structure.ajouterVal(classe, type, prop, newNom);
+    fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_VALEUR, classe, type, prop, newNom));
+    return newNom;
+  }
+  public String saisirRenommerType(Container fenetre, Class<? extends Element> classe, String oldNom) {
+    String newNom = (String) JOptionPane.showInputDialog(fenetre, "Nouveau nom pour le type "+"\""+oldNom+"\"",
+            "Renommer un type "+GVisu.getNomDeClasse(classe), JOptionPane.PLAIN_MESSAGE, null, null, oldNom);
+    if (newNom==null) return null;
+    newNom = newNom.trim();
+    if (oldNom.equals(newNom)||newNom.isEmpty()) return null;
+    boolean fusion = structure.getTypes(classe).contains(newNom);
+    if (fusion&&!GMessages.confirmationAction("Le type "+"\""+newNom+"\""
+            +" existe déjà. Fusionner les deux types ? ")) return null;
+    if (classe==Unite.class) {
+      if (fusion) unites.get(newNom).addAll(unites.get(oldNom));
+      else unites.put(newNom, unites.get(oldNom));
+      for (Unite unit : unites.get(oldNom)) unit.setType(newNom);
+      unites.remove(oldNom);
+    } else if (classe==Relation.class) {
+      if (fusion) relations.get(newNom).addAll(relations.get(oldNom));
+      else relations.put(newNom, relations.get(oldNom));
+      for (Relation rel : relations.get(oldNom)) {
+        rel.getElt1().oteRelationSortante(rel);
+        rel.getElt2().oteRelationEntrante(rel);
+        rel.setType(newNom);
+        rel.getElt1().addRelationSortante(rel);
+        rel.getElt2().addRelationEntrante(rel);
+      }
+      relations.remove(oldNom);
+    } else if (classe==Schema.class) {
+      if (fusion) schemas.get(newNom).addAll(schemas.get(oldNom));
+      else schemas.put(newNom, schemas.get(oldNom));
+      for (Schema sch : schemas.get(oldNom)) {
+        for (Element elt : sch.getContenu()) elt.oteSchemaContenant(sch);
+        sch.setType(newNom);
+        for (Element elt : sch.getContenu()) elt.addSchemaContenant(sch);
+      }
+      schemas.remove(oldNom);
+    }
+    if (fusion) {
+      structure.fusionnerType(classe, oldNom, newNom);
+      fireMessage(new StructureEvent(this, TypeModifStructure.FUSION_TYPE,
+              classe, oldNom, newNom));
+    } else {
+      structure.renommerType(classe, oldNom, newNom);
+      fireMessage(new StructureEvent(this, TypeModifStructure.RENOM_TYPE,
+              classe, oldNom, newNom));
+    }
+    return newNom;
+  }
+  public String saisirRenommerProp(Container fenetre,
+          Class<? extends Element> classe, String type, String oldNom) {
+    String newNom = (String) JOptionPane.showInputDialog(fenetre, "Nouveau nom pour la propriété "+"\""+oldNom+"\"",
+            "Renommer une propriété du type "+"\""+type+"\"", JOptionPane.PLAIN_MESSAGE, null, null, oldNom);
+    if (newNom==null) return null;
+    newNom = newNom.trim();
+    if (oldNom.equals(newNom)||newNom.isEmpty()) return null;
+    if (Structure.FORME.equals(newNom)) {
+      GMessages.impossibiliteAction("Le nom "+Structure.FORME+" est réservé par le système");
+      return null;
+    }
+    boolean fusion = false;
+    ArrayList<? extends Element> elements = getElements(classe, type);
+    if (structure.getNomsProps(classe, type).contains(newNom)) {
+      int rep = JOptionPane.showOptionDialog(fenetre, "La propriété "+"\""+newNom+"\""+" existe déjà."
+              +" Fusionner les deux propriétés ? ", "Propriété existante",
+              JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+              null, new Object[]{"Oui", "Annuler"}, "Oui");
+      if (rep==1) return null;
+      int nbEcrases = 0;
+      for (Element elt : elements) if (!elt.getProp(newNom).isEmpty()
+                &&!elt.getProp(newNom).equals(elt.getProp(oldNom))) nbEcrases++;
+      if (nbEcrases>0) {
+        int rep1 = JOptionPane.showOptionDialog(fenetre, "L'opération de fusion va écraser l'ancienne valeur de la propriété "
+                +"\""+newNom+"\""+" pour "+nbEcrases+" élément(s)", "Fusion de deux propriétés",
+                JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+                null, new Object[]{"Continuer", "Annuler"}, "Continuer");
+        if (rep1==1) return null;
+      }
+      fusion = true;
+    }
+    if (fusion) structure.fusionnerProp(classe, type, oldNom, newNom);
+    else structure.renommerProp(classe, type, oldNom, newNom);
+    for (Element elt : elements) {
+      String val = elt.getProp(oldNom);
+      if (!val.isEmpty()) elt.putProp(newNom, val);
+      elt.getProps().remove(oldNom);
+    }
+    if (fusion)
+      fireMessage(new StructureEvent(this, TypeModifStructure.FUSION_PROP, classe, type, oldNom, newNom));
+    else
+      fireMessage(new StructureEvent(this, TypeModifStructure.RENOM_PROP, classe, type, oldNom, newNom));
+    return newNom;
+  }
+  public String saisirRenommerVal(Container fenetre, Class<? extends Element> classe, String type,
+          String prop, String oldNom) {
+    String newNom = (String) JOptionPane.showInputDialog(fenetre, "Nouveau nom pour la valeur "+"\""+oldNom+"\"",
+            "Renommer une valeur de la propriété "+"\""+prop+"\"", JOptionPane.PLAIN_MESSAGE, null, null, oldNom);
+    if (newNom==null) return null;
+    newNom = newNom.trim();
+    if (oldNom.equals(newNom)||newNom.isEmpty()) return null;
+    boolean fusion = false;
+    if (structure.getValeursProp(classe, type, prop).contains(newNom)) {
+      int rep = JOptionPane.showOptionDialog(fenetre, "La valeur "+"\""+newNom+"\""+" existe déjà."
+              +" Fusionner les deux valeurs ? ", "Valeur existante",
+              JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+              null, new Object[]{"Oui", "Annuler"}, "Oui");
+      if (rep==1) return null;
+      fusion = true;
+    }
+    structure.renommerVal(classe, type, prop, oldNom, newNom);
+    ArrayList<? extends Element> elements = getElements(classe, type);
+    for (Element elt : elements) {
+      String val = elt.getProp(prop);
+      if (oldNom.equals(val)) {
+        elt.putProp(prop, newNom);
+      }
+    }
+    if (fusion)
+      fireMessage(new StructureEvent(this, TypeModifStructure.FUSION_VALEUR, classe, type, prop, oldNom, newNom));
+    else
+      fireMessage(new StructureEvent(this, TypeModifStructure.RENOM_VALEUR, classe, type, prop, oldNom, newNom));
+    return newNom;
+  }
+  public boolean saisirSupprimerType(Container fenetre, Class<? extends Element> classe, String type) {
+    Element[] elements = new Element[0];
+    if (classe==Unite.class) {
+      if (unites.containsKey(type))
+        elements = unites.get(type).toArray(elements);
+    } else if (classe==Relation.class) {
+      if (unites.containsKey(type))
+        elements = relations.get(type).toArray(elements);
+    } else if (classe==Schema.class) {
+      if (unites.containsKey(type))
+        elements = schemas.get(type).toArray(elements);
+    }
+    if (elements.length>0) {
+      int nbSupprimes = elements.length;
+      int rep = JOptionPane.showOptionDialog(fenetre, "La suppresion du type  "+"\""+type+"\""
+              +" va entraîner la suppression "+(nbSupprimes==1 ? "d'un élément" : "de "+nbSupprimes+" éléments"),
+              "Suppression "+GVisu.getNomDeClasse(classe)+"s",
+              JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+              null, new Object[]{"Continuer", "Annuler"}, "Continuer");
+      if (rep==1) return false;
+      if (classe==Unite.class) {
+        for (Element elt : elements) supUnite((Unite) elt);
+        unites.remove(type);
+      }
+      if (classe==Relation.class) {
+        for (Element elt : elements) supRelation((Relation) elt);
+        relations.remove(type);
+      }
+      if (classe==Schema.class) {
+        for (Element elt : elements) supSchema((Schema) elt);
+        schemas.remove(type);
+      }
+    }
+    structure.supprimerType(classe, type);
+    fireMessage(new StructureEvent(this, TypeModifStructure.SUPPR_TYPE, classe, type));
+    return true;
+  }
+  public boolean saisirSupprimerProp(Container fenetre, Class<? extends Element> classe, String type, String oldNom) {
+    ArrayList<? extends Element> elements = getElements(classe, type);
+    int nbSup = 0;
+    for (Element elt : elements) if (!elt.getProp(oldNom).isEmpty()) nbSup++;
+    if (nbSup>0) {
+      int rep = JOptionPane.showOptionDialog(fenetre, "La propriété "+"\""+oldNom+"\""+" était instanciée pour "
+              +(nbSup==1 ? "un élément" : nbSup+" éléments"), "Suppression d'une propriété",
+              JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+              null, new Object[]{"Continuer", "Annuler"}, "Continuer");
+      if (rep==1) return false;
+    }
+    for (Element elt : elements) elt.supProp(oldNom);
+    structure.supprimerProp(classe, type, oldNom);
+    fireMessage(new StructureEvent(this, TypeModifStructure.SUPPR_PROP, classe, type, oldNom));
+    return true;
+  }
+  public boolean saisirSupprimerVal(Container fenetre, Class<? extends Element> classe, String type,
+          String prop, String oldNom) {
+    ArrayList<? extends Element> elements = getElements(classe, type);
+    int nbSup = 0;
+    for (Element elt : elements) if (oldNom.equals(elt.getProp(prop)))
+        nbSup++;
+    if (nbSup>0) {
+      int rep = JOptionPane.showOptionDialog(fenetre, "La valeur "+"\""+oldNom+"\""+" était attribuée à "
+              +(nbSup==1 ? "un élément" : nbSup+" éléments"), "Suppression d'une valeur",
+              JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+              null, new Object[]{"Continuer", "Annuler"}, "Continuer");
+      if (rep==1) return false;
+    }
+    structure.supprimerVal(classe, type, prop, oldNom);
+    for (Element elt : elements) if (oldNom.equals(elt.getProp(prop)))
+        elt.supProp(prop);
+    fireMessage(new StructureEvent(this, TypeModifStructure.SUPPR_VALEUR, classe, type, prop, oldNom));
+    return true;
+  }
+  public boolean saisirDispatcherProp(Container fenetre,
+          Class<? extends Element> classe, String oldtype, String oldprop,
+          String[] newtypes, String[] props, String[][] propsvals) {
+    HashSet<String> types = structure.getTypes(classe);
+    for (String type : newtypes) if (types.contains(type)) {
+        GMessages.impossibiliteAction("Le type "+type+" existe déjà");
+        return false;
+      }
+    ArrayList<? extends Element> elements = getElements(classe, oldtype);
+    for (Element elt : elements) if (elt.getProp(oldprop).isEmpty()) {
+        GMessages.impossibiliteAction("Certains éléments de type "+oldtype
+                +" ne possèdent pas de valeur pour la propriété "+oldprop);
+        return false;
+      }
+    structure.supprimerType(classe, oldtype);
+    for (String type : newtypes) {
+      structure.ajouterType(classe, type);
+      for (int i = 0; i<props.length; i++) {
+        structure.ajouterProp(classe, type, props[i]);
+        for (String val : propsvals[i])
+          structure.ajouterVal(classe, type, props[i], val);
+      }
+    }
+    if (classe==Unite.class) {
+      for (String type : newtypes) unites.put(type, new ArrayList<Unite>());
+      for (Unite unit : unites.get(oldtype)) {
+        String newtype = unit.getProp(oldprop);
+        unit.supProp(oldprop);
+        unit.setType(newtype);
+        unites.get(newtype).add(unit);
+      }
+      unites.remove(oldtype);
+    } else if (classe==Relation.class) {
+      for (String type : newtypes)
+        relations.put(type, new ArrayList<Relation>());
+      for (Relation rel : relations.get(oldtype)) {
+        String newtype = rel.getProp(oldprop);
+        rel.supProp(oldprop);
+        rel.getElt1().oteRelationSortante(rel);
+        rel.getElt2().oteRelationEntrante(rel);
+        rel.setType(newtype);
+        rel.getElt1().addRelationSortante(rel);
+        rel.getElt2().addRelationEntrante(rel);
+        relations.get(newtype).add(rel);
+      }
+      relations.remove(oldtype);
+    } else if (classe==Schema.class) {
+      for (String type : newtypes) schemas.put(type, new ArrayList<Schema>());
+      for (Schema sch : schemas.get(oldtype)) {
+        String newtype = sch.getProp(oldprop);
+        sch.supProp(oldprop);
+        for (Element elt : sch.getContenu()) elt.oteSchemaContenant(sch);
+        sch.setType(newtype);
+        for (Element elt : sch.getContenu()) elt.addSchemaContenant(sch);
+        schemas.get(newtype).add(sch);
+      }
+      schemas.remove(oldtype);
+    }
+    fireMessage(new StructureEvent(this, TypeModifStructure.SUPPR_TYPE,
+            classe, oldtype));
+    for (String type : newtypes) {
+      fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_TYPE_ET_ELEMENTS,
+              classe, type));
+      for (String prop : props)
+        fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_PROP,
+                classe, type, prop));
+    }
+    return true;
+  }
+  public void clearAnnot() {
+    finParagraphes.clear();
+    unites.clear();
+    relations.clear();
+    schemas.clear();
+  }
+  public void clearAll() {
+    clearAnnot();
+    structure.clear();
+    texte = "";
+  }
+  public boolean isModifie() {
+    return modifie;
+  }
+  public boolean isVide() {
+    return texte.isEmpty()&&structure.isVide();
+  }
+  public void fermer() {
+    if (isVide()) return;
+    clearAnnot();
+    structure.clear();
+    texte = "";
+    fireMessage(new Message(this, TypeMessage.CLEAR_CORPUS));
+  }
+  public void fermerConserverStructure() {
+    if (texte.isEmpty()) return;
+    clearAnnot();
+    texte = "";
+    fireMessage(new Message(this, TypeMessage.CLEAR_CORPUS));
+  }
+  @SuppressWarnings("unchecked")
+  public void lireJava(ObjectInputStream ois, boolean batch) throws IOException, ClassNotFoundException, ClassCastException {
+    texte = (String) ois.readObject();
+    finParagraphes = (ArrayList<Integer>) ois.readObject();
+    unites = (HashMap<String, ArrayList<Unite>>) ois.readObject();
+    relations = (HashMap<String, ArrayList<Relation>>) ois.readObject();
+    schemas = (HashMap<String, ArrayList<Schema>>) ois.readObject();
+    structure = Structure.lireJava(ois);
+    if (!batch) fireMessage(new Message(this, TypeMessage.NEW_CORPUS));
+  }
+  @SuppressWarnings("unchecked")
+  public void fusionnerAnnotJava(ObjectInputStream ois) throws IOException, ClassNotFoundException, ClassCastException {
+    String texte1 = (String) ois.readObject();
+    ArrayList<Integer> finParagraphes1 = (ArrayList<Integer>) ois.readObject();
+    if (!texte1.equals(texte)||!finParagraphes1.equals(finParagraphes)) {
+      JOptionPane.showMessageDialog(null, "Le texte du corpus à fusionner est différent du texte en cours",
+              "Fusion d'annotations impossible.", JOptionPane.ERROR_MESSAGE);
+      return;
+    }
+    HashMap<String, ArrayList<Unite>> unites1 = (HashMap<String, ArrayList<Unite>>) ois.readObject();
+    HashMap<String, ArrayList<Relation>> relations1 = (HashMap<String, ArrayList<Relation>>) ois.readObject();
+    HashMap<String, ArrayList<Schema>> schemas1 = (HashMap<String, ArrayList<Schema>>) ois.readObject();
+    Structure structure1 = Structure.lireJava(ois);
+    fusionnerStructureLue(structure1);
+    HashSet<Unite> unitesAajouter = new HashSet<Unite>();
+    HashMap<Unite, Unite> unitesAfusionner = new HashMap<Unite, Unite>();
+    int nbUnitesEcrasees = checkFusionnerUnites(unites1, unitesAajouter, unitesAfusionner);
+    HashSet<Relation> relationsAajouter = new HashSet<Relation>();
+    HashMap<Relation, Relation> relationsAfusionner = new HashMap<Relation, Relation>();
+    int nbRelationsEcrasees = checkFusionnerRelations(relations1, relationsAajouter, relationsAfusionner);
+    HashSet<Schema> schemasAajouter = new HashSet<Schema>();
+    HashMap<Schema, Schema> schemasAfusionner = new HashMap<Schema, Schema>();
+    int nbSchemasEcrases = checkFusionnerSchemas(schemas1, schemasAajouter, schemasAfusionner);
+    int nbEcrases = nbUnitesEcrasees+nbRelationsEcrasees+nbSchemasEcrases; // à améliorer
+    if (nbUnitesEcrasees>0||nbRelationsEcrasees>0||nbSchemasEcrases>0) {
+      int rep = JOptionPane.showOptionDialog(null, "L'opération de fusion va écraser d'anciennes valeurs de propriétés "
+              +" pour "+nbEcrases+" élément(s)", "Fusion d'annotations",
+              JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+              null, new Object[]{"Continuer", "Annuler"}, "Continuer");
+      if (rep==1) return;
+    }
+    for (Unite unit : unitesAajouter) addUniteLue(unit);
+    for (Unite unit : unitesAfusionner.keySet())
+      for (String prop : unit.getProps().keySet())
+        unitesAfusionner.get(unit).putProp(prop, unit.getProp(prop));
+    for (Relation rel : relationsAajouter) {
+      fusionnerElementsRelation(rel, unitesAfusionner, relationsAfusionner, schemasAfusionner);
+      addRelationLue(rel);
+    }
+    for (Relation rel : relationsAfusionner.keySet())
+      for (String prop : rel.getProps().keySet())
+        relationsAfusionner.get(rel).putProp(prop, rel.getProp(prop));
+    for (Schema sch : schemasAajouter) {
+      fusionnerElementsSchema(sch, unitesAfusionner, relationsAfusionner, schemasAfusionner);
+      addSchemaLu(sch);
+    }
+    for (Schema sch : schemasAfusionner.keySet())
+      for (String prop : sch.getProps().keySet())
+        unitesAfusionner.get(sch).putProp(prop, sch.getProp(prop));
+    fireMessage(new Message(this, TypeMessage.NEW_CORPUS));
+  }
+  @SuppressWarnings("unchecked")
+  public void concatenerCorpusJava(ObjectInputStream ois) throws IOException, ClassNotFoundException, ClassCastException {
+    String texte1 = (String) ois.readObject();
+    ArrayList<Integer> finParagraphes1 = (ArrayList<Integer>) ois.readObject();
+    int offset = texte.length();
+    texte += texte1;
+    for (int finP : finParagraphes1) finParagraphes.add(finP+offset);
+    verifierFinParagrapheFinTexte();
+    HashMap<String, ArrayList<Unite>> unites1 = (HashMap<String, ArrayList<Unite>>) ois.readObject();
+    HashMap<String, ArrayList<Relation>> relations1 = (HashMap<String, ArrayList<Relation>>) ois.readObject();
+    HashMap<String, ArrayList<Schema>> schemas1 = (HashMap<String, ArrayList<Schema>>) ois.readObject();
+    Structure structure1 = Structure.lireJava(ois);
+    fusionnerStructureLue(structure1);
+    for (String type : unites1.keySet()) for (Unite unit : unites1.get(type)) {
+        unit.setDeb(unit.getDeb()+offset);
+        unit.setFin(unit.getFin()+offset);
+        addUniteLue(unit);
+      }
+    for (String type : relations1.keySet())
+      for (Relation rel : relations1.get(type)) {
+        addRelationLue(rel);
+      }
+    for (String type : schemas1.keySet())
+      for (Schema sch : schemas1.get(type)) {
+        addSchemaLu(sch);
+      }
+  }
+  @SuppressWarnings("unchecked")
+  public void extraireEtConcatenerCorpusJava(ObjectInputStream ois,
+          String nomDocument, String type)
+          throws IOException, ClassNotFoundException, ClassCastException {
+//    System.out.println(nomDocument);
+    String texte1 = (String) ois.readObject();
+    ArrayList<Integer> finParagraphes1 = (ArrayList<Integer>) ois.readObject();
+    HashMap<String, ArrayList<Unite>> unites1 = (HashMap<String, ArrayList<Unite>>) ois.readObject();
+    if (unites1.containsKey(type)) {
+      int indFinPar1 = -1;
+      int offset1 = -1;
+      int offset = -1;
+      for (Unite unit : unites1.get(type)) {
+        int finUnit = unit.getFin();
+        if (indFinPar1<0||finUnit>finParagraphes1.get(indFinPar1)) {
+          do indFinPar1++;
+          while (finUnit>finParagraphes1.get(indFinPar1));
+          offset1 = indFinPar1==0 ? 0 : finParagraphes1.get(indFinPar1-1);
+          offset = texte.length();
+          texte += texte1.substring(offset1, finParagraphes1.get(indFinPar1));
+          finParagraphes.add(texte.length());
+        }
+        unit.setDeb(unit.getDeb()-offset1+offset);
+        unit.setFin(unit.getFin()-offset1+offset);
+        unit.putProp("sourceFile", nomDocument);
+        addUniteLue(unit);
+      }
+    }
+  }
+  public void ecrireJava(ObjectOutputStream oos) throws IOException {
+    oos.writeObject(texte);
+    oos.writeObject(finParagraphes);
+    oos.writeObject(unites);
+    oos.writeObject(relations);
+    oos.writeObject(schemas);
+    structure.ecrireJava(oos);
+    modifie = false;
+  }
+  @SuppressWarnings("unchecked")
+  public void fusionnerStructureLue(Structure structureLue) {
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class
+    }) {
+      for (String typeLu : structureLue.getTypes(classe)) {
+        if (!structure.getTypes(classe).contains(typeLu))
+          ajouterType(classe, typeLu);
+        for (String propLue : structureLue.getNomsProps(classe, typeLu)) {
+          if (!structure.getNomsProps(classe, typeLu).contains(propLue))
+            structure.ajouterProp(classe, typeLu, propLue);
+          for (String valLue : structureLue.getValeursProp(classe, typeLu, propLue))
+            if (!structure.getValeursProp(classe, typeLu, propLue).contains(valLue))
+              structure.ajouterVal(classe, typeLu, propLue, valLue);
+          String valdefLue = structureLue.getValeurParDefaut(classe, typeLu, propLue);
+          String valdef = structure.getValeurParDefaut(classe, typeLu, propLue);
+          if (!valdefLue.isEmpty()&&!valdefLue.equals(valdef)) {
+            structure.modifierValParDefaut(classe, typeLu, propLue, valdefLue);
+          }
+        }
+      }
+    }
+  }
+  public void ecrireStructureJava(ObjectOutputStream oos) throws IOException {
+    structure.ecrireJava(oos);
+  }
+  public Structure lireStructureJava(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+    return Structure.lireJava(ois);
+  }
+  public void lireTexte(BufferedReader text) throws IOException {
+    String parag;
+    String newtexte = "";
+    ArrayList<Integer> newfinParag = new ArrayList<Integer>();
+    while ((parag = text.readLine())!=null) {
+      newtexte += parag;
+      newfinParag.add(newtexte.length());
+    }
+    texte = newtexte;
+    finParagraphes = newfinParag;
+    fireMessage(new Message(this, TypeMessage.NEW_CORPUS));
+  }
+  public void newCorpusLu() {
+    fireMessage(new Message(this, TypeMessage.NEW_CORPUS));
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/donnees/Corpus.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/donnees/Structure.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/donnees/Structure.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/donnees/Structure.java	(revision 3653)
@@ -0,0 +1,313 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.donnees;
+
+import java.io.*;
+import java.util.*;
+
+import visuAnalec.elements.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class Structure implements Serializable {
+  public final static String FORME = "#forme#";
+  private HashMap<Class<? extends Element>, HashSet<String>> types =
+          new HashMap<Class<? extends Element>, HashSet<String>>();
+  private HashMap<Class<? extends Element>, HashMap<String, HashSet<String>>> nomsProps =
+          new HashMap<Class<? extends Element>, HashMap<String, HashSet<String>>>();
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashSet<String>>>> valeursProps =
+          new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashSet<String>>>>();
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, String>>> valeursParDefaut =
+          new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, String>>>();
+
+  @SuppressWarnings("unchecked")
+  public Structure() {
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      types.put(classe, new HashSet<String>());
+      nomsProps.put(classe, new HashMap<String, HashSet<String>>());
+      valeursProps.put(classe, new HashMap<String, HashMap<String, HashSet<String>>>());
+      valeursParDefaut.put(classe, new HashMap<String, HashMap<String, String>>());
+    }
+  }
+  
+  public HashSet<String> getSchemas() {
+	  return this.getTypes(Schema.class);
+  }
+  
+  public HashSet<String> getRelations() {
+	  return this.getTypes(Relation.class);
+  }
+  
+  public HashSet<String> getUnites() {
+	  return this.getTypes(Unite.class);
+  }
+  
+  public HashSet<String> getSchemaProperties(String schema_type) {
+	  return getNomsProps(Schema.class, schema_type);
+  }
+  
+  public HashSet<String> getUniteProperties(String schema_type) {
+	  return getNomsProps(Unite.class, schema_type);
+  }
+  
+  public HashSet<String> getRelationProperties(String schema_type) {
+	  return getNomsProps(Relation.class, schema_type);
+  }
+
+  @Override
+  public String toString() {
+    String dump = "STRUCTURE :";
+    dump += "\n\tUNITES : ";
+    dump += "\n\t\tTYPES : ";
+    for (String type : types.get(Unite.class)) {
+      dump += type+"; ";
+    }
+    dump += "\n\t\tNOMSPROP : ";
+    for (String type : nomsProps.get(Unite.class).keySet()) {
+      dump += "\n\t\t\t"+type+" : ";
+      for (String prop : nomsProps.get(Unite.class).get(type)) {
+        dump += prop+"; ";
+      }
+    }
+    dump += "\n\t\tVALEURSPROP : ";
+    for (String type : valeursProps.get(Unite.class).keySet()) {
+      dump += "\n\t\t\t"+type+" : ";
+      for (String prop : valeursProps.get(Unite.class).get(type).keySet()) {
+        dump += "\n\t\t\t\t"+prop+" : ";
+        for (String val : valeursProps.get(Unite.class).get(type).get(prop)) {
+          dump += val+"; ";
+        }
+      }
+    }
+
+    dump += "\n\tRELATIONS : ";
+    dump += "\n\t\tTYPES : ";
+    for (String type : types.get(Relation.class)) {
+      dump += type+"; ";
+    }
+    dump += "\n\t\tNOMSPROP : ";
+    for (String type : nomsProps.get(Relation.class).keySet()) {
+      dump += "\n\t\t\t"+type+" : ";
+      for (String prop : nomsProps.get(Relation.class).get(type)) {
+        dump += prop+"; ";
+      }
+    }
+    dump += "\n\t\tVALEURSPROP : ";
+    for (String type : valeursProps.get(Relation.class).keySet()) {
+      dump += "\n\t\t\t"+type+" : ";
+      for (String prop : valeursProps.get(Relation.class).get(type).keySet()) {
+        dump += "\n\t\t\t\t"+prop+" : ";
+        for (String val : valeursProps.get(Relation.class).get(type).get(prop)) {
+          dump += val+"; ";
+        }
+      }
+    }
+
+    dump += "\n\tSCHEMAS : ";
+    dump += "\n\t\tTYPES : ";
+    for (String type : types.get(Schema.class)) {
+      dump += type+"; ";
+    }
+    dump += "\n\t\tNOMSPROP : ";
+    for (String type : nomsProps.get(Schema.class).keySet()) {
+      dump += "\n\t\t\t"+type+" : ";
+      for (String prop : nomsProps.get(Schema.class).get(type)) {
+        dump += prop+"; ";
+      }
+    }
+    dump += "\n\t\tVALEURSPROP : ";
+    for (String type : valeursProps.get(Schema.class).keySet()) {
+      dump += "\n\t\t\t"+type+" : ";
+      for (String prop : valeursProps.get(Schema.class).get(type).keySet()) {
+        dump += "\n\t\t\t\t"+prop+" : ";
+        for (String val : valeursProps.get(Schema.class).get(type).get(prop)) {
+          dump += val+"; ";
+        }
+      }
+    }
+
+
+    return dump;
+  }
+
+  public HashSet<String> getNomsProps(Class<? extends Element> classe, String type) {
+    if (nomsProps.get(classe).containsKey(type)) {
+      return nomsProps.get(classe).get(type);
+    }
+    return new HashSet<String>();
+  }
+
+  public HashSet<String> getValeursProp(Class<? extends Element> classe, String type, String prop) {
+    if (valeursProps.get(classe).containsKey(type)&&valeursProps.get(classe).get(type).containsKey(prop)) {
+      return (valeursProps.get(classe).get(type).get(prop));
+    }
+    return new HashSet<String>();
+  }
+
+  public String getValeurParDefaut(Class<? extends Element> classe, String type, String prop) {
+    if (valeursParDefaut.get(classe).containsKey(type)&&valeursParDefaut.get(classe).get(type).containsKey(prop)) {
+      return (valeursParDefaut.get(classe).get(type).get(prop));
+    }
+    return "";
+  }
+
+  public HashSet<String> getTypes(Class<? extends Element> classe) {
+    return (types.get(classe));
+  }
+
+  public boolean isVide() {
+    for (Class classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      if (!types.get(classe).isEmpty()) return false;
+    }
+    return true;
+  }
+
+  void clear() {
+    for (Class classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      types.get(classe).clear();
+      nomsProps.get(classe).clear();
+      valeursProps.get(classe).clear();
+      valeursParDefaut.get(classe).clear();
+    }
+  }
+
+  public void ajouterVal(Class<? extends Element> classe, String type, String prop, String val) {
+    valeursProps.get(classe).get(type).get(prop).add(val);
+  }
+
+  void renommerVal(Class<? extends Element> classe, String type, String prop, String oldNom, String newNom) {
+    valeursProps.get(classe).get(type).get(prop).add(newNom);
+    valeursProps.get(classe).get(type).get(prop).remove(oldNom);
+    if (oldNom.equals(valeursParDefaut.get(classe).get(type).get(prop))) {
+      valeursParDefaut.get(classe).get(type).put(prop, newNom);
+    }
+  }
+
+  void supprimerVal(Class<? extends Element> classe, String type, String prop, String oldNom) {
+    valeursProps.get(classe).get(type).get(prop).remove(oldNom);
+    if (oldNom.equals(valeursParDefaut.get(classe).get(type).get(prop))) {
+      valeursParDefaut.get(classe).get(type).put(prop, "");
+    }
+  }
+
+  public void modifierValParDefaut(Class<? extends Element> classe, String type, String prop, String val) {
+    valeursParDefaut.get(classe).get(type).put(prop, val);
+  }
+
+  public void ajouterProp(Class<? extends Element> classe, String type, String prop) {
+    nomsProps.get(classe).get(type).add(prop);
+    valeursProps.get(classe).get(type).put(prop, new HashSet<String>());
+    valeursParDefaut.get(classe).get(type).put(prop, "");
+  }
+
+  void renommerProp(Class<? extends Element> classe, String type, String oldNom, String newNom) {
+    nomsProps.get(classe).get(type).add(newNom);
+    nomsProps.get(classe).get(type).remove(oldNom);
+    valeursProps.get(classe).get(type).put(newNom, valeursProps.get(classe).get(type).get(oldNom));
+    valeursProps.get(classe).get(type).remove(oldNom);
+    valeursParDefaut.get(classe).get(type).put(newNom, valeursParDefaut.get(classe).get(type).get(oldNom));
+    valeursParDefaut.get(classe).get(type).remove(oldNom);
+  }
+
+  void fusionnerProp(Class<? extends Element> classe, String type, String oldNom, String newNom) {
+    nomsProps.get(classe).get(type).remove(oldNom);
+    valeursProps.get(classe).get(type).get(newNom).addAll(valeursProps.get(classe).get(type).get(oldNom));
+    valeursProps.get(classe).get(type).remove(oldNom);
+    if (!valeursParDefaut.get(classe).get(type).get(oldNom).isEmpty()) {
+      valeursParDefaut.get(classe).get(type).put(newNom, valeursParDefaut.get(classe).get(type).get(oldNom));
+    }
+    valeursParDefaut.get(classe).get(type).remove(oldNom);
+  }
+
+  void supprimerProp(Class<? extends Element> classe, String type, String prop) {
+    nomsProps.get(classe).get(type).remove(prop);
+    valeursProps.get(classe).get(type).remove(prop);
+    valeursParDefaut.get(classe).get(type).remove(prop);
+  }
+
+  @SuppressWarnings("unchecked")
+  public void ajouterType(Class<? extends Element> classe, String type) {
+    types.get(classe).add(type);
+    nomsProps.get(classe).put(type, new HashSet<String>());
+    valeursProps.get(classe).put(type, new HashMap<String, HashSet<String>>());
+    valeursParDefaut.get(classe).put(type, new HashMap<String, String>());
+  }
+  // }
+
+  void renommerType(Class<? extends Element> classe, String oldType, String newType) {
+    types.get(classe).add(newType);
+    types.get(classe).remove(oldType);
+    nomsProps.get(classe).put(newType, nomsProps.get(classe).get(oldType));
+    nomsProps.get(classe).remove(oldType);
+    valeursProps.get(classe).put(newType, valeursProps.get(classe).get(oldType));
+    valeursProps.get(classe).remove(oldType);
+    valeursParDefaut.get(classe).put(newType, valeursParDefaut.get(classe).get(oldType));
+    valeursParDefaut.get(classe).remove(oldType);
+  }
+
+  void fusionnerType(Class<? extends Element> classe, String oldType, String newType) {
+    types.get(classe).remove(oldType);
+    for (String prop : nomsProps.get(classe).get(oldType)) {
+      if (!nomsProps.get(classe).get(newType).contains(prop))
+        ajouterProp(classe, newType, prop);
+      for (String val : valeursProps.get(classe).get(oldType).get(prop))
+        if (!valeursProps.get(classe).get(newType).get(prop).contains(val))
+          ajouterVal(classe, newType, prop, val);
+      String valdef1 = getValeurParDefaut(classe, oldType, prop);
+      String valdef = getValeurParDefaut(classe, newType, prop);
+      if (!valdef1.isEmpty()&&!valdef1.equals(valdef)) {
+        modifierValParDefaut(classe, newType, prop, valdef1);
+      }
+    }
+    nomsProps.get(classe).remove(oldType);
+    valeursProps.get(classe).remove(oldType);
+    valeursParDefaut.get(classe).remove(oldType);
+
+  }
+
+  void supprimerType(Class<? extends Element> classe, String type) {
+    types.get(classe).remove(type);
+    nomsProps.get(classe).remove(type);
+    valeursProps.get(classe).remove(type);
+    valeursParDefaut.get(classe).remove(type);
+  }
+
+  void majNewElement(Element element) { // appelé par corpus.addUniteLue, addRelationLue, addSchemaLu
+    String type = element.getType();
+    Class<? extends Element> classe = element.getClass();
+    if (!types.get(classe).contains(type)) {
+      ajouterType(classe, type);
+    }
+    HashMap<String, String> props = element.getProps();
+    for (String prop : props.keySet()) {
+      if (!nomsProps.get(classe).get(type).contains(prop)) {
+        ajouterProp(classe, type, prop);
+      }
+      String val = props.get(prop);
+      if (val!=null&&!val.isEmpty()&&!valeursProps.get(classe).get(type).get(prop).contains(val)) {
+        ajouterVal(classe, type, prop, val);
+      }
+    }
+  }
+
+ @SuppressWarnings("unchecked")
+   public static Structure lireJava(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+    Structure structure = new Structure();
+    structure.types = (HashMap<Class<? extends Element>, HashSet<String>>) ois.readObject();
+    structure.nomsProps = (HashMap<Class<? extends Element>, HashMap<String, HashSet<String>>>) ois.readObject();
+    structure.valeursProps = (HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashSet<String>>>>) ois.readObject();
+    structure.valeursParDefaut = (HashMap<Class<? extends Element>, HashMap<String, HashMap<String, String>>>) ois.readObject();
+    return structure;
+  }
+
+  public void ecrireJava(ObjectOutputStream oos) throws IOException {
+    oos.writeObject(types);
+    oos.writeObject(nomsProps);
+    oos.writeObject(valeursProps);
+    oos.writeObject(valeursParDefaut);
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/donnees/Structure.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/donnees/VisuStructure.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/donnees/VisuStructure.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/donnees/VisuStructure.java	(revision 3653)
@@ -0,0 +1,682 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.donnees;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.tree.*;
+import visuAnalec.*;
+import visuAnalec.Message.*;
+import visuAnalec.donnees.Corpus.*;
+import visuAnalec.vue.Vue.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.GMessages;
+import visuAnalec.util.GMessages.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class VisuStructure extends JFrame implements CorpusListener {
+	static private VisuStructure instance = null;
+	private Corpus corpus;
+	private Structure structure;
+	private JScrollPane panneauUnites, panneauRelations, panneauSchemas;
+	private HashMap<Class<? extends Element>, ModeleArbreProp> donneesClasse =
+			new HashMap<Class<? extends Element>, ModeleArbreProp>();
+	static public VisuStructure newVisuStructure(Container fenetre, Corpus corpus) {
+		if (instance==null) instance = new VisuStructure(fenetre, corpus);
+		return instance;
+	}
+	static public boolean isOpen() {
+		return instance != null && instance.isVisible();
+	}
+	
+	private VisuStructure(Container fenetre, Corpus corps) {
+		super("Structure des annotations");
+		if (fenetre != null) {
+			Point locFenetre = new Point(fenetre.getX()+20, fenetre.getY()+50);
+			Dimension dimFenetre = new Dimension(fenetre.getWidth(), fenetre.getHeight()-30);
+			setLocation(locFenetre);
+			setSize(dimFenetre);
+		}
+		this.corpus = corps;
+		this.structure = corps.getStructure();
+		corps.addEventListener(this);
+		// Panneau des types d'unités
+		ModeleArbreProp donneesPropUnites = new ModeleArbreProp(structure, Unite.class);
+		JTree arbrePropUnites = new JTree(donneesPropUnites);
+		donneesClasse.put(Unite.class, donneesPropUnites);
+		arbrePropUnites.setRootVisible(true);
+		arbrePropUnites.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+		panneauUnites = new JScrollPane(arbrePropUnites);
+		panneauUnites.setBorder(new TitledBorder("Unités"));
+		// Panneau des types de relations
+		ModeleArbreProp donneesPropRelations = new ModeleArbreProp(structure, Relation.class);
+		JTree arbrePropRelations = new JTree(donneesPropRelations);
+		donneesClasse.put(Relation.class, donneesPropRelations);
+		arbrePropRelations.setRootVisible(true);
+		arbrePropRelations.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+		panneauRelations = new JScrollPane(arbrePropRelations);
+		panneauRelations.setBorder(new TitledBorder("Relations"));
+		// Panneau des types de schémas
+		ModeleArbreProp donneesPropSchemas = new ModeleArbreProp(structure, Schema.class);
+		JTree arbrePropSchemas = new JTree(donneesPropSchemas);
+		donneesClasse.put(Schema.class, donneesPropSchemas);
+		arbrePropSchemas.setRootVisible(true);
+		arbrePropSchemas.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+		panneauSchemas = new JScrollPane(arbrePropSchemas);
+		panneauSchemas.setBorder(new TitledBorder("Schémas"));
+
+		// cadre global de la fenêtre
+		JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, panneauUnites,
+				new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+						panneauRelations, panneauSchemas));
+		getContentPane().add(split);
+
+		// Gestion des menus contextuels
+		final JPopupMenuStructure popupMenuStructure = new JPopupMenuStructure();
+
+		MouseListener popupListener = new MouseAdapter() {
+			@Override
+			public void mousePressed(MouseEvent e) {
+				try {
+					if (e.isPopupTrigger()) showPopup(e);
+					else if (e.getClickCount()==2) {
+						JTree arbre = (JTree) e.getComponent();
+						TreePath item = arbre.getPathForLocation(e.getX(), e.getY());
+						if (item==null) return;
+						if (item.getPathCount()!=4) return;
+						ModeleArbreProp donnees = (ModeleArbreProp) arbre.getModel();
+						Class<? extends Element> classe = donnees.classe;
+						DefaultMutableTreeNode noeudType = (DefaultMutableTreeNode) item.getPathComponent(1);
+						DefaultMutableTreeNode noeudProp = (DefaultMutableTreeNode) item.getPathComponent(2);
+						DefaultMutableTreeNode noeudVal = (DefaultMutableTreeNode) item.getPathComponent(3);
+						String type = (String) noeudType.getUserObject();
+						String prop = (String) noeudProp.getUserObject();
+						String val = (String) noeudVal.getUserObject();
+						if (isDefaut(val)) {
+							corpus.modifierValParDefaut(classe, type, prop, "");
+							//             noeudVal.setUserObject(oteDefaut(val));
+						} else {
+							corpus.modifierValParDefaut(classe, type, prop, val);
+							//              for (Enumeration noeuds = noeudProp.children(); noeuds.hasMoreElements();) {
+							//                DefaultMutableTreeNode noeud1 = (DefaultMutableTreeNode) noeuds.nextElement();
+							//                String val1 = (String) noeud1.getUserObject();
+							//                if (isDefaut(val1)) {
+							//                  noeud1.setUserObject(oteDefaut(val1));
+							//                  donnees.nodeChanged(noeudVal);
+							//                  break;
+							//                }
+							//              }
+							////              noeudVal.setUserObject(placeDefaut(val));
+							//             corpus.newValeurDefaut(classe, type, prop, val);
+						}
+						//          donnees.nodeChanged(noeudVal);
+
+					}
+				} catch (Throwable ex) {
+					GMessages.erreurFatale(ex);
+				}
+			}
+			@Override
+			public void mouseReleased(MouseEvent e) {
+				try {
+					if (e.isPopupTrigger()) showPopup(e);
+				} catch (Throwable ex) {
+					GMessages.erreurFatale(ex);
+				}
+			}
+			private void showPopup(MouseEvent e) {
+				JTree arbre = (JTree) e.getComponent();
+				TreePath item = arbre.getPathForLocation(e.getX(), e.getY());
+				if (item==null) return;
+				popupMenuStructure.init(arbre, item);
+				popupMenuStructure.show(e.getComponent(), e.getX(), e.getY());
+			}
+		};
+
+		arbrePropUnites.addMouseListener(popupListener);
+		arbrePropRelations.addMouseListener(popupListener);
+		arbrePropSchemas.addMouseListener(popupListener);
+		// Fermeture de la fenêtre
+		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+		addWindowListener(new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent evt) {
+				fermerFenetre();
+			}
+		});
+
+	}
+	public void agencer() {
+		((JSplitPane) panneauUnites.getParent()).setDividerLocation(1./3);
+		((JSplitPane) panneauRelations.getParent()).setDividerLocation(1./3);
+	}
+	private void fermerFenetre() {
+		corpus.removeEventListener(this);
+		dispose();
+		instance = null;
+	}
+	public void traiterEvent(Message evt) {
+		switch (evt.getType()) {
+		case CLEAR_CORPUS:
+			fermerFenetre();
+			return;
+		case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+			throw new UnsupportedOperationException("Fenêtre stat présente lors d'un message NEW_CORPUS ???");
+		case MODIF_STRUCTURE:
+			StructureEvent evtS = (StructureEvent) evt;
+			ModeleArbreProp donnees = donneesClasse.get(evtS.getClasse());
+			switch (evtS.getModif()) { // pour les modifs ayant lieu en dehors de VisuStructure 
+			case AJOUT_TYPE:
+				donnees.insererNewType(evtS.getArg(0));
+				return;
+			case AJOUT_PROP:
+				donnees.insererNewProp(evtS.getArg(0), evtS.getArg(1));
+				return;
+			case AJOUT_VALEUR:
+				donnees.insererNewValeur(evtS.getArg(0), evtS.getArg(1), evtS.getArg(2));
+				return;
+			case VALEUR_PAR_DEFAUT:
+				donnees.modifierValDefaut(evtS.getArg(0), evtS.getArg(1), evtS.getArg(2));
+				return;
+			default:
+				return;
+			}
+		case MODIF_ELEMENT:
+		case MODIF_TEXTE:
+			return;
+		default:
+			throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+		}
+	}
+	static boolean isDefaut(String val) {
+		return val.startsWith("=>");
+	}
+	static String placeDefaut(String val) {
+		return isDefaut(val) ? val : "=>"+val;
+	}
+	static String oteDefaut(String val) {
+		return isDefaut(val) ? val.substring(2) : val;
+	}
+
+	private class JPopupMenuStructure extends JPopupMenu {
+		void init(JTree arbre, TreePath item) {
+			ModeleArbreProp donnees = (ModeleArbreProp) arbre.getModel();
+			removeAll();
+			int niveau = item.getPathCount();
+			if (niveau<4) {
+				add(new ActionAjouter(donnees.classe, arbre, donnees, item));
+			}
+			if (niveau>1) {
+				if (niveau!=3||!donnees.classe.equals(Unite.class)||!Structure.FORME.equals(
+						((DefaultMutableTreeNode) item.getLastPathComponent()).getUserObject()))
+					add(new ActionRenommer(donnees.classe, donnees, item));
+				add(new ActionSupprimer(donnees.classe, donnees, item));
+			}
+			if (niveau==2&&donnees.classe.equals(Unite.class)
+					&&!donnees.hasForme((DefaultMutableTreeNode) item.getLastPathComponent()))
+				add(new ActionAjouterForme(arbre, donnees, item));
+			if (niveau==3)
+				add(new ActionDispatcher(donnees.classe, arbre, donnees, item));
+		}
+	}
+	static String[] commandesAjout = new String[]{
+		"Ajouter un type",
+		"Ajouter une propriété",
+		"Ajouter une valeur"
+	};
+
+	private class ActionAjouter extends GAction {
+		TreePath item;
+		Class<? extends Element> classe;
+		JTree arbre;
+		ModeleArbreProp donnees;
+		ActionAjouter(Class<? extends Element> classe, JTree arbre, ModeleArbreProp donnees, TreePath item) {
+			super(commandesAjout[item.getPathCount()-1]);
+			this.item = item;
+			this.classe = classe;
+			this.donnees = donnees;
+			this.arbre = arbre;
+		}
+		public void executer() {
+			corpus.removeEventListener(VisuStructure.this);
+			DefaultMutableTreeNode noeud, noeud1, noeud2;
+			noeud = (DefaultMutableTreeNode) item.getLastPathComponent();
+			switch (item.getPathCount()) {
+			case 1: // racine : ajout d'un type
+			String newType =
+			corpus.saisirAjouterType(VisuStructure.this, classe);
+			if (newType!=null) {
+				noeud1 = new DefaultMutableTreeNode(newType, true);
+				donnees.insertNodeInto(noeud1, noeud, 0);
+				arbre.makeVisible(item.pathByAddingChild(noeud1));
+			}
+			break;
+			case 2: // type : ajout d'une prop
+				String newProp =
+				corpus.saisirAjouterProp(VisuStructure.this, classe,
+						(String) noeud.getUserObject());
+				if (newProp!=null) {
+					noeud1 = new DefaultMutableTreeNode(newProp, true);
+					donnees.insertNodeInto(noeud1, noeud, 0);
+					arbre.makeVisible(item.pathByAddingChild(noeud1));
+				}
+				break;
+			case 3: // prop : ajout d'une valeur
+				noeud1 = (DefaultMutableTreeNode) item.getPathComponent(1);
+				String newVal = corpus.saisirAjouterVal(VisuStructure.this, classe,
+						(String) noeud1.getUserObject(), (String) noeud.getUserObject());
+				if (newVal!=null) {
+					noeud2 = new DefaultMutableTreeNode(newVal, false);
+					donnees.insertNodeInto(noeud2, noeud, 0);
+					arbre.makeVisible(item.pathByAddingChild(noeud1));
+				}
+				break;
+			default:
+				throw new UnsupportedOperationException("Cas d'ajout non prévu ");
+			}
+			corpus.addEventListener(VisuStructure.this);
+		}
+	}
+	static String[] commandesRenom = new String[]{
+		"Renommer le type",
+		"Renommer la propriété",
+		"Renommer la valeur"
+	};
+
+	private class ActionRenommer extends GAction {
+		TreePath item;
+		Class<? extends Element> classe;
+		ModeleArbreProp donnees;
+		ActionRenommer(Class<? extends Element> classe, ModeleArbreProp donnees, TreePath item) {
+			super(commandesRenom[item.getPathCount()-2]);
+			this.item = item;
+			this.classe = classe;
+			this.donnees = donnees;
+		}
+		@SuppressWarnings("unchecked")
+		public void executer() {
+			corpus.removeEventListener(VisuStructure.this);
+			DefaultMutableTreeNode noeud, noeud0, noeud1, noeud2;
+			noeud = (DefaultMutableTreeNode) item.getLastPathComponent();
+			switch (item.getPathCount()) {
+			case 2: // type
+				String newType = corpus.saisirRenommerType(VisuStructure.this, classe,
+						(String) noeud.getUserObject());
+				if (newType!=null) {
+					DefaultMutableTreeNode ntypefusion = null;
+					noeud0 = (DefaultMutableTreeNode) item.getPathComponent(0);
+					for (Enumeration<DefaultMutableTreeNode> etype = noeud0.children(); etype.hasMoreElements();) {
+						DefaultMutableTreeNode ntype = etype.nextElement();
+						String type0 = (String) ntype.getUserObject();
+						if (newType.equals(type0)) {
+							ntypefusion = ntype;
+							break;
+						}
+					}
+					if (ntypefusion!=null)
+						donnees.fusionnerType(noeud, ntypefusion);
+					else {
+						noeud.setUserObject(newType);
+						donnees.nodeChanged(noeud);
+					}
+				}
+				break;
+			case 3: // prop
+				noeud1 = (DefaultMutableTreeNode) item.getPathComponent(1);
+				String newProp = corpus.saisirRenommerProp(VisuStructure.this, classe,
+						(String) noeud1.getUserObject(), (String) noeud.getUserObject());
+				if (newProp!=null) {
+					DefaultMutableTreeNode npropfusion = null;
+					for (Enumeration<DefaultMutableTreeNode> eprop = noeud1.children(); eprop.hasMoreElements();) {
+						DefaultMutableTreeNode nprop = eprop.nextElement();
+						String prop0 = (String) nprop.getUserObject();
+						if (newProp.equals(prop0)) {
+							npropfusion = nprop;
+							break;
+						}
+					}
+					if (npropfusion!=null)
+						donnees.fusionnerProp(noeud1, noeud, npropfusion);
+					else {
+						noeud.setUserObject(newProp);
+						donnees.nodeChanged(noeud);
+					}
+				}
+				break;
+			case 4: // val
+				noeud1 = (DefaultMutableTreeNode) item.getPathComponent(1);
+				noeud2 = (DefaultMutableTreeNode) item.getPathComponent(2);
+				String val = (String) noeud.getUserObject();
+				boolean isDefaut = isDefaut(val);
+				if (isDefaut) val = oteDefaut(val);
+				String newVal = corpus.saisirRenommerVal(VisuStructure.this, classe,
+						(String) noeud1.getUserObject(), (String) noeud2.getUserObject(), val);
+				if (newVal!=null) {
+					for (Enumeration<DefaultMutableTreeNode> eval = noeud2.children(); eval.hasMoreElements();) {
+						DefaultMutableTreeNode nval = eval.nextElement();
+						String val0 = (String) nval.getUserObject();
+						if (newVal.equals(isDefaut(val0) ? oteDefaut(val0) : val0)) {
+							isDefaut = isDefaut||isDefaut(val0);
+							donnees.removeNodeFromParent(nval);
+							break;
+						}
+					}
+					if (isDefaut) newVal = placeDefaut(newVal);
+					noeud.setUserObject(newVal);
+					donnees.nodeChanged(noeud);
+				}
+				break;
+			default:
+				throw new UnsupportedOperationException("Cas de renommage non prévu ");
+			}
+			corpus.addEventListener(VisuStructure.this);
+		}
+	}
+	static String[] commandesSuppr = new String[]{
+		"Supprimer le type",
+		"Supprimer la propriété",
+		"Supprimer la valeur"
+	};
+
+	private class ActionSupprimer extends GAction {
+		TreePath item;
+		Class<? extends Element> classe;
+		ModeleArbreProp donnees;
+		ActionSupprimer(Class<? extends Element> classe, ModeleArbreProp donnees, TreePath item) {
+			super(commandesSuppr[item.getPathCount()-2]);
+			this.item = item;
+			this.classe = classe;
+			this.donnees = donnees;
+		}
+		@SuppressWarnings("unchecked")
+		public void executer() {
+			corpus.removeEventListener(VisuStructure.this);
+			DefaultMutableTreeNode noeud, noeud1, noeud2;
+			noeud = (DefaultMutableTreeNode) item.getLastPathComponent();
+			switch (item.getPathCount()) {
+			case 1: // racine
+				return;
+			case 2: // type
+				if (corpus.saisirSupprimerType(VisuStructure.this, classe,
+						(String) noeud.getUserObject())) {
+					donnees.removeNodeFromParent(noeud);
+				}
+				break;
+			case 3: // prop
+				noeud1 = (DefaultMutableTreeNode) item.getPathComponent(1);
+				if (corpus.saisirSupprimerProp(VisuStructure.this, classe,
+						(String) noeud1.getUserObject(), (String) noeud.getUserObject())) {
+					donnees.removeNodeFromParent(noeud);
+				}
+				;
+				break;
+			case 4: // val
+				noeud1 = (DefaultMutableTreeNode) item.getPathComponent(1);
+				noeud2 = (DefaultMutableTreeNode) item.getPathComponent(2);
+				String val = (String) noeud.getUserObject();
+				if (isDefaut(val)) val = oteDefaut(val);
+				if (corpus.saisirSupprimerVal(VisuStructure.this, classe,
+						(String) noeud1.getUserObject(), (String) noeud2.getUserObject(), val)) {
+					donnees.removeNodeFromParent(noeud);
+				}
+				break;
+			default:
+				throw new UnsupportedOperationException("Cas de suppression non prévu ");
+			}
+			corpus.addEventListener(VisuStructure.this);
+		}
+	}
+
+	private class ActionAjouterForme extends GAction {
+		TreePath item;
+		Class<? extends Element> classe;
+		JTree arbre;
+		ModeleArbreProp donnees;
+		ActionAjouterForme(JTree arbre, ModeleArbreProp donnees, TreePath item) {
+			super("Ajouter la forme de surface");
+			this.item = item;
+			this.donnees = donnees;
+			this.arbre = arbre;
+		}
+		@SuppressWarnings("unchecked")
+		public void executer() {
+			corpus.removeEventListener(VisuStructure.this);
+			DefaultMutableTreeNode noeud, noeud1;
+			noeud = (DefaultMutableTreeNode) item.getLastPathComponent();
+			String type = (String) noeud.getUserObject();
+			corpus.ajouterFormeUnite(type);
+			noeud1 = new DefaultMutableTreeNode(Structure.FORME, true);
+			donnees.insertNodeInto(noeud1, noeud, 0);
+			arbre.makeVisible(item.pathByAddingChild(noeud1));
+			corpus.addEventListener(VisuStructure.this);
+			corpus.instancierFormeUnite(type);
+
+		}
+	}
+
+	private class ActionDispatcher extends GAction {
+		TreePath item;
+		Class<? extends Element> classe;
+		JTree arbre;
+		ModeleArbreProp donnees;
+		ActionDispatcher(Class<? extends Element> classe, JTree arbre,
+				ModeleArbreProp donnees, TreePath item) {
+			super("Transformer en types distincts");
+			this.item = item;
+			this.classe = classe;
+			this.donnees = donnees;
+			this.arbre = arbre;
+		}
+		@SuppressWarnings("unchecked")
+		public void executer() {
+			corpus.removeEventListener(VisuStructure.this);
+			DefaultMutableTreeNode noeudprop = (DefaultMutableTreeNode) item.getLastPathComponent();
+			int nbval = noeudprop.getChildCount();
+			String[] vals = new String[nbval];
+			Enumeration<DefaultMutableTreeNode> eval = noeudprop.children();
+			for (int i = 0; i<nbval; i++)
+				vals[i] = (String) eval.nextElement().getUserObject();
+			DefaultMutableTreeNode noeudtype = (DefaultMutableTreeNode) item.getPathComponent(1);
+			int nbprop = noeudtype.getChildCount();
+			String[] props = new String[nbprop-1];
+			String[][] propsvals = new String[nbprop-1][];
+			Enumeration<DefaultMutableTreeNode> eprop = noeudtype.children();
+			for (int i = 0; eprop.hasMoreElements(); i++) {
+				DefaultMutableTreeNode nprop = eprop.nextElement();
+				if (nprop!=noeudprop) {
+					props[i] = (String) nprop.getUserObject();
+					propsvals[i] = new String[nprop.getChildCount()];
+					Enumeration<DefaultMutableTreeNode> epropval = nprop.children();
+					for (int j = 0; epropval.hasMoreElements(); j++)
+						propsvals[i][j] = (String) epropval.nextElement().getUserObject();
+				} else i--;
+			}
+			if (corpus.saisirDispatcherProp(VisuStructure.this, classe,
+					(String) noeudtype.getUserObject(),
+					(String) noeudprop.getUserObject(), vals, props, propsvals))
+				donnees.dispatcherProp(noeudtype, noeudprop, vals, props, propsvals);
+			corpus.addEventListener(VisuStructure.this);
+		}
+	}
+
+	private static class ModeleArbreProp extends DefaultTreeModel {
+		Structure structure;
+		Class<? extends Element> classe;
+		ModeleArbreProp(Structure structure, Class<? extends Element> classe) {
+			super(null, true);
+			this.structure = structure;
+			this.classe = classe;
+			setModele();
+		}
+		private void setModele() {
+			DefaultMutableTreeNode racine = new DefaultMutableTreeNode("TYPES :", true);
+			setRoot(racine);
+			String[] types = structure.getTypes(classe).toArray(new String[0]);
+			Arrays.sort(types);
+			for (String type : types) {
+				DefaultMutableTreeNode ntype =
+						new DefaultMutableTreeNode(type, true);
+				racine.add(ntype);
+				String[] props =
+						structure.getNomsProps(classe, type).toArray(new String[0]);
+				Arrays.sort(props);
+				for (String prop : props) {
+					DefaultMutableTreeNode nprop =
+							new DefaultMutableTreeNode(prop, true);
+					ntype.add(nprop);
+					String[] vals =
+							structure.getValeursProp(classe, type, prop).toArray(new String[0]);
+					Arrays.sort(vals);
+					for (String val : vals) {
+						if (val.equals(structure.getValeurParDefaut(classe, type, prop)))
+							val = placeDefaut(val);
+						DefaultMutableTreeNode nval =
+								new DefaultMutableTreeNode(val, false);
+						nprop.add(nval);
+					}
+				}
+			}
+			reload();
+		}
+		@SuppressWarnings("unchecked")
+		void insererNewType(String type) {
+			DefaultMutableTreeNode racine = (DefaultMutableTreeNode) getRoot();
+			insertNodeInto(new DefaultMutableTreeNode(type, true), racine, 0);
+		}
+		@SuppressWarnings("unchecked")
+		void insererNewProp(String type, String prop) {
+			DefaultMutableTreeNode racine = (DefaultMutableTreeNode) getRoot();
+			DefaultMutableTreeNode ntype = null;
+			for (Enumeration<DefaultMutableTreeNode> etype = racine.children();
+					etype.hasMoreElements();) {
+				ntype = etype.nextElement();
+				if (type.equals(ntype.getUserObject())) break;
+			}
+			insertNodeInto(new DefaultMutableTreeNode(prop, true), ntype, 0);
+		}
+		@SuppressWarnings("unchecked")
+		void insererNewValeur(String type, String prop, String valeur) {
+			DefaultMutableTreeNode racine = (DefaultMutableTreeNode) getRoot();
+			DefaultMutableTreeNode ntype = null;
+			DefaultMutableTreeNode nprop = null;
+			for (Enumeration<DefaultMutableTreeNode> etype = racine.children();
+					etype.hasMoreElements();) {
+				ntype = etype.nextElement();
+				if (type.equals(ntype.getUserObject())) {
+					for (Enumeration<DefaultMutableTreeNode> eprop = ntype.children(); eprop.hasMoreElements();) {
+						nprop = eprop.nextElement();
+						if (prop.equals(nprop.getUserObject())) break;
+					}
+					break;
+				}
+			}
+			insertNodeInto(new DefaultMutableTreeNode(valeur, false), nprop, 0);
+		}
+		@SuppressWarnings("unchecked")
+		void modifierValDefaut(String type, String prop, String valeur) {
+			DefaultMutableTreeNode racine = (DefaultMutableTreeNode) getRoot();
+			DefaultMutableTreeNode ntype = null;
+			DefaultMutableTreeNode nprop = null;
+			DefaultMutableTreeNode nval = null;
+			for (Enumeration<DefaultMutableTreeNode> etype = racine.children(); etype.hasMoreElements();) {
+				ntype = etype.nextElement();
+				if (type.equals(ntype.getUserObject())) {
+					for (Enumeration<DefaultMutableTreeNode> eprop = ntype.children(); eprop.hasMoreElements();) {
+						nprop = eprop.nextElement();
+						if (prop.equals(nprop.getUserObject())) break;
+					}
+					break;
+				}
+			}
+			for (Enumeration<DefaultMutableTreeNode> eval = nprop.children(); eval.hasMoreElements();) {
+				nval = eval.nextElement();
+				String val = (String) nval.getUserObject();
+				if (isDefaut(val)) {
+					nval.setUserObject(oteDefaut(val));
+					nodeChanged(nval);
+				}
+				if (val.equals(valeur)) {
+					nval.setUserObject(placeDefaut(val));
+					nodeChanged(nval);
+				}
+
+			}
+		}
+		void fusionnerType(DefaultMutableTreeNode noeudafusionner,
+				DefaultMutableTreeNode noeudagarder) {
+			removeNodeFromParent(noeudafusionner);
+			noeudagarder.removeAllChildren();
+			String type = (String) noeudagarder.getUserObject();
+			String[] props = structure.getNomsProps(classe, type).toArray(new String[0]);
+			Arrays.sort(props);
+			for (String prop : props) {
+				DefaultMutableTreeNode nprop = new DefaultMutableTreeNode(prop, true);
+				noeudagarder.add(nprop);
+				String[] vals = structure.getValeursProp(classe, type, prop).toArray(new String[0]);
+				Arrays.sort(vals);
+				for (String val : vals) {
+					if (val.equals(structure.getValeurParDefaut(classe, type, prop)))
+						val = placeDefaut(val);
+					DefaultMutableTreeNode nval = new DefaultMutableTreeNode(val, false);
+					nprop.add(nval);
+				}
+			}
+			nodeStructureChanged(noeudagarder);
+		}
+		void fusionnerProp(DefaultMutableTreeNode noeudtype, DefaultMutableTreeNode noeudafusionner,
+				DefaultMutableTreeNode noeudagarder) {
+			removeNodeFromParent(noeudafusionner);
+			noeudagarder.removeAllChildren();
+			String type = (String) noeudtype.getUserObject();
+			String prop = (String) noeudagarder.getUserObject();
+			String[] vals = structure.getValeursProp(classe, type, prop).toArray(new String[0]);
+			Arrays.sort(vals);
+			for (String val : vals) {
+				if (val.equals(structure.getValeurParDefaut(classe, type, prop)))
+					val = placeDefaut(val);
+				DefaultMutableTreeNode nval = new DefaultMutableTreeNode(val, false);
+				noeudagarder.add(nval);
+			}
+			nodeStructureChanged(noeudagarder);
+		}
+		void dispatcherProp(DefaultMutableTreeNode noeudtype,
+				DefaultMutableTreeNode noeudprop, String[] newtypes, String[] props,
+				String[][] propsvals) {
+			removeNodeFromParent(noeudtype);
+			removeNodeFromParent(noeudprop);
+			DefaultMutableTreeNode racine = (DefaultMutableTreeNode) getRoot();
+			DefaultMutableTreeNode ntype = null;
+			DefaultMutableTreeNode nprop = null;
+			for (String type : newtypes) {
+				insertNodeInto(ntype = new DefaultMutableTreeNode(type, true), racine, 0);
+				for (int i = 0; i<props.length; i++) {
+					insertNodeInto(nprop = new DefaultMutableTreeNode(props[i], true),
+							ntype, i);
+					for (int j = 0; j<propsvals[i].length; j++)
+						insertNodeInto(new DefaultMutableTreeNode(oteDefaut(propsvals[i][j]),
+								false), nprop, j);
+
+				}
+
+			}
+		}
+		@SuppressWarnings("unchecked")
+		boolean hasForme(DefaultMutableTreeNode noeudtype) {
+			for (Enumeration<DefaultMutableTreeNode> eprop = noeudtype.children();
+					eprop.hasMoreElements();) {
+				DefaultMutableTreeNode nprop = eprop.nextElement();
+				if (Structure.FORME.equals(nprop.getUserObject())) return true;
+			}
+
+			return false;
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/donnees/VisuStructure.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Element.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Element.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Element.java	(revision 3653)
@@ -0,0 +1,193 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.elements;
+
+import java.io.Serializable;
+import java.util.*;
+import java.util.ArrayList;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public abstract class Element implements Serializable, Comparable {
+  private String type;
+  private HashMap<String, String> props = new HashMap<String, String>();
+  private HashMap<String, ArrayList<Relation>> relationsEntrantes = new HashMap<String, ArrayList<Relation>>();
+  private HashMap<String, ArrayList<Relation>> relationsSortantes = new HashMap<String, ArrayList<Relation>>();
+  private HashMap<String, ArrayList<Schema>> schemasContenants = new HashMap<String, ArrayList<Schema>>();
+  Element() {
+  }
+  Element(String type) {
+    this.type = type;
+  }
+  @Override
+  public String toString() {
+    String dump = "ELEMENT "+type;
+    dump += "\n\tPROPS : ";
+    for (String prop : props.keySet()) {
+      dump += "\n\t\t"+prop+" : "+props.get(prop);
+    }
+    dump += "\n\tRELATIONS ENTRANTES : ";
+    for (String typ : relationsEntrantes.keySet()) {
+      dump += "\n\t\t"+typ+" : ";
+      for (Relation rel : relationsEntrantes.get(typ)) {
+        dump += rel.getElt1().getType();
+      }
+    }
+    dump += "\n\tRELATIONS SORTANTES : ";
+    for (String typ : relationsSortantes.keySet()) {
+      dump += "\n\t\t"+typ+" : ";
+      for (Relation rel : relationsSortantes.get(typ)) {
+        dump += rel.getElt2().getType();
+      }
+    }
+    return dump;
+  }
+  public String getType() {
+    return type;
+  }
+  public void setType(String type) {
+    this.type = type;
+  }
+  public HashMap<String, String> getProps() {
+    return props;
+  }
+  public String getProp(String prop) {
+    if (props.get(prop)==null) {
+      return "";
+    }
+    return props.get(prop);
+  }
+  public void putProp(String prop, String valeur) {
+    props.put(prop, valeur);
+  }
+  public void supProp(String prop) {
+    props.remove(prop);
+  }
+  public void addRelationEntrante(Relation rel) {
+    if (!relationsEntrantes.containsKey(rel.getType())) {
+      relationsEntrantes.put(rel.getType(), new ArrayList<Relation>());
+    }
+    relationsEntrantes.get(rel.getType()).add(rel);
+  }
+  public void oteRelationEntrante(Relation rel) {
+    relationsEntrantes.get(rel.getType()).remove(rel);
+  }
+  public void addRelationSortante(Relation rel) {
+    if (!relationsSortantes.containsKey(rel.getType())) {
+      relationsSortantes.put(rel.getType(), new ArrayList<Relation>());
+    }
+    relationsSortantes.get(rel.getType()).add(rel);
+  }
+  public void oteRelationSortante(Relation rel) {
+    relationsSortantes.get(rel.getType()).remove(rel);
+  }
+  public void addSchemaContenant(Schema sch) {
+    if (!schemasContenants.containsKey(sch.getType())) {
+      schemasContenants.put(sch.getType(), new ArrayList<Schema>());
+    }
+    schemasContenants.get(sch.getType()).add(sch);
+  }
+  public void oteSchemaContenant(Schema sch) {
+    schemasContenants.get(sch.getType()).remove(sch);
+  }
+  public ArrayList<Relation> getRelations() {
+    ArrayList<Relation> rels = new ArrayList<Relation>();
+    for (String typerel : relationsEntrantes.keySet()) {
+      rels.addAll(relationsEntrantes.get(typerel));
+    }
+    for (String typerel : relationsSortantes.keySet()) {
+      rels.addAll(relationsSortantes.get(typerel));
+    }
+    return rels;
+  }
+  public ArrayList<Schema> getSchemas() {
+    ArrayList<Schema> schs = new ArrayList<Schema>();
+    for (String typesch : schemasContenants.keySet()) {
+      schs.addAll(schemasContenants.get(typesch));
+    }
+    return schs;
+  }
+  public Element getElementSuivant(Jalon jalon) {
+    switch (jalon.origine) {
+      case ELT_0:
+        return this;
+      case REL_SORTANTE:
+        if (!relationsSortantes.containsKey(jalon.type)||relationsSortantes.get(jalon.type).isEmpty()) {
+          return null;
+        }
+        return relationsSortantes.get(jalon.type).get(0);
+      case REL_ENTRANTE:
+        if (!relationsEntrantes.containsKey(jalon.type)||relationsEntrantes.get(jalon.type).isEmpty()) {
+          return null;
+        }
+        return relationsEntrantes.get(jalon.type).get(0);
+      case SCH_CONTENANT:
+        if (!schemasContenants.containsKey(jalon.type)||schemasContenants.get(jalon.type).isEmpty()) {
+          return null;
+        }
+        return schemasContenants.get(jalon.type).get(0);
+      default:  // les cas ELT_1 et ELT_2 sont traités par la classe Relation
+        throw new UnsupportedOperationException("Pas encore implémenté");
+    }
+  }
+  protected abstract HashSet<Unite> getUnitesSousjacentesNonTriees();
+  public Unite[] getUnitesSousjacentes() { // triées
+    Unite[] units = getUnitesSousjacentesNonTriees().toArray(new Unite[0]);
+    Arrays.sort(units);
+    return units;
+  }
+  public Unite getUnite0() {
+    Unite[] units = getUnitesSousjacentes();
+    if (units.length==0) return null;
+    return units[0];
+  }
+  public static Unite[] getUnites0(Element[] elts) {
+    Unite[] units = new Unite[elts.length];
+    for (int i = 0; i<elts.length; i++) units[i] = elts[i].getUnite0();
+    return units;
+  }
+  public static Unite[] getUnitesSousjacentes(Element[] elts) { // triées : est-ce nécessaire ??
+    ArrayList<Unite> lunits = new ArrayList<Unite>();
+    for (Element elt : elts)
+      lunits.addAll(elt.getUnitesSousjacentesNonTriees());
+    Unite[] units = lunits.toArray(new Unite[0]);
+    Arrays.sort(units);
+    return units;
+  }
+  public static Element trouverElementParUniteSousjacente(Element[] elements, Unite unite) { // prend le premier
+    for (Element elt : elements) {
+      int i = Arrays.binarySearch(elt.getUnitesSousjacentes(), unite);
+      if (i>=0) return elt;
+    }
+    return null;
+  }
+  public static ArrayList<Element> trouverElementsParUniteSousjacente(Element[] elements, Unite unite) {
+    ArrayList<Element> elts = new ArrayList<Element>();
+    for (Element elt : elements) {
+      int i = Arrays.binarySearch(elt.getUnitesSousjacentes(), unite);
+      if (i>=0) elts.add(elt);
+    }
+    return elts;
+  }
+  public int compareTo(Object obj) {
+    if (obj.getClass().getSuperclass()!=Element.class) {
+      throw new ClassCastException("Comparaison impossible : "+obj.toString()+" n'est pas une instance d'Elément");
+    }
+    Unite[] unites1 = getUnitesSousjacentes();
+    Unite[] unites2 = ((Element) obj).getUnitesSousjacentes();
+    int comp;
+    for (int i = 0; i<unites1.length; i++) {
+      if (i==unites2.length) return 1;
+      if ((comp = unites1[i].compareTo(unites2[i]))!=0) return comp;
+    }
+    if (unites1.length<unites2.length) return -1;
+    return Integer.signum(hashCode()-obj.hashCode());
+  }
+  abstract public boolean coincide(Element elt);
+//  abstract boolean contientSchemaSousJacent(Schema sch);
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Element.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Relation.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Relation.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Relation.java	(revision 3653)
@@ -0,0 +1,64 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.elements;
+
+import java.util.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class Relation extends Element {
+  private Element elt1, elt2;
+  public Relation() {
+    super();
+  }
+  public Relation(String type, Element elt1, Element elt2) {
+    super(type);
+    setElt1(elt1);
+    setElt2(elt2);
+  }
+  public Element getElt1() {
+    return elt1;
+  }
+  public void setElt1(Element elt) {
+    elt1 = elt;
+  }
+  public Element getElt2() {
+    return elt2;
+  }
+  public void setElt2(Element elt) {
+    elt2 = elt;
+  }
+  @Override
+  public Element getElementSuivant(Jalon jalon) {
+    switch (jalon.origine) {
+      case ELT_2:
+        if (elt2.getClass()==jalon.classe&&elt2.getType().equals(jalon.type))
+          return elt2;
+        return null;
+      case ELT_1:
+        if (elt1.getClass()==jalon.classe&&elt1.getType().equals(jalon.type))
+          return elt1;
+        return null;
+      default:
+        return super.getElementSuivant(jalon);
+    }
+  }
+  protected HashSet<Unite> getUnitesSousjacentesNonTriees() {
+    HashSet<Unite> units = elt1.getUnitesSousjacentesNonTriees();
+    units.addAll(elt2.getUnitesSousjacentesNonTriees());
+    return units;
+  }
+//  boolean contientSchemaSousJacent(Schema sch) {
+//    return elt1.contientSchemaSousJacent(sch)||elt2.contientSchemaSousJacent(sch);
+//  }
+  public boolean coincide(Element elt) {
+    if (elt.getClass()!=Relation.class) return false;
+    Relation rel = (Relation) elt;
+    return getType().equals(rel.getType())&&elt1.coincide(rel.elt1)&&elt2.coincide(rel.elt2);
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Relation.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Schema.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Schema.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Schema.java	(revision 3653)
@@ -0,0 +1,83 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.elements;
+
+import java.util.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class Schema extends Element {
+  private HashSet<Element> contenu = new HashSet<Element>();
+  public Schema() {
+    super();
+  }
+  public Schema(String type) {
+    super(type);
+  }
+  public boolean ajouter(Element elt) {
+    // retourne false ssi pb de recursivité
+    if (elt==null) return true;
+    // à remplacer lors d'un chgt de version modifiant la signature de la classe
+// Element par :if (elt.contientSchemaSousJacent(this)) return false;
+    if (contientSchemaSousJacent(elt, this)) return false;
+    contenu.add(elt);
+    return true;
+  }
+  public boolean oter(Element elt) {
+    return contenu.remove(elt);
+  }
+  public HashSet<Element> getContenu() {
+    return contenu;
+  }
+  public boolean contient(Element elt) {
+    return contenu.contains(elt);
+  }
+  protected HashSet<Unite> getUnitesSousjacentesNonTriees() {
+    HashSet<Unite> units = new HashSet<Unite>();
+    for (Element elt : contenu) {
+      units.addAll(elt.getUnitesSousjacentesNonTriees());
+    }
+    return units;
+  }
+//  boolean contientSchemaSousJacent(Schema sch) {
+//    if (coincide(sch)) return true;
+//    for (Element elt : contenu) if (elt.contientSchemaSousJacent(sch))
+//        return true;
+//    return false;
+//  }
+  private static boolean contientSchemaSousJacent(Element elt, Schema sch) {
+    // Solution provisoire en attendant le chgt de version modifiant la signature
+    // de la classe Element
+    if (elt.getClass()==Unite.class) return false;
+    if (elt.getClass()==Relation.class) {
+      Relation rel = (Relation) elt;
+      return contientSchemaSousJacent(rel.getElt1(), sch)
+              ||contientSchemaSousJacent(rel.getElt2(), sch);
+    }
+    if (elt.getClass()==Schema.class) {
+      Schema sch1 = (Schema) elt;
+      if (sch1.coincide(sch)) return true;
+      for (Element elt1 : sch1.contenu) if (contientSchemaSousJacent(elt1, sch))
+          return true;
+      return false;
+    }
+    throw new IllegalArgumentException("Element de classe non identifiée");
+  }
+  public boolean coincide(Element elt) {
+    if (elt.getClass()!=Schema.class) return false;
+    Schema sch = (Schema) elt;
+    if (!getType().equals(sch.getType())) return false;
+    if (contenu.size()!=sch.getContenu().size()) return false;
+    Element[] contenu1 = contenu.toArray(new Element[0]);
+    Arrays.sort(contenu1);
+    Element[] contenu2 = sch.getContenu().toArray(new Element[0]);
+    Arrays.sort(contenu2);
+    for (int i = 0; i<contenu1.length; i++)
+      if (!contenu1[i].coincide(contenu2[i])) return false;
+    return true;
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Schema.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Unite.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Unite.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Unite.java	(revision 3653)
@@ -0,0 +1,70 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.elements;
+
+import java.util.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class Unite extends Element implements Comparable {
+  private int deb;
+  private int fin;
+  public Unite() {
+    super();
+  }
+  public Unite(String type, int deb, int fin) {
+    super(type);
+    this.deb = deb;
+    this.fin = fin;
+  }
+  public int getDeb() {
+    return deb;
+  }
+  public void setDeb(int deb) {
+    this.deb = deb;
+  }
+  public int getFin() {
+    return fin;
+  }
+  public void setFin(int fin) {
+    this.fin = fin;
+  }
+//  boolean contientSchemaSousJacent(Schema sch) {
+//    return false;
+//  }
+  public boolean coincide(Element elt) {
+    if (elt.getClass()!=Unite.class) return false;
+    Unite unit = (Unite) elt;
+    return getType().equals(unit.getType())&&deb==unit.deb&&fin==unit.fin;
+  }
+  public int compareTo(Unite unit2) {
+    int comp = Integer.signum(deb-unit2.deb);
+    if (comp==0) {
+      comp = -Integer.signum(fin-unit2.fin);
+      if (comp==0) {
+        comp = getType().compareTo(unit2.getType());
+        if (comp==0) {
+          comp = Integer.signum(hashCode()-unit2.hashCode());
+        }
+      }
+    }
+    return comp;
+  }
+  protected HashSet<Unite> getUnitesSousjacentesNonTriees() {
+    HashSet<Unite> units = new HashSet<Unite>();
+    units.add(this);
+    return units;
+  }
+  @Override
+  public Unite getUnite0() {
+    return this;
+  }
+  @Override
+  public Unite[] getUnitesSousjacentes() {
+    return new Unite[]{this};
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/elements/Unite.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersJava.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersJava.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersJava.java	(revision 3653)
@@ -0,0 +1,386 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+import java.io.*;
+import javax.swing.*;
+import visuAnalec.donnees.*;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public abstract class FichiersJava {
+	public static void ouvrirCorpusVue(Corpus corpus, Vue vue, String nomfichier) {
+		File fichierCorpus;
+		if (nomfichier.isEmpty()) {
+			if ((fichierCorpus = Fichiers.choisirFichier(Commande.OUVRIR,
+					"Choix du document", Fichiers.TypeFichier.DOC_ANALEC))==null) return;
+		} else {
+			if ((fichierCorpus = Fichiers.trouverFichier(Fichiers.TypeFichier.DOC_ANALEC, nomfichier))==null) {
+				JOptionPane.showMessageDialog(null, "Fichier "+nomfichier+" inexistant dans le dossier "
+						+Fichiers.getRepertoireCourant(Fichiers.TypeFichier.DOC_ANALEC).getPath(), "Erreur de lecture de fichier",
+						JOptionPane.ERROR_MESSAGE);
+				return;
+			}
+		}
+		if(!ouvrirCorpus(corpus, fichierCorpus, false)) return;
+		File fichierVue = Fichiers.trouverFichier(Fichiers.TypeFichier.VUE, fichierCorpus);
+		if (fichierVue==null) return;
+		ouvrirVue(vue, fichierVue);
+	}
+
+	public static boolean ouvrirCorpus(Corpus corpus, File fichierCorpus, boolean batch) {
+		ObjectInputStream ois = null;
+		try {
+			ois = new ObjectInputStream(new FileInputStream(fichierCorpus));
+			corpus.lireJava(ois, batch);
+		} catch (ClassNotFoundException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire le document "+fichierCorpus.getName()
+					+" : versions d'Analec incompatibles : "+e,
+					"Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (InvalidClassException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire le document "+fichierCorpus.getName()
+					+" : versions d'Analec incompatibles : "+e,
+					"Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (ClassCastException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire le document "+fichierCorpus.getName()
+					+" : versions d'Analec incompatibles : "+e,
+					"Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (IOException e) {
+			corpus.fermer();
+			JOptionPane.showMessageDialog(null, e, "Erreur de lecture de fichier : "+e, JOptionPane.ERROR_MESSAGE);
+			return false;
+		} finally {
+			try {
+				if (ois!=null) ois.close();
+			} catch (IOException e) {
+				JOptionPane.showMessageDialog(null, e, "Erreur de fermeture de fichier lu : "+e, JOptionPane.ERROR_MESSAGE);
+				return false;
+			}
+			return true;
+		}
+	}
+	public static boolean ouvrirStructure(Corpus corpus) {
+		File fichierStructure;
+		if ((fichierStructure = Fichiers.choisirFichier(Commande.OUVRIR,
+				"Choix de la structure", Fichiers.TypeFichier.STRUCTURE))==null) return false;
+		ObjectInputStream ois = null;
+		try {
+			ois = new ObjectInputStream(new FileInputStream(fichierStructure));
+			Structure structureLue = corpus.lireStructureJava(ois);
+			corpus.fusionnerStructureLue(structureLue);
+			corpus.newCorpusLu();
+		} catch (ClassNotFoundException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire la structure "+fichierStructure.getName()
+					+" : versions d'Analec incompatibles : "+e,
+					"Erreur d'ouverture de fichier .ecs", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (InvalidClassException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire la structure "+fichierStructure.getName()
+					+" : versions d'Analec incompatibles : "+e,
+					"Erreur d'ouverture de fichier .ecs", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (ClassCastException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire la structure "+fichierStructure.getName()
+					+" : versions d'Analec incompatibles : "+e,
+					"Erreur d'ouverture de fichier .ecs", JOptionPane.ERROR_MESSAGE);
+		} catch (IOException e) {
+			JOptionPane.showMessageDialog(null, e, "Erreur de lecture de fichier : "+e, JOptionPane.ERROR_MESSAGE);
+			return false;
+		} finally {
+			try {
+				if (ois!=null) ois.close();
+			} catch (IOException e) {
+				JOptionPane.showMessageDialog(null, e, "Erreur de fermeture de fichier lu : "+e, JOptionPane.ERROR_MESSAGE);
+			}
+		}
+		return true;
+	}
+
+	public static boolean ouvrirVue(Vue vue, File fichierVue) {
+		ObjectInputStream ois = null;
+		try {
+			ois = new ObjectInputStream(new FileInputStream(fichierVue));
+			if (!vue.lireJava(ois)) {
+				JOptionPane.showMessageDialog(null, "Impossible d'utiliser la vue "+fichierVue.getName()
+						+" : vue incompatible avec le document courant", "Erreur de lecture de fichier .ecv", JOptionPane.ERROR_MESSAGE);
+				if (ois!=null) ois.close();
+				return false;
+			}
+		} catch (InvalidClassException ex) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire la vue "+fichierVue.getName()
+					+" : versions d'Analec incompatibles ", "Erreur d'ouverture de fichier .ecv", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (IOException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (ClassNotFoundException ex) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire la vue "+fichierVue.getName()
+					+" : versions d'Analec incompatibles ", "Erreur d'ouverture de fichier .ecv", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (ClassCastException ex) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire la vue "+fichierVue.getName()
+					+" : versions d'Analec incompatibles ", "Erreur d'ouverture de fichier .ecv", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} finally {
+			try {
+				if (ois!=null) ois.close();
+			} catch (IOException ex) {
+				JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier lu", JOptionPane.ERROR_MESSAGE);
+			}
+		}
+		return true;
+	}
+
+	public static boolean ouvrirVue(Vue vue) {
+		File fichierVue;
+		if ((fichierVue = Fichiers.choisirFichier(Commande.OUVRIR,
+				"Choix de la vue", Fichiers.TypeFichier.VUE))==null) return false;
+		return ouvrirVue(vue, fichierVue);
+	}
+
+	public static void fusionnerAnnot(Corpus corpus) {
+		File fichierCorpus;
+		if ((fichierCorpus = Fichiers.choisirFichier(Commande.OUVRIR,
+				"Choix du fichier à fusionner", Fichiers.TypeFichier.DOC_ANALEC))==null)
+			return;
+		ObjectInputStream ois = null;
+		try {
+			ois = new ObjectInputStream(new FileInputStream(fichierCorpus));
+			corpus.fusionnerAnnotJava(ois);
+		} catch (ClassNotFoundException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+					+" : versions d'Analec incompatibles ",
+					"Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+			return;
+		} catch (ClassCastException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+					+" : versions d'Analec incompatibles ",
+					"Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+			return;
+		} catch (InvalidClassException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+					+" : versions d'Analec incompatibles ",
+					"Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+			return;
+		} catch (IOException ex) {
+			corpus.fermer();
+			JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+			return;
+		} finally {
+			try {
+				if (ois!=null) ois.close();
+			} catch (IOException ex) {
+				JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier lu", JOptionPane.ERROR_MESSAGE);
+			}
+		}
+
+	}
+
+	public static void concatenerDocuments(Corpus corpus) {
+		File fichierCorpus;
+		if ((fichierCorpus = Fichiers.choisirFichier(Commande.OUVRIR,
+				"Choix du fichier à concaténer", Fichiers.TypeFichier.DOC_ANALEC))==null)
+			return;
+		concatener(fichierCorpus, corpus);
+		corpus.newCorpusLu();
+	}
+
+	public static void concatenerCorpus(final Corpus corpus) {
+		File rep;
+		if ((rep = Fichiers.choisirRepertoire("Choix du dossier à concaténer"))
+				==null) return;
+		final File[] fics = Fichiers.listerFichiers(rep, Fichiers.TypeFichier.DOC_ANALEC);
+		final GMessages.GProgression progression =
+				new GMessages.GProgression(fics.length, "Concaténation", "fichiers");
+		Thread traitement = new Thread() {
+			@Override
+			public void run() {
+				for (int i = 0; i<fics.length; i++) {
+					if (progression.isCanceled()) break;
+					progression.setNbTraites(i+1);
+					concatener(fics[i], corpus);
+				}
+				corpus.newCorpusLu();
+			}
+		};
+		traitement.start();
+	}
+
+	public static void extraireTypeCorpus(final String type, final Corpus corpus) {
+		File rep;
+		if ((rep = Fichiers.choisirRepertoire("Choix du dossier à traiter"))==null) return;
+		final  File[] fics = Fichiers.listerFichiers(rep, Fichiers.TypeFichier.DOC_ANALEC);
+		final GMessages.GProgression progression =
+				new GMessages.GProgression(fics.length, "Extraction", "fichiers");
+		Thread traitement = new Thread() {
+			@Override
+			public void run() {
+				for (int i = 0; i<fics.length; i++) {
+					if (progression.isCanceled()) break;
+					progression.setNbTraites(i+1);
+					extraireType(fics[i], Fichiers.extraireNom(fics[i]), type, corpus);        
+				}
+				corpus.newCorpusLu();
+			}
+		};
+		traitement.start();
+	}
+
+	private static void extraireType(File fichierCorpus, String nomDocument,
+			String type, Corpus corpus) {
+		ObjectInputStream ois = null;
+		try {
+			ois = new ObjectInputStream(new FileInputStream(fichierCorpus));
+			corpus.extraireEtConcatenerCorpusJava(ois, nomDocument, type);
+		} catch (ClassNotFoundException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+					+" : versions d'Analec incompatibles ",
+					"Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+			return;
+		} catch (ClassCastException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+					+" : versions d'Analec incompatibles ",
+					"Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+			return;
+		} catch (InvalidClassException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+					+" : versions d'Analec incompatibles ",
+					"Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+			return;
+		} catch (IOException ex) {
+			corpus.fermer();
+			JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+			return;
+		} finally {
+			try {
+				if (ois!=null) ois.close();
+			} catch (IOException ex) {
+				JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier lu", JOptionPane.ERROR_MESSAGE);
+			}
+		}
+	}
+
+	private static void concatener(File fichierCorpus, Corpus corpus) {
+		ObjectInputStream ois = null;
+		try {
+			ois = new ObjectInputStream(new FileInputStream(fichierCorpus));
+			corpus.concatenerCorpusJava(ois);
+		} catch (ClassNotFoundException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+					+" : versions d'Analec incompatibles ",
+					"Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+			return;
+		} catch (ClassCastException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+					+" : versions d'Analec incompatibles ",
+					"Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+			return;
+		} catch (InvalidClassException e) {
+			JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+					+" : versions d'Analec incompatibles ",
+					"Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+			return;
+		} catch (IOException ex) {
+			corpus.fermer();
+			JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+			return;
+		} finally {
+			try {
+				if (ois!=null) ois.close();
+			} catch (IOException ex) {
+				JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier lu", JOptionPane.ERROR_MESSAGE);
+			}
+		}
+	}
+
+	public static boolean enregistrerCorpus(Corpus corpus, File fichier) {
+		if (fichier!=null) return ecrireCorpus(corpus, fichier);
+		return false;
+	}
+
+	public static boolean enregistrerCorpusSous(Corpus corpus) {
+		File fichier;
+		if ((fichier = Fichiers.choisirFichier(Commande.ENREGISTRER,
+				"Nom du fichier corpus", Fichiers.TypeFichier.DOC_ANALEC))==null) return false;
+		return ecrireCorpus(corpus, fichier);
+	}
+
+	public static boolean enregistrerStructure(Corpus corpus) {
+		File fichier;
+		if ((fichier = Fichiers.choisirFichier(Commande.ENREGISTRER,
+				"Nom du fichier structure", Fichiers.TypeFichier.STRUCTURE))==null) return false;
+		
+		return enregistrerStructure(corpus, fichier);
+	}
+
+	public static boolean enregistrerStructure(Corpus corpus, File fichier) {
+		ObjectOutputStream oos = null;
+		try {
+			oos = new ObjectOutputStream(new FileOutputStream(fichier));
+			corpus.ecrireStructureJava(oos);
+		} catch (IOException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} finally {
+			try {
+				if (oos!=null) oos.close();
+			} catch (IOException ex) {
+				JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier écrit", JOptionPane.ERROR_MESSAGE);
+			}
+		}
+		return true;
+	}
+
+	private static boolean ecrireCorpus(Corpus corpus, File fichier) {
+		ObjectOutputStream oos = null;
+		try {
+			oos = new ObjectOutputStream(new FileOutputStream(fichier));
+			corpus.ecrireJava(oos);
+			return true;
+		} catch (IOException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+			if (oos!=null) try {
+				oos.close();
+			} catch (IOException ex1) {
+			}
+			return false;
+
+		}
+	}
+
+	public static boolean enregistrerVue(Vue vue) {
+		File fichier;
+		if ((fichier = Fichiers.choisirFichier(Commande.ENREGISTRER,
+				"Nom du fichier vue", Fichiers.TypeFichier.VUE))==null) return false;
+		return enregistrerVue(vue, fichier);
+	}
+
+	public static boolean enregistrerVue(Vue vue, File fichier) {
+		ObjectOutputStream oos = null;
+		try {
+			oos = new ObjectOutputStream(new FileOutputStream(fichier));
+			vue.ecrireJava(oos);
+		} catch (IOException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} finally {
+			try {
+				if (oos!=null) oos.close();
+				return true;
+			} catch (IOException ex) {
+				JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier écrit", JOptionPane.ERROR_MESSAGE);
+				return false;
+			}
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersJava.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersTEI.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersTEI.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersTEI.java	(revision 3653)
@@ -0,0 +1,952 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.xml.parsers.*;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+import visuAnalec.util.GMessages.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public abstract class FichiersTEI {
+	public static void convertirCorpusTEI(final Corpus corpus) {
+		final File ficTEI;
+		final File repJava;
+		if ((ficTEI = Fichiers.choisirFichier(Commande.OUVRIR,
+				"Choix du fichier corpus TEI", TypeFichier.TEI))==null)
+			return;
+		if ((repJava = Fichiers.choisirRepertoire("Choix du dossier Java"))==null)
+			return;
+		if (!repJava.exists()) {
+			if (!GMessages.confirmationAction("Le dossier spécifié n'existe pas."
+					+" Voulez-vous le créer ?")) return;
+			if (!repJava.mkdir()) {
+				GMessages.impossibiliteAction("Echec de la création du dossier");
+				return;
+			}
+		}
+		convertir(ficTEI, repJava, corpus);
+	}
+	private static void convertir(File ficTEI, File repJava, Corpus corpus) {
+		BufferedInputStream tei = null;
+		String nomTEI = Fichiers.extraireNom(ficTEI)+"-";
+		if (Fichiers.existeDebutFichier(repJava, TypeFichier.DOC_ANALEC, nomTEI))
+			if (!GMessages.confirmationAction("Attention! Certains fichiers du "
+					+"dossier "+repJava.getName()
+					+" risquent d'être écrasés")) return;
+		try {
+			tei = new BufferedInputStream(
+					new ProgressMonitorInputStream(
+							null, "Conversion du corpus TEI "+nomTEI,
+							new FileInputStream(ficTEI)));
+			SAXParserFactory pf = (SAXParserFactory) SAXParserFactory.newInstance();
+			SAXParser sp = pf.newSAXParser();
+			sp.parse(tei, new TEIHandler(corpus, repJava, nomTEI));
+		} catch (IOException ex) {
+			corpus.fermer();
+			JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+			return;
+		} catch (ParserConfigurationException ex) {
+			corpus.fermer();
+			JOptionPane.showMessageDialog(null, ex, "Erreur de format de fichier", JOptionPane.ERROR_MESSAGE);
+			return;
+		} catch (SAXException ex) {
+			corpus.fermer();
+			JOptionPane.showMessageDialog(null, ex, "Erreur de format de fichier", JOptionPane.ERROR_MESSAGE);
+			return;
+		} finally {
+			try {
+				if (tei!=null) tei.close();
+			} catch (IOException ex) {
+				JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture du fichier lu", JOptionPane.ERROR_MESSAGE);
+			}
+		}
+	}
+
+	static class TEIHandler extends DefaultHandler {
+		File repJava;
+		String nomTEI;
+		Corpus corpus;
+		int noDoc;
+		String texte;
+		ArrayList<Integer> finParagraphes = new ArrayList<Integer>();
+		Balise etatCourant;
+		String typeCourant;
+		HashMap<String, Integer> ancres = new HashMap<String, Integer>();
+		HashMap<Unite, String[]> posUnites = new HashMap<Unite, String[]>();
+		HashMap<String, Element> idElements = new HashMap<String, Element>();
+		HashMap<Relation, String[]> eltsRelations = new HashMap<Relation, String[]>();
+		HashMap<Schema, String[]> eltsSchemas = new HashMap<Schema, String[]>();
+		HashMap<Element, String> propsElements = new HashMap<Element, String>();
+		HashMap<String, HashMap<String, String>> valsprops =
+				new HashMap<String, HashMap<String, String>>();
+		String idPropsEltCourant;
+		String champCourant;
+		String valCourant;
+
+		enum Balise {
+			TEICORPUS, TEIHEADER, TEIHEADER_CORPUS, TEI, TEXT, BODY, P, ANCHOR,
+			BACK, SPANGRP, SPAN, JOINGRP, JOIN, JOINGRP_REL, JOIN_REL,
+			JOINGRP_SCH, JOIN_SCH, FVLIB, FS, F, STRING, DEBUT_DOC, FIN_DOC,
+			AUTRE
+		};
+		static Balise balise(String nomBalise) {
+			try {
+				return Balise.valueOf(nomBalise.replaceAll("\\W", "").toUpperCase());
+			} catch (IllegalArgumentException e) {
+				return Balise.AUTRE;
+			}
+		}
+		TEIHandler(Corpus corpus, File repJava, String nomTEI) {
+			super();
+			this.corpus = corpus;
+			this.repJava = repJava;
+			this.nomTEI = nomTEI;
+		}
+		@Override
+		public void startDocument() {
+			noDoc = 0;
+			etatCourant = Balise.DEBUT_DOC;
+		}
+		@Override
+		public void endDocument() throws SAXNotSupportedException {
+			if (etatCourant!=Balise.FIN_DOC)
+				throw new SAXNotSupportedException("Fin de fichier inattendue");
+		}
+		@Override
+		public void startElement(String uri, String local, String nomBalise,
+				Attributes attributs) throws SAXException {
+			switch (balise(nomBalise)) {
+			case TEICORPUS:
+				if (etatCourant==Balise.DEBUT_DOC) etatCourant = Balise.TEICORPUS;
+				else
+					throw new SAXNotSupportedException("Balise <teiCorpus> mal placée");
+				break;
+			case TEIHEADER:
+				if (etatCourant==Balise.TEICORPUS)
+					etatCourant = Balise.TEIHEADER_CORPUS;
+				else if (etatCourant==Balise.TEI) etatCourant = Balise.TEIHEADER;
+				else
+					throw new SAXNotSupportedException("Balise <teiHeader> mal placée");
+
+				break;
+			case TEI:
+				if (etatCourant==Balise.TEICORPUS) {
+					noDoc++;
+					initCorpus();
+					etatCourant = Balise.TEI;
+				} else
+					throw new SAXNotSupportedException("Balise <tei> mal placée");
+				break;
+			case TEXT:
+				if (etatCourant==Balise.TEI) {
+					etatCourant = Balise.TEXT;
+				} else
+					throw new SAXNotSupportedException("Balise <text> mal placée");
+				break;
+			case BODY:
+				if (etatCourant==Balise.TEXT) {
+					etatCourant = Balise.BODY;
+				} else
+					throw new SAXNotSupportedException("Balise <body> mal placée");
+				break;
+			case P:
+				if (etatCourant==Balise.BODY) {
+					etatCourant = Balise.P;
+				} else
+					throw new SAXNotSupportedException("Balise <p> mal placée");
+				break;
+			case ANCHOR:
+				if ("AnalecDelimiter".equals(attributs.getValue("type"))) {
+					if (etatCourant==Balise.BODY||etatCourant==Balise.P) {
+						ancres.put(attributs.getValue("xml:id"), texte.length());
+					} else
+						throw new SAXNotSupportedException("Balise <anchor> de type "
+								+"\"AnalecDelimiter\" mal placée");
+				}
+				break;
+			case BACK:
+				if (etatCourant==Balise.TEXT) {
+					etatCourant = Balise.BACK;
+				} else
+					throw new SAXNotSupportedException("Balise <back> mal placée");
+				break;
+			case SPANGRP:
+				if ("AnalecUnit".equals(attributs.getValue("type"))) {
+					if (etatCourant==Balise.BACK) {
+						typeCourant = decodeId(attributs.getValue("n"));
+						if (typeCourant.isEmpty())
+							throw new SAXNotSupportedException("Attribut \"n\" d'une balise "
+									+"<spanGrp> de type \"AnalecUnit\" manquant");
+						etatCourant = Balise.SPANGRP;
+					} else
+						throw new SAXNotSupportedException("Balise <spanGrp> "
+								+"de type \"AnalecUnit\" mal placée");
+				}
+				break;
+			case SPAN:
+				if (etatCourant==Balise.SPANGRP) {
+					Unite unit = new Unite();
+					unit.setType(typeCourant);
+					posUnites.put(unit, new String[]{
+							xmlId(attributs.getValue("from")),
+							xmlId(attributs.getValue("to"))});
+					idElements.put(attributs.getValue("xml:id"), unit);
+					propsElements.put(unit, xmlId(attributs.getValue("ana")));
+					etatCourant = Balise.SPAN;
+				}
+				break;
+			case JOINGRP:
+				if ("AnalecRelation".equals(attributs.getValue("type"))) {
+					if (etatCourant==Balise.BACK) {
+						typeCourant = decodeId(attributs.getValue("n"));
+						if (typeCourant.isEmpty())
+							throw new SAXNotSupportedException("Attribut \"n\" d'une balise "
+									+"<joinGrp> de type \"AnalecRelation\" manquant");
+						etatCourant = Balise.JOINGRP_REL;
+					} else
+						throw new SAXNotSupportedException("Balise <joinGrp> "
+								+"de type \"AnalecRelation\" mal placée");
+				} else if ("AnalecSchema".equals(attributs.getValue("type"))) {
+					if (etatCourant==Balise.BACK) {
+						typeCourant = decodeId(attributs.getValue("n"));
+						if (typeCourant.isEmpty())
+							throw new SAXNotSupportedException("Attribut \"n\" d'une balise "
+									+"<joinGrp> de type \"AnalecSchema\" manquant");
+						etatCourant = Balise.JOINGRP_SCH;
+					} else
+						throw new SAXNotSupportedException("Balise <joinGrp> "
+								+"de type \"AnalecSchema\" mal placée");
+				}
+
+				break;
+			case JOIN:
+				if (etatCourant==Balise.JOINGRP_REL) {
+					Relation rel = new Relation();
+					rel.setType(typeCourant);
+					eltsRelations.put(rel, splitIds(attributs.getValue("target")));
+					idElements.put(attributs.getValue("xml:id"), rel);
+					propsElements.put(rel, xmlId(attributs.getValue("ana")));
+					etatCourant = Balise.JOIN_REL;
+				} else if (etatCourant==Balise.JOINGRP_SCH) {
+					Schema sch = new Schema();
+					sch.setType(typeCourant);
+					eltsSchemas.put(sch, splitIds(attributs.getValue("target")));
+					idElements.put(attributs.getValue("xml:id"), sch);
+					propsElements.put(sch, xmlId(attributs.getValue("ana")));
+					etatCourant = Balise.JOIN_SCH;
+				}
+				break;
+			case FVLIB:
+				if ("AnalecElementProperties".equals(attributs.getValue("n"))) {
+					if (etatCourant==Balise.BACK) {
+						etatCourant = Balise.FVLIB;
+					} else
+						throw new SAXNotSupportedException("Balise <fvLib> "
+								+"de type \"AnalecElementProperties\" mal placée");
+				}
+				break;
+			case FS:
+				if (etatCourant==Balise.FVLIB) {
+					idPropsEltCourant = attributs.getValue("xml:id");
+					valsprops.put(idPropsEltCourant, new HashMap<String, String>());
+					etatCourant = Balise.FS;
+				}
+				break;
+			case F:
+				if (etatCourant==Balise.FS) {
+					champCourant = decodeId(attributs.getValue("name"));
+					if (champCourant.isEmpty())
+						throw new SAXNotSupportedException("Attribut \"name\" "
+								+ "d'une balise <f> dans le <fvLib> de type"
+								+ " \"AnalecElementProperties\" manquant");
+
+					etatCourant = Balise.F;
+				}
+				break;
+			case STRING:
+				if (etatCourant==Balise.F) {
+					valCourant = "";
+					etatCourant = Balise.STRING;
+				}
+				break;
+			}
+		}
+		private String xmlId(String id) {
+			if (id==null||id.isEmpty()||id.charAt(0)!='#') return null;
+			return id.substring(1);
+		}
+		private String[] splitIds(String ids) {
+			if(ids.isEmpty()) return new String[0];
+			String[] idsplit = ids.split("\\s+");
+			for (int i = 0; i<idsplit.length; i++) {
+				idsplit[i] = xmlId(idsplit[i]);
+			}
+			return idsplit;
+		}
+		@Override
+		public void endElement(String uri, String local, String nomBalise) throws SAXException {
+			String type = "";
+			switch (balise(nomBalise)) {
+			case TEICORPUS:
+				if (etatCourant==Balise.TEICORPUS) etatCourant = Balise.FIN_DOC;
+				else
+					throw new SAXNotSupportedException("Balise </teiCorpus> mal placée");
+				break;
+			case TEIHEADER:
+				if (etatCourant==Balise.TEIHEADER_CORPUS)
+					etatCourant = Balise.TEICORPUS;
+				else if (etatCourant==Balise.TEIHEADER) etatCourant = Balise.TEI;
+				else
+					throw new SAXNotSupportedException("Balise </teiHeader> mal placée");
+				break;
+			case TEI:
+				if (etatCourant==Balise.TEI) {
+					remplirCorpus();
+					if (!ecrireFichier()) throw new SAXException("Erreur d'écriture "
+							+"du fichier "+nomTEI+noDoc+".ec");
+					etatCourant = Balise.TEICORPUS;
+				} else
+					throw new SAXNotSupportedException("Balise </tei> mal placée");
+				break;
+			case TEXT:
+				if (etatCourant==Balise.TEXT) etatCourant = Balise.TEI;
+				else
+					throw new SAXNotSupportedException("Balise </text> mal placée");
+				break;
+			case BODY:
+				if (etatCourant==Balise.BODY) {
+					corpus.setTexte(texte);
+					corpus.setFinParagraphes(finParagraphes);
+					etatCourant = Balise.TEXT;
+				} else
+					throw new SAXNotSupportedException("Balise </body> mal placée");
+				break;
+			case P:
+				if (etatCourant==Balise.P) {
+					finParagraphes.add(texte.length());
+					etatCourant = Balise.BODY;
+				}
+				break;
+			case BACK:
+				if (etatCourant==Balise.BACK) etatCourant = Balise.TEXT;
+				else
+					throw new SAXNotSupportedException("Balise </back> mal placée");
+				break;
+			case SPANGRP:
+				if (etatCourant==Balise.SPANGRP) etatCourant = Balise.BACK;
+				break;
+			case SPAN:
+				if (etatCourant==Balise.SPAN) etatCourant = Balise.SPANGRP;
+				break;
+			case JOINGRP:
+				if (etatCourant==Balise.JOINGRP_REL||etatCourant==Balise.JOINGRP_SCH)
+					etatCourant = Balise.BACK;
+				break;
+			case JOIN:
+				if (etatCourant==Balise.JOIN_REL) etatCourant = Balise.JOINGRP_REL;
+				else if (etatCourant==Balise.JOIN_SCH)
+					etatCourant = Balise.JOINGRP_SCH;
+				break;
+			case FVLIB:
+				if (etatCourant==Balise.FVLIB) etatCourant = Balise.BACK;
+				break;
+			case FS:
+				if (etatCourant==Balise.FS) etatCourant = Balise.FVLIB;
+				break;
+			case F:
+				if (etatCourant==Balise.F) etatCourant = Balise.FS;
+				break;
+			case STRING:
+				if (etatCourant==Balise.STRING) {
+					valsprops.get(idPropsEltCourant).put(champCourant, valCourant);
+					etatCourant = Balise.F;
+				}
+				break;
+			}
+		}
+		@Override
+		public void characters(char[] ch, int start, int taille) throws SAXException {
+			if (etatCourant==Balise.P)
+				texte += decodeTexte(new String(ch, start, taille));
+			if (etatCourant==Balise.STRING)
+				valCourant += decodeTexte(new String(ch, start, taille));
+		}
+		private static String decodeTexte(String ch) {
+			return ch.replaceAll("&amp;", "&").replaceAll("&lt;", "<").
+					replaceAll("&gt;", ">").replaceAll("&quot;", "\"").
+					replaceAll("&apos;", "\'").replaceAll("[\\t\\n\\r\\f]", "");
+		}
+		private static String decodeId(String ch) {
+			if (ch==null||ch.isEmpty()) return "";
+			String id = ch.charAt(0)=='_' ? ch.substring(1) : ch;
+			return id.replaceAll("_", " ");
+		}
+		private void initCorpus() {
+			corpus.clearAll();
+			texte = "";
+			finParagraphes.clear();
+			ancres.clear();
+			posUnites.clear();
+			eltsRelations.clear();
+			eltsSchemas.clear();
+			idElements.clear();
+			propsElements.clear();
+			valsprops.clear();
+		}
+		private void remplirCorpus() throws SAXNotSupportedException {
+			for (Unite unit : posUnites.keySet()) {
+				String[] pos = posUnites.get(unit);
+				if (pos[0]==null||!ancres.containsKey(pos[0])
+						||pos[1]==null||!ancres.containsKey(pos[1]))
+					throw new SAXNotSupportedException("Pas trouvé d'ancrage pour "
+							+"une unité de type "+unit.getType());
+				unit.setDeb(ancres.get(pos[0]));
+				unit.setFin(ancres.get(pos[1]));
+				String idProps = propsElements.get(unit);
+				if (idProps==null||!valsprops.containsKey(idProps))
+					throw new SAXNotSupportedException("Pas trouvé de propriétés pour "
+							+"une unité de type "+unit.getType());
+				HashMap<String, String> props = valsprops.get(idProps);
+				for (String champ : props.keySet())
+					unit.putProp(champ, props.get(champ));
+				corpus.addUniteLue(unit);
+			}
+			for (Relation rel : eltsRelations.keySet()) {
+				String[] idElts = eltsRelations.get(rel);
+				if (idElts.length!=2) {
+					throw new SAXNotSupportedException("Une relation de type "
+							+rel.getType()+" n'a pas deux termes");
+				}
+				if (idElts[0]==null||!idElements.containsKey(idElts[0])
+						||idElts[1]==null||!idElements.containsKey(idElts[1])) {
+					throw new SAXNotSupportedException("Errreur d'identification de termes "
+							+" pour une relation de type "+rel.getType());
+				}
+				rel.setElt1(idElements.get(idElts[0]));
+				rel.setElt2(idElements.get(idElts[1]));
+				String idProps = propsElements.get(rel);
+				if (idProps==null||!valsprops.containsKey(idProps))
+					throw new SAXNotSupportedException("Pas trouvé de propriétés pour "
+							+"une relation de type "+rel.getType());
+				HashMap<String, String> props = valsprops.get(idProps);
+				for (String champ : props.keySet())
+					rel.putProp(champ, props.get(champ));
+				corpus.addRelationLue(rel);
+			}
+			for (Schema sch : eltsSchemas.keySet()) {
+				String[] idElts = eltsSchemas.get(sch);
+				for (String idElt : idElts) {
+					if (idElt==null||!idElements.containsKey(idElt)) {
+						throw new SAXNotSupportedException("Errreur d'identification de termes "
+								+" pour un schema de type "+sch.getType());
+					}
+					sch.ajouter(idElements.get(idElt));
+				}
+				String idProps = propsElements.get(sch);
+				if (idProps==null||!valsprops.containsKey(idProps))
+					throw new SAXNotSupportedException("Pas trouvé de propriétés pour "
+							+"un schéma de type "+sch.getType());
+				HashMap<String, String> props = valsprops.get(idProps);
+				for (String champ : props.keySet())
+					sch.putProp(champ, props.get(champ));
+				corpus.addSchemaLu(sch);
+			}
+		}
+		private boolean ecrireFichier() {
+			return FichiersJava.enregistrerCorpus(corpus, Fichiers.creerFichier(
+					repJava, TypeFichier.DOC_ANALEC, nomTEI+noDoc));
+		}
+	}
+	public final static String TYPE_INFOS_META_DOCUMENTS = "Titre";
+	public final static String CHAMP_NON_RENSEIGNE = "non renseigné";
+	public final static String DEFAUT_TITRE_CORPUS = "";
+	public final static String DEFAUT_ANNOTATEURS = "";
+	public final static String DEFAUT_EDITEUR = "";
+	public final static String DEFAUT_SOURCE_CORPUS = "";
+	public static boolean exporterCorpusTEI(final Corpus corpus) {
+		File repJava;
+		final File ficTEI;
+		final File[] fics = Fichiers.choisirCorpus("Choix du dossier Java",
+				TypeFichier.CORPUS_ANALEC);
+		if (fics.length==0) return false;
+
+		final HashMap<String, String> infosCorpus = new HashMap<String, String>();
+		saisirInfosCorpus(infosCorpus);
+		if ((ficTEI = Fichiers.choisirFichier(Commande.ENREGISTRER,
+				"Nom du fichier TEI", Fichiers.TypeFichier.TEI))==null) return false;
+		final PrintWriter teiWriter;
+		try {
+			teiWriter = new PrintWriter(ficTEI, "UTF-8");
+		} catch (FileNotFoundException ex) {
+			GMessages.impossibiliteAction("Pas de fichier TEI ? ");
+
+			return false;
+		} catch (UnsupportedEncodingException ex) {
+			GMessages.impossibiliteAction("Pas de codage UTF-8 ?");
+			return false;
+		}
+		final TEIPrinter teiPrinter = new TEIPrinter(corpus, teiWriter);
+		final GMessages.GProgression progression =
+				new GMessages.GProgression(fics.length, "Conversion", "fichiers");
+		Thread traitement = new Thread() {
+			@Override
+			public void run() {
+				try {
+					teiPrinter.ecrireEnteteCorpus(infosCorpus);
+					for (int i = 0; i<fics.length; i++) {
+						if (progression.isCanceled()) break;
+						progression.setNbTraites(i+1);
+						File ficJava = fics[i];
+						if (FichiersJava.ouvrirCorpus(corpus, ficJava, true))
+							teiPrinter.ecrireDocument(Fichiers.extraireNom(ficJava));
+					}
+					corpus.fermer();
+					teiPrinter.ecrireFinCorpus();
+					teiWriter.close();
+				} catch (Throwable ex) {
+					GMessages.erreurFatale(ex);
+
+				}
+			}
+		};
+		traitement.start();
+		try {
+			traitement.join();
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+			return false;
+		}
+		return true;
+	}
+
+	private static boolean saisirInfosCorpus(HashMap<String, String> infosCorpus) {
+		final boolean[] pvalide = new boolean[1];
+		SaisieInfos fenetre = new SaisieInfos(pvalide, infosCorpus);
+		return pvalide[0];
+	}
+
+	private static class SaisieInfos extends JDialog {
+		private SaisieInfos(final boolean[] pvalide,
+				final HashMap<String, String> infosCorpus) {
+			super((JFrame) null, "Informations sur le corpus", true);
+			JPanel cadre = new JPanel(new BorderLayout());
+			setContentPane(cadre);
+			Rectangle rmax = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
+			int largeur = Math.min(rmax.width-100, 600);
+			int hauteur = Math.min(rmax.height-100, 400);
+			Point locFenetre = new Point((rmax.x+rmax.width)/2-largeur/2,
+					(rmax.y+rmax.height)/2-hauteur/2);
+			Dimension dimFenetre = new Dimension(largeur, hauteur);
+			setLocation(locFenetre);
+			setSize(dimFenetre);
+			setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
+			int hauteurCars = cadre.getFontMetrics(cadre.getFont()).getHeight()+5;
+			final JTextField champTitre = new JTextField(40);
+			champTitre.setMaximumSize(new Dimension(500, hauteurCars));
+			champTitre.setText(DEFAUT_TITRE_CORPUS);
+			final JTextField champAnnot = new JTextField(40);
+			champAnnot.setMaximumSize(new Dimension(500, hauteurCars));
+			champAnnot.setText(DEFAUT_ANNOTATEURS);
+			final JTextField champEditeur = new JTextField(40);
+			champEditeur.setMaximumSize(new Dimension(500, hauteurCars));
+			champEditeur.setText(DEFAUT_EDITEUR);
+			final JTextField champSource = new JTextField(40);
+			champSource.setMaximumSize(new Dimension(500, hauteurCars));
+			champSource.setText(DEFAUT_SOURCE_CORPUS);
+			Box box = Box.createVerticalBox();
+			box.add(Box.createVerticalGlue());
+			Box boxTitre = Box.createHorizontalBox();
+			boxTitre.add(Box.createHorizontalGlue());
+			boxTitre.add(new JLabel("Titre du corpus"));
+			boxTitre.add(Box.createHorizontalStrut(5));
+			boxTitre.add(champTitre);
+			boxTitre.add(Box.createHorizontalGlue());
+			box.add(boxTitre);
+			box.add(Box.createVerticalGlue());
+			Box boxAnnot = Box.createHorizontalBox();
+			boxAnnot.add(Box.createHorizontalGlue());
+			boxAnnot.add(new JLabel("Annotateurs"));
+			boxAnnot.add(Box.createHorizontalStrut(5));
+			boxAnnot.add(champAnnot);
+			boxAnnot.add(Box.createHorizontalGlue());
+			box.add(boxAnnot);
+			box.add(Box.createVerticalGlue());
+			Box boxEditeur = Box.createHorizontalBox();
+			boxEditeur.add(Box.createHorizontalGlue());
+			boxEditeur.add(new JLabel("Editeur"));
+			boxEditeur.add(Box.createHorizontalStrut(5));
+			boxEditeur.add(champEditeur);
+			boxEditeur.add(Box.createHorizontalGlue());
+			box.add(boxEditeur);
+			box.add(Box.createVerticalGlue());
+			Box boxSource = Box.createHorizontalBox();
+			boxSource.add(Box.createHorizontalGlue());
+			boxSource.add(new JLabel("Description du corpus"));
+			boxSource.add(Box.createHorizontalStrut(5));
+			boxSource.add(champSource);
+			boxSource.add(Box.createHorizontalGlue());
+			box.add(boxSource);
+			box.add(Box.createVerticalGlue());
+			add(box);
+			JButton valideModifs = new JButton(
+					new GAction("Valider") {
+						@Override
+						public void executer() {
+							pvalide[0] = true;
+							infosCorpus.put("Titre", champTitre.getText());
+							infosCorpus.put("Annot", champAnnot.getText());
+							infosCorpus.put("Editeur", champEditeur.getText());
+							infosCorpus.put("Source", champSource.getText());
+							dispose();
+						}
+						;
+					});
+			JButton annuleModifs = new JButton(
+					new GAction("Annuler") {
+						@Override
+						public void executer() {
+							pvalide[0] = false;
+							dispose();
+						}
+						;
+					});
+			Box boutons = Box.createHorizontalBox();
+			boutons.add(Box.createGlue());
+			boutons.add(valideModifs, Box.CENTER_ALIGNMENT);
+			boutons.add(Box.createHorizontalStrut(5));
+			boutons.add(annuleModifs, Box.CENTER_ALIGNMENT);
+			boutons.add(Box.createGlue());
+			add(boutons, BorderLayout.SOUTH);
+			setVisible(
+					true);
+
+		}
+	}
+
+	static private class TEIPrinter {
+		static private class Delimiteur implements Comparable<Delimiteur> {
+			private String id;
+			private int taille; // signé : négatif pour les délimiteurs de fin
+			private Delimiteur(String id, int taille) {
+				this.id = id;
+				this.taille = taille;
+			}
+			public int compareTo(Delimiteur d) {
+				if (taille!=d.taille) {
+					if (taille<0&&d.taille<0||taille>0&&d.taille>0)
+						return d.taille-taille;
+					else return taille-d.taille;
+				} else return taille>0 ? -d.id.compareTo(id) : d.id.compareTo(id);
+			}
+		}
+		private Corpus corpus;
+		private PrintWriter writer;
+		private String titreCorpus, annot, editeur, sourceCorpus;
+		private HashMap<String, ArrayList<Unite>> unites =
+				new HashMap<String, ArrayList<Unite>>();
+		private HashMap<String, ArrayList<Relation>> relations =
+				new HashMap<String, ArrayList<Relation>>();
+		private HashMap<String, ArrayList<Schema>> schemas =
+				new HashMap<String, ArrayList<Schema>>();
+		private HashMap<Element, String> ids = new HashMap<Element, String>();
+		private HashMap<String, String> encodeName = new HashMap<String, String>();
+		private HashMap<Integer, ArrayList<Delimiteur>> delimiteurs =
+				new HashMap<Integer, ArrayList<Delimiteur>>();
+		TEIPrinter(Corpus corpus, PrintWriter writer) {
+			this.corpus = corpus;
+			this.writer = writer;
+		}
+		private void ecrireEnteteCorpus(HashMap<String, String> infosCorpus) {
+			titreCorpus = traiterSaisie(infosCorpus.get("Titre"));
+			annot = traiterSaisie(infosCorpus.get("Annot"));
+			editeur = traiterSaisie(infosCorpus.get("Editeur"));
+			sourceCorpus = traiterSaisie(infosCorpus.get("Source"));
+			writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
+			writer.println("<teiCorpus xmlns=\"http://www.tei-c.org/ns/1.0\">");
+			writer.println(" <teiHeader>");
+			writer.println("<fileDesc>");
+			writer.println("<titleStmt>");
+			writer.println("<title>"+titreCorpus+"</title>");
+			writer.println("<respStmt>");
+			writer.println("<resp>annotated by</resp>");
+			writer.println("<name>"+annot+"</name>");
+			writer.println("</respStmt>");
+			writer.println("</titleStmt>");
+			writer.println("<publicationStmt>");
+			writer.println("<publisher>"+editeur+"</publisher>");
+			writer.println("</publicationStmt>");
+			writer.println("<sourceDesc>");
+			writer.println("<bibl>"+sourceCorpus+"</bibl>");
+			writer.println("</sourceDesc>");
+			writer.println("</fileDesc>");
+			writer.println("</teiHeader>");
+		}
+		private void ecrireFinCorpus() {
+			writer.println("</teiCorpus>");
+		}
+		private void preparerDonnees() {
+			unites.clear();
+			relations.clear();
+			schemas.clear();
+			ids.clear();
+			encodeName.clear();
+			delimiteurs.clear();
+			String codeType = "";
+			for (String type : corpus.getStructure().getTypes(Unite.class)) {
+				Unite[] units = corpus.getUnites(type).toArray(new Unite[0]);
+				Arrays.sort(units);
+				if (units.length>0) {
+					unites.put(type, new ArrayList<Unite>());
+					codeType = encodeId(type);
+					encodeName.put(type, codeType);
+					for (String prop : corpus.getStructure().getNomsProps(Unite.class, type))
+						encodeName.put(prop, encodeId(prop));
+				}
+				for (int no = 0; no<units.length; no++) {
+					Unite unit = units[no];
+					String id = "u-"+codeType+"-"+(no+1);
+					ids.put(unit, id);
+					unites.get(type).add(unit);
+					int taille = unit.getFin()-unit.getDeb();
+					Delimiteur del = new Delimiteur(id, taille);
+					addDel(unit.getDeb(), del);
+					if (taille>0) {
+						del = new Delimiteur(id, -taille);
+						addDel(unit.getFin(), del);
+					}
+				}
+			}
+			for (String type : corpus.getStructure().getTypes(Relation.class)) {
+				Relation[] rels = corpus.getRelations(type).toArray(new Relation[0]);
+				Arrays.sort(rels);
+				if (rels.length>0) {
+					relations.put(type, new ArrayList<Relation>());
+					codeType = encodeId(type);
+					encodeName.put(type, codeType);
+					for (String prop : corpus.getStructure().getNomsProps(Relation.class, type))
+						encodeName.put(prop, encodeId(prop));
+
+				}
+				for (int no = 0; no<rels.length; no++) {
+					Relation rel = rels[no];
+					String id = "r-"+codeType+"-"+(no+1);
+					ids.put(rel, id);
+					relations.get(type).add(rel);
+				}
+			}
+			for (String type : corpus.getStructure().getTypes(Schema.class)) {
+				Schema[] schs = corpus.getSchemas(type).toArray(new Schema[0]);
+				Arrays.sort(schs);
+				if (schs.length>0) {
+					schemas.put(type, new ArrayList<Schema>());
+					codeType = encodeId(type);
+					encodeName.put(type, codeType);
+					for (String prop : corpus.getStructure().getNomsProps(Schema.class, type))
+						encodeName.put(prop, encodeId(prop));
+				}
+				for (int no = 0; no<schs.length; no++) {
+					Schema sch = schs[no];
+					String id = "s-"+codeType+"-"+(no+1);
+					ids.put(sch, id);
+					schemas.get(type).add(sch);
+				}
+			}
+			int deb = 0;
+			for (int fin : corpus.getFinParagraphes()) {
+				int taille = fin-deb;
+				Delimiteur del = new Delimiteur("p", taille);
+				addDel(deb, del);
+				if (taille>0) {
+					del = new Delimiteur("p", -taille);
+					addDel(fin, del);
+				}
+				deb = fin;
+			}
+		}
+		private void addDel(int pos, Delimiteur del) {
+			if (!delimiteurs.containsKey(pos))
+				delimiteurs.put(pos, new ArrayList<Delimiteur>());
+			delimiteurs.get(pos).add(del);
+		}
+		private void ecrireDocument(String nomfic) {
+			preparerDonnees();
+			writer.println("<TEI>");
+			ecrireEntete(nomfic);
+			writer.println("<text>");
+			ecrireTexte();
+			ecrireAnnot();
+			writer.println("</text>");
+			writer.println("</TEI>");
+		}
+		private void ecrireEntete(String nomfic) {
+			String titre = "";
+			String auteur = "";
+			String source = "";
+			if (!corpus.getUnites(TYPE_INFOS_META_DOCUMENTS).isEmpty()) {
+				Unite infos = corpus.getUnites(TYPE_INFOS_META_DOCUMENTS).get(0);
+				titre = encodeTexte(infos.getProp("titre"));
+				auteur = encodeTexte(infos.getProp("auteur"));
+				source = encodeTexte(infos.getProp("source"));
+			}
+			if (titre.isEmpty()) titre = nomfic;
+			if (auteur.isEmpty()) auteur = CHAMP_NON_RENSEIGNE;
+			if (source.isEmpty()) source = CHAMP_NON_RENSEIGNE;
+			writer.println("<teiHeader>");
+			writer.println("<fileDesc>");
+			writer.println("<titleStmt>");
+			writer.println("<title>"+titre+"</title>");
+			writer.println("<author>"+auteur+"</author>");
+			writer.println("<respStmt>");
+			writer.println("<resp>annotated by</resp>");
+			writer.println("<name>"+annot+"</name>");
+			writer.println("</respStmt>");
+			writer.println("</titleStmt>");
+			writer.println("<publicationStmt>");
+			writer.println("<publisher>"+editeur+"</publisher>");
+			writer.println("</publicationStmt>");
+			writer.println("<sourceDesc>");
+			writer.println("<bibl>"+source+"</bibl>");
+			writer.println("</sourceDesc>");
+			writer.println("</fileDesc>");
+			writer.println("</teiHeader>");
+		}
+		private void ecrireTexte() {
+			writer.println("<body>");
+			Integer[] pos = delimiteurs.keySet().toArray(new Integer[0]);
+			Arrays.sort(pos);
+			ecrireDel(delimiteurs.get(0));
+			int deb = 0;
+			for (int i = 1; i<pos.length; i++) {
+				int fin = pos[i];
+				writer.print(encodeTexte(corpus.getTexte().substring(deb, fin)));
+				ecrireDel(delimiteurs.get(fin));
+				deb = fin;
+			}
+			writer.println("</body>");
+		}
+		private void ecrireDel(ArrayList<Delimiteur> delims) {
+			Delimiteur[] dels = delims.toArray(new Delimiteur[0]);
+			Arrays.sort(dels);
+			for (Delimiteur del : dels) {
+				if (del.id.equals("p")) {
+					if (del.taille>0)
+						writer.println("<p>");
+					else {
+						writer.println();
+						if (del.taille<0) writer.println("</p>");
+						else writer.println("<p/>");
+					}
+				} else {
+					String ancre1 = "<anchor xml:id=\""+del.id;
+					String ancre2 = "\" type=\"AnalecDelimiter\" subtype=\"Unit";
+					if (del.taille>0)
+						writer.print(ancre1+"-start"+ancre2+"Start\"/>");
+					else if (del.taille<0)
+						writer.print(ancre1+"-end"+ancre2+"End\"/>");
+					else {  // ne devrait pas se produire : une unité de taille nulle
+						writer.print(ancre1+"-start"+ancre2+"Start\"/>");
+						writer.print(ancre1+"-end"+ancre2+"End\"/>");
+					}
+				}
+			}
+		}
+		private void ecrireAnnot() {
+			writer.println("<back>");
+			for (String type : unites.keySet()) {
+				writer.println("<spanGrp type=\"AnalecUnit\""
+						+" n=\""+encodeName.get(type)+"\">");
+				for (Unite unit : unites.get(type)) ecrireUnite(unit);
+				writer.println("</spanGrp>");
+			}
+			for (String type : relations.keySet()) {
+				writer.println("<joinGrp type=\"AnalecRelation\""
+						+" n=\""+encodeName.get(type)+"\">");
+				for (Relation rel : relations.get(type)) ecrireRelation(rel);
+				writer.println("</joinGrp>");
+			}
+			for (String type : schemas.keySet()) {
+				writer.println("<joinGrp type=\"AnalecSchema\""
+						+" n=\""+encodeName.get(type)+"\">");
+				for (Schema sch : schemas.get(type)) ecrireSchema(sch);
+				writer.println("</joinGrp>");
+			}
+			writer.println("<fvLib n=\"AnalecElementProperties\">");
+			for (String type : unites.keySet())
+				for (Unite unit : unites.get(type)) ecrireProps(unit);
+			for (String type : relations.keySet())
+				for (Relation rel : relations.get(type)) ecrireProps(rel);
+			for (String type : schemas.keySet())
+				for (Schema sch : schemas.get(type)) ecrireProps(sch);
+			writer.println("</fvLib>");
+			writer.println("</back>");
+		}
+		private void ecrireUnite(Unite unit) {
+			String id = ids.get(unit);
+			writer.println("<span xml:id=\""+id+"\"");
+			writer.println("from=\"#"+id+"-start\" to=\"#"+id+"-end\"");
+			writer.println("ana=\"#"+id+"-fs\"/>");
+		}
+		private void ecrireRelation(Relation rel) {
+			String id = ids.get(rel);
+			writer.println("<join xml:id=\""+ids.get(rel)+"\"");
+			writer.println("target=\"#"+ids.get(rel.getElt1())
+					+" #"+ids.get(rel.getElt2())+"\"");
+			writer.println("ana=\"#"+id+"-fs\"/>");
+		}
+		private void ecrireSchema(Schema sch) {
+			String id = ids.get(sch);
+			writer.println("<join xml:id=\""+ids.get(sch)+"\"");
+			writer.print("target=\"");
+			for (Element elt : sch.getContenu())
+				writer.print("#"+ids.get(elt)+" ");
+			writer.println("\"");
+			writer.println("ana=\"#"+id+"-fs\"/>");
+		}
+		private void ecrireProps(Element elt) {
+			writer.println("<fs xml:id=\""+ids.get(elt)+"-fs\">");
+			HashMap<String, String> props = elt.getProps();
+			for (String nom : props.keySet()) {
+				if (props.get(nom)!=null)
+					writer.println("<f name=\""+encodeName.get(nom)+"\"><string>"
+							+encodeTexte(props.get(nom))+"</string></f>");
+			}
+			writer.println("</fs>");
+		}
+		private static String encodeTexte(String ch) {
+			return ch.replaceAll("&", "&amp;").replaceAll("<", "&lt;").
+					replaceAll(">", "&gt;").replaceAll("\"", "&quot;").
+					replaceAll("\'", "&apos;");
+		}
+		final static String interdits = "[!\\\"#\\$%&'\\(\\)\\*+,/;<=>\\?"
+				+"@\\[\\\\\\]\\^`\\{\\|\\}\\~]";
+		private static String encodeId(String ch) {
+			String id = ch.replaceAll("\\s", "_");
+			if (id.matches("[-\\.0-9];*")) id = '_'+id;
+			id = id.replaceAll(interdits, "\u00b7");
+			if (id.length()>2&&id.substring(0, 3).equalsIgnoreCase("xml")) id = '_'+id;
+			return id;
+		}
+		private static String traiterSaisie(String ch) {
+			if (ch==null) return CHAMP_NON_RENSEIGNE;
+			if (ch.trim().isEmpty()) return CHAMP_NON_RENSEIGNE;
+			return encodeTexte(ch);
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersTEI.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/ProgressMonitorDemo.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/ProgressMonitorDemo.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/ProgressMonitorDemo.java	(revision 3653)
@@ -0,0 +1,173 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+/*
+ * 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.
+ */ 
+
+
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.beans.*;
+import java.util.Random;
+
+public class ProgressMonitorDemo extends JPanel
+                                 implements ActionListener,
+                                            PropertyChangeListener {
+
+    private ProgressMonitor progressMonitor;
+    private JButton startButton;
+    private JTextArea taskOutput;
+    private Task task;
+
+    class Task extends SwingWorker<Void, Void> {
+        @Override
+        public Void doInBackground() {
+            Random random = new Random();
+            int progress = 0;
+            setProgress(0);
+            try {
+                Thread.sleep(1000);
+                while (progress < 100 && !isCancelled()) {
+                    //Sleep for up to one second.
+                    Thread.sleep(random.nextInt(1000));
+                    //Make random progress.
+                    progress += random.nextInt(10);
+                    setProgress(Math.min(progress, 100));
+                }
+            } catch (InterruptedException ignore) {}
+            return null;
+        }
+
+        @Override
+        public void done() {
+            Toolkit.getDefaultToolkit().beep();
+            startButton.setEnabled(true);
+            progressMonitor.setProgress(0);
+        }
+    }
+
+    public ProgressMonitorDemo() {
+        super(new BorderLayout());
+
+        //Create the demo's UI.
+        startButton = new JButton("Start");
+        startButton.setActionCommand("start");
+        startButton.addActionListener(this);
+
+        taskOutput = new JTextArea(5, 20);
+        taskOutput.setMargin(new Insets(5,5,5,5));
+        taskOutput.setEditable(false);
+
+        add(startButton, BorderLayout.PAGE_START);
+        add(new JScrollPane(taskOutput), BorderLayout.CENTER);
+        setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
+
+    }
+
+
+    /**
+     * Invoked when the user presses the start button.
+     */
+    public void actionPerformed(ActionEvent evt) {
+        progressMonitor = new ProgressMonitor(ProgressMonitorDemo.this,
+                                  "Running a Long Task",
+                                  "", 0, 100);
+        progressMonitor.setProgress(0);
+        task = new Task();
+        task.addPropertyChangeListener(this);
+        task.execute();
+        startButton.setEnabled(false);
+    }
+
+    /**
+     * Invoked when task's progress property changes.
+     */
+    public void propertyChange(PropertyChangeEvent evt) {
+        if ("progress" == evt.getPropertyName() ) {
+            int progress = (Integer) evt.getNewValue();
+            progressMonitor.setProgress(progress);
+            String message =
+                String.format("Completed %d%%.\n", progress);
+            progressMonitor.setNote(message);
+            taskOutput.append(message);
+            if (progressMonitor.isCanceled() || task.isDone()) {
+                Toolkit.getDefaultToolkit().beep();
+                if (progressMonitor.isCanceled()) {
+                    task.cancel(true);
+                    taskOutput.append("Task canceled.\n");
+                } else {
+                    taskOutput.append("Task completed.\n");
+                }
+                startButton.setEnabled(true);
+            }
+        }
+
+    }
+
+    /**
+     * Create the GUI and show it.  For thread safety,
+     * this method should be invoked from the
+     * event-dispatching thread.
+     */
+    private static void createAndShowGUI() {
+        //Create and set up the window.
+        JFrame frame = new JFrame("ProgressMonitorDemo");
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+        //Create and set up the content pane.
+        JComponent newContentPane = new ProgressMonitorDemo();
+        newContentPane.setOpaque(true); //content panes must be opaque
+        frame.setContentPane(newContentPane);
+
+        //Display the window.
+        frame.pack();
+        frame.setVisible(true);
+    }
+
+    public static void main(String[] args) {
+        //Schedule a job for the event-dispatching thread:
+        //creating and showing this application's GUI.
+        javax.swing.SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+                createAndShowGUI();
+            }
+        });
+    }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/ProgressMonitorDemo.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersGlozz.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersGlozz.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersGlozz.java	(revision 3653)
@@ -0,0 +1,731 @@
+package visuAnalec.fichiers;
+
+import java.io.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.xml.parsers.*;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public abstract class FichiersGlozz {
+	public static void convertirCorpusGlozz(final Corpus corpus) {
+		File repGlozz;
+		final File repJava;
+		if ((repGlozz = Fichiers.choisirRepertoire("Choix du dossier Glozz"))==null)
+			return;
+		if ((repJava = Fichiers.choisirRepertoire("Choix du dossier Java"))==null)
+			return;
+		if (!repJava.exists()) {
+			if (!GMessages.confirmationAction("Le dossier spécifié n'existe pas."
+					+" Voulez-vous le créer ?")) return;
+			if (!repJava.mkdir()) {
+				GMessages.impossibiliteAction("Echec de la création du dossier");
+				return;
+			}
+		}
+		final File[] fics = Fichiers.listerFichiers(repGlozz, Fichiers.TypeFichier.GLOZZ_CORPUS);
+		final GMessages.GProgression progression =
+				new GMessages.GProgression(fics.length, "Conversion", "fichiers");
+		Thread traitement = new Thread() {
+			@Override
+			public void run() {
+				try {
+					for (int i = 0; i<fics.length; i++) {
+						if (progression.isCanceled()) break;
+						progression.setNbTraites(i+1);
+						File fichierCorpus = fics[i];
+						File fichierAnnot = Fichiers.trouverFichier(TypeFichier.GLOZZ_ANNOT, fichierCorpus);
+						if (fichierAnnot==null) continue;
+						importer(fichierCorpus, fichierAnnot, corpus);
+						FichiersJava.enregistrerCorpus(corpus, Fichiers.creerFichier(repJava, TypeFichier.DOC_ANALEC, fichierCorpus));
+						//          corpus.fermer();
+					}
+					corpus.fermer();
+				} catch (Throwable ex) {
+					GMessages.erreurFatale(ex);
+				}
+			}
+		};
+		traitement.start();
+	}
+	
+	public static boolean importerGlozz(Corpus corpus, File fichierCorpus, File fichierAnnot) {
+		if (!importer(fichierCorpus, fichierAnnot, corpus)) {
+			return false;
+		}
+		corpus.newCorpusLu();
+		
+		return true;
+	}
+	
+	/**
+	 * 
+	 * @param corpus
+	 */
+	public static boolean importerGlozz(Corpus corpus) {
+		File fichierCorpus;
+		File fichierAnnot;
+		if ((fichierCorpus = Fichiers.choisirFichier(Commande.OUVRIR,
+				"Choix du fichier corpus", Fichiers.TypeFichier.GLOZZ_CORPUS))==null)
+			return false;
+		if ((fichierAnnot = Fichiers.choisirFichier(Commande.OUVRIR,
+				"Choix du fichier annotations", Fichiers.TypeFichier.GLOZZ_ANNOT))==null)
+			return false;
+		
+		return importerGlozz(corpus, fichierCorpus, fichierAnnot);
+	}
+	
+	/**
+	 * 
+	 * @param fichierCorpus ac file (txt)
+	 * @param fichierAnnot aa file (annotations)
+	 * 
+	 * @param corpus
+	 */
+	private static boolean importer(File fichierCorpus, File fichierAnnot, Corpus corpus) {
+		BufferedReader text = null;
+		BufferedInputStream annot = null;
+		try {
+			text = new BufferedReader(new InputStreamReader(new FileInputStream(fichierCorpus), "UTF-8"));
+			annot = new BufferedInputStream(new FileInputStream(fichierAnnot));
+			corpus.setTexte(text.readLine());
+			SAXParserFactory pf = (SAXParserFactory) SAXParserFactory.newInstance();
+			SAXParser sp = pf.newSAXParser();
+			sp.parse(annot, new GlozzHandler(corpus));
+		} catch (IOException ex) {
+			corpus.fermer();
+			JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (ParserConfigurationException ex) {
+			corpus.fermer();
+			JOptionPane.showMessageDialog(null, ex, "Erreur de format de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (SAXException ex) {
+			corpus.fermer();
+			JOptionPane.showMessageDialog(null, ex, "Erreur de format de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} finally {
+			try {
+				if (text!=null) text.close();
+				if (annot!=null) annot.close();
+			} catch (IOException ex) {
+				JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture du fichier lu", JOptionPane.ERROR_MESSAGE);
+			}
+		}
+		return true;
+	}
+	
+	public static boolean importerModeleGlozz(Corpus corpus, File fichierModele) {
+		BufferedInputStream modele = null;
+		
+		try {
+			modele = new BufferedInputStream(new FileInputStream(fichierModele));
+			SAXParserFactory pf = (SAXParserFactory) SAXParserFactory.newInstance();
+			SAXParser sp = pf.newSAXParser();
+			Structure structureLue = new Structure();
+			sp.parse(modele, new ModeleGlozzHandler(structureLue));
+			corpus.fusionnerStructureLue(structureLue);
+			corpus.newCorpusLu();
+		} catch (IOException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (ParserConfigurationException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur de format de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (SAXException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur de format de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} finally {
+			try {
+				if (modele!=null) modele.close();
+			} catch (IOException ex) {
+				JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture du fichier lu", JOptionPane.ERROR_MESSAGE);
+			}
+		}
+		return true;
+	}
+	
+	public static boolean importerModeleGlozz(Corpus corpus) {
+		File fichierModele;
+		if ((fichierModele = Fichiers.choisirFichier(Commande.OUVRIR,
+				"Choix du fichier modèle", Fichiers.TypeFichier.GLOZZ_MODELE))==null)
+			return false;
+		
+		return importerModeleGlozz(corpus, fichierModele);
+	}
+	
+	public static boolean exporterGlozz(Corpus corpus) {
+		PrintWriter text = null;
+		PrintWriter annot = null;
+		PrintWriter model = null;
+		File fichierCorpus;
+		File fichierAnnot;
+		File fichierModel;
+		if ((fichierCorpus = Fichiers.choisirFichier(Commande.ENREGISTRER,
+				"Nom du fichier corpus", Fichiers.TypeFichier.GLOZZ_CORPUS))==null) return false;
+		if ((fichierAnnot = Fichiers.choisirFichier(Commande.ENREGISTRER,
+				"Nom du fichier annotations", Fichiers.TypeFichier.GLOZZ_ANNOT))==null)
+			return false;
+		try {
+			text = new PrintWriter(fichierCorpus, "UTF-8");
+			annot = new PrintWriter(fichierAnnot, "UTF-8");
+			text.print(corpus.getTexte());
+			GlozzPrinter gp = new GlozzPrinter(corpus, annot);
+			gp.ecrireAnnot();
+		} catch (FileNotFoundException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (UnsupportedEncodingException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} finally {
+			if (text!=null) text.close();
+			if (annot!=null) annot.close();
+		}
+		if ((fichierModel = Fichiers.choisirFichier(Commande.ENREGISTRER,
+				"Exporter aussi le modèle ?", Fichiers.TypeFichier.GLOZZ_MODELE))==null)
+			return true;
+		try {
+			model = new PrintWriter(fichierModel, "UTF-8");
+			ModelGlozzPrinter gp = new ModelGlozzPrinter(corpus.getStructure(), model);
+			gp.ecrireModel();
+		} catch (FileNotFoundException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (UnsupportedEncodingException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} finally {
+			if (model!=null) model.close();
+		}
+		return true;
+	}
+	
+	public static boolean exporterModeleGlozz(Structure structure) {
+		PrintWriter model = null;
+		File fichierModel;
+		if ((fichierModel = Fichiers.choisirFichier(Commande.ENREGISTRER,
+				"Nom du fichier modèle ?", Fichiers.TypeFichier.GLOZZ_MODELE))==null)
+			return false;
+		try {
+			model = new PrintWriter(fichierModel, "UTF-8");
+			ModelGlozzPrinter gp = new ModelGlozzPrinter(structure, model);
+			gp.ecrireModel();
+		} catch (FileNotFoundException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} catch (UnsupportedEncodingException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} finally {
+			if (model!=null) model.close();
+		}
+		return true;
+	}
+
+	static class GlozzHandler extends DefaultHandler {
+		Corpus corpus;
+		Balise etatCourant = null;
+		Element elementCourant = null;
+		String champCourant = null;
+		String valCourant = null;
+		HashMap<String, Element> elements = new HashMap<String, Element>();
+		ArrayList<Relation> relations = new ArrayList<Relation>();
+		HashMap<Relation, ArrayList<String>> idTermes = new HashMap<Relation, ArrayList<String>>();
+		ArrayList<Schema> schemas = new ArrayList<Schema>();
+		HashMap<Schema, ArrayList<String>> idContenus = new HashMap<Schema, ArrayList<String>>();
+
+		public static enum Balise {
+			ANNOTATIONS, UNIT, RELATION, SCHEMA, METADATA, AUTHOR, CREATIONDATE,
+			LASTMODIFIER, LASTMODIFICATIONDATE, CHARACTERISATION, TYPE, FEATURESET,
+			FEATURE, POSITIONING, START, END, SINGLEPOSITION, TERM,
+			EMBEDDEDUNIT, EMBEDDEDRELATION, EMBEDDEDSCHEMA,
+			FLAG, COMMENT, ANNOTATIONMODEL, UNITS, VALUE
+		};
+		static Balise balise(String nomBalise) {
+			return Balise.valueOf(nomBalise.replaceAll("\\W", "").toUpperCase());
+		}
+		GlozzHandler(Corpus corpus) {
+			super();
+			this.corpus = corpus;
+		}
+		@Override
+		public void startDocument() {
+			corpus.clearAnnot();
+		}
+		@Override
+		public void endDocument() throws SAXNotSupportedException {
+			for (Relation rel : relations) {
+				ArrayList<String> idterms = idTermes.get(rel);
+				if (idterms.size()!=2) {
+					throw new SAXNotSupportedException("Une relation de type "+rel.getType()+" n'a pas deux termes");
+				}
+				if (elements.get(idterms.get(0))==null) {
+					throw new SAXNotSupportedException("Terme inconnu id = "+idterms.get(0)
+							+" pour une relation de type "+rel.getType());
+				}
+				rel.setElt1(elements.get(idterms.get(0)));
+				if (elements.get(idterms.get(1))==null) {
+					throw new SAXNotSupportedException("Terme inconnu id = "+idterms.get(1)
+							+" pour une relation de type "+rel.getType());
+				}
+				rel.setElt2(elements.get(idterms.get(1)));
+				corpus.addRelationLue(rel);
+			}
+			for (Schema sch : schemas) {
+				for (String id : idContenus.get(sch)) {
+					if (elements.get(id)==null) {
+						throw new SAXNotSupportedException("Contenu inconnu id = "+id
+								+" pour un schéma de type "+sch.getType());
+					}
+					sch.ajouter(elements.get(id));
+				}
+				corpus.addSchemaLu(sch);
+			}
+			corpus.verifierFinParagraphesTypesUnites(new String[]{
+					"title", "subTitle", "sectionTitle", "subSectionTitle",
+					"subSubSectionTitle", "subSubSubSectionTitle", "quote", "listItem"});
+			corpus.trierFinParagraphes();
+			corpus.verifierFinParagrapheFinTexte();
+		}
+		@Override
+		public void startElement(String uri, String local, String nomBalise, Attributes attributs) throws SAXException {
+			if (etatCourant==Balise.FLAG) return;
+			switch (balise(nomBalise)) {
+			case FLAG:
+				etatCourant = Balise.FLAG;
+				break;
+			case UNIT:
+				elementCourant = new Unite();
+				elements.put(attributs.getValue("id"), elementCourant);
+				break;
+			case RELATION:
+				elementCourant = new Relation();
+				elements.put(attributs.getValue("id"), elementCourant);
+				idTermes.put((Relation) elementCourant, new ArrayList<String>());
+				break;
+			case SCHEMA:
+				elementCourant = new Schema();
+				elements.put(attributs.getValue("id"), elementCourant);
+				idContenus.put((Schema) elementCourant, new ArrayList<String>());
+				break;
+			case TYPE:
+				etatCourant = Balise.TYPE;
+				valCourant = "";
+				break;
+			case FEATURE:
+				etatCourant = Balise.FEATURE;
+				champCourant = attributs.getValue("name");
+				valCourant = "";
+				break;
+			case START:
+				etatCourant = Balise.START;
+				break;
+			case END:
+				etatCourant = Balise.END;
+				break;
+			case SINGLEPOSITION:
+				if (elementCourant.getClass()!=Unite.class) {
+					throw new SAXNotSupportedException("La balise singlePosition ne peut être utilisée que pour des unités");
+				}
+				if (elementCourant.getType().equals("paragraph")) {
+					if (etatCourant==Balise.END) {
+						corpus.addFinParagraphe(Integer.parseInt(attributs.getValue("index")));
+					}
+				} else {
+					switch (etatCourant) {
+					case START:
+						((Unite) elementCourant).setDeb(Integer.parseInt(attributs.getValue("index")));
+						break;
+					case END:
+						((Unite) elementCourant).setFin(Integer.parseInt(attributs.getValue("index")));
+						break;
+					}
+				}
+				break;
+			case TERM:
+				if (elementCourant.getClass()!=Relation.class)
+					throw new SAXNotSupportedException("La balise term ne peut être utilisée que pour des relations");
+				idTermes.get((Relation) elementCourant).add(attributs.getValue("id"));
+				break;
+
+			case EMBEDDEDUNIT:
+			case EMBEDDEDRELATION:
+			case EMBEDDEDSCHEMA:
+				if (elementCourant.getClass()!=Schema.class)
+					throw new SAXNotSupportedException(
+							"Les balises embedded ne peuvent être utilisées que pour des schémas");
+				idContenus.get((Schema) elementCourant).add(attributs.getValue("id"));
+				break;
+			}
+		}
+		@Override
+		public void endElement(String uri, String local, String nomBalise) throws SAXException {
+			if (etatCourant==Balise.FLAG) {
+				if (balise(nomBalise)==Balise.FLAG) etatCourant = null;
+				return;
+			}
+			String type = "";
+			switch (balise(nomBalise)) {
+			case UNIT:
+				type = elementCourant.getType();
+				if (type==null||type.isEmpty())
+					throw new SAXNotSupportedException("Pas trouvé de type pour cette unité");
+				if (!type.equals("paragraph")) {
+					corpus.addUniteLue((Unite) elementCourant);
+					elementCourant = null;
+				}
+				break;
+			case RELATION:
+				type = elementCourant.getType();
+				if (type==null||type.isEmpty())
+					throw new SAXNotSupportedException("Pas trouvé de type pour cette relation");
+				relations.add((Relation) elementCourant);
+				elementCourant = null;
+				break;
+			case SCHEMA:
+				type = elementCourant.getType();
+				if (type==null||type.isEmpty())
+					throw new SAXNotSupportedException("Pas trouvé de type pour ce shéma");
+				schemas.add((Schema) elementCourant);
+				elementCourant = null;
+				break;
+			case TYPE:
+				elementCourant.setType(valCourant);
+				valCourant = null;
+				etatCourant = null;
+				break;
+			case FEATURE:
+				elementCourant.putProp(champCourant, valCourant);
+				etatCourant = null;
+				champCourant = null;
+				valCourant = null;
+				break;
+			case START:
+				etatCourant = null;
+				break;
+			case END:
+				etatCourant = null;
+				break;
+			}
+		}
+		@Override
+		public void characters(char[] ch, int start, int taille) throws SAXException {
+			if (etatCourant==null||!EnumSet.of(Balise.TYPE, Balise.FEATURE).contains(etatCourant)) {
+				return;
+			}
+			valCourant += new String(ch, start, taille);
+		}
+	}
+
+	static class ModeleGlozzHandler extends DefaultHandler {
+		Structure structure;
+		boolean listeValeurs = false;
+		Class<? extends Element> classeCourante = Unite.class;  // par défaut : balise <units> sous-entendue 
+		String typeCourant = null;
+		String champCourant = null;
+		String valeurCourante = null;
+
+		public static enum Balise {
+			ANNOTATIONMODEL, UNITS, RELATIONS, SCHEMAS, TYPE, FEATURESET,
+			FEATURE, POSSIBLEVALUES, VALUE
+		};
+		static Balise balise(String nomBalise) throws SAXNotRecognizedException {
+			try {
+				return Balise.valueOf(nomBalise.replaceAll("\\W", "").toUpperCase());
+			} catch (Exception e) {
+				throw new SAXNotRecognizedException("Balise non reconnue : "+nomBalise);
+			}
+		}
+		ModeleGlozzHandler(Structure structure) {
+			super();
+			this.structure = structure;
+		}
+		@Override
+		public void startDocument() {
+		}
+		@Override
+		public void endDocument() throws SAXNotSupportedException {
+		}
+		@Override
+		public void startElement(String uri, String local, String nomBalise, Attributes attributs) throws SAXException {
+			String valdef = null;
+			switch (balise(nomBalise)) {
+			case UNITS:
+				classeCourante = Unite.class;
+				break;
+			case RELATIONS:
+				classeCourante = Relation.class;
+				break;
+			case SCHEMAS:
+				classeCourante = Schema.class;
+				break;
+			case TYPE:
+				typeCourant = attributs.getValue("name");
+				if (typeCourant==null||typeCourant.isEmpty())
+					throw new SAXNotSupportedException("Nom de type absent");
+				structure.ajouterType(classeCourante, typeCourant);
+				break;
+			case FEATURE:
+				if (typeCourant==null||typeCourant.isEmpty())
+					throw new SAXNotSupportedException("Nom de type absent");
+				champCourant = attributs.getValue("name");
+				if (champCourant==null||champCourant.isEmpty())
+					throw new SAXNotSupportedException("Nom de type absent");
+				structure.ajouterProp(classeCourante, typeCourant, champCourant);
+				break;
+			case POSSIBLEVALUES:
+				if (typeCourant==null||typeCourant.isEmpty()||champCourant==null||champCourant.isEmpty())
+					throw new SAXNotSupportedException("Nom de type ou de feature absent");
+				listeValeurs = true;
+				valdef = attributs.getValue("default");
+				if (valdef!=null&&!valdef.isEmpty())
+					structure.modifierValParDefaut(classeCourante, typeCourant, champCourant, valdef);
+				break;
+			case VALUE:
+				if (listeValeurs) valeurCourante = "";
+				valdef = attributs.getValue("default");
+				if (valdef!=null&&!valdef.isEmpty()) {
+					if (typeCourant==null||typeCourant.isEmpty()||champCourant==null||champCourant.isEmpty())
+						throw new SAXNotSupportedException("Nom de type ou de feature absent");
+					structure.ajouterVal(classeCourante, typeCourant, champCourant, valdef);
+					structure.modifierValParDefaut(classeCourante, typeCourant, champCourant, valdef);
+				}
+				break;
+			}
+		}
+		@Override
+		public void endElement(String uri, String local, String nomBalise) throws SAXException {
+			switch (balise(nomBalise)) {
+			case POSSIBLEVALUES:
+				listeValeurs = false;
+				break;
+			case VALUE:
+				if (listeValeurs&&valeurCourante!=null&&!valeurCourante.isEmpty())
+					structure.ajouterVal(classeCourante, typeCourant, champCourant, valeurCourante);
+				break;
+			}
+		}
+		@Override
+		public void characters(char[] ch, int start, int taille) throws SAXException {
+			if (listeValeurs) {
+				valeurCourante += new String(ch, start, taille);
+			}
+		}
+	}
+
+	static class GlozzPrinter {
+		Corpus corpus;
+		PrintWriter annot;
+		HashMap<Element, String> idDates = new HashMap<Element, String>();
+		String idAuteur = "analec0.2";
+		String idDateParagraphes = "0";
+		String idParagraphes = idAuteur+"_"+idDateParagraphes;
+		GlozzPrinter(Corpus corpus, PrintWriter annot) {
+			this.corpus = corpus;
+			this.annot = annot;
+			attribueIdDates();
+		}
+		void attribueIdDates() {
+			long idDate = (new Date()).getTime();
+			for (Unite unite : corpus.getToutesUnites()) {
+				idDates.put(unite, Long.toString(idDate++));
+			}
+			for (Relation relation : corpus.getToutesRelations()) {
+				idDates.put(relation, Long.toString(idDate++));
+			}
+			for (Schema schema : corpus.getTousSchemas()) {
+				idDates.put(schema, Long.toString(idDate++));
+			}
+		}
+		String getId(Element elt) {
+			return idAuteur+"_"+idDates.get(elt);
+		}
+		void ecrireAnnot() {
+			annot.println("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
+			annot.println("<annotations>");
+			ecrireFinParagraphes();
+			ecrireUnites();
+			ecrireRelations();
+			ecrireSchemas();
+			annot.println("</annotations>");
+		}
+		private void ecrireFinParagraphes() {
+			int deb = 0;
+			for (int fin : corpus.getFinParagraphes()) {
+				ecrireUnite("paragraph", idAuteur, idDateParagraphes, idParagraphes, new HashMap<String, String>(), deb, fin);
+				deb = fin;
+			}
+		}
+		private void ecrireUnites() {
+			for (Unite unit : corpus.getToutesUnites()) {
+				ecrireUnite(unit.getType(), idAuteur, idDates.get(unit), getId(unit), unit.getProps(), unit.getDeb(), unit.getFin());
+			}
+		}
+		private void ecrireRelations() {
+			for (Relation rel : corpus.getToutesRelations()) {
+				ecrireRelation(rel.getType(), idAuteur, idDates.get(rel), getId(rel), rel.getProps(), rel.getElt1(), rel.getElt2());
+			}
+		}
+		private void ecrireSchemas() {
+			for (Schema sch : corpus.getTousSchemas()) {
+				ecrireSchema(sch.getType(), idAuteur, idDates.get(sch), getId(sch), sch.getProps(), sch.getContenu());
+			}
+		}
+		private void ecrireUnite(String type, String idAuteur, String idDate, String id, HashMap<String, String> props, int deb, int fin) {
+			annot.println("<unit id=\""+id+"\">");
+			ecrireMetadata(idAuteur, idDate);
+			ecrireProps(type, props);
+			ecrirePos(deb, fin);
+			annot.println("</unit>");
+		}
+		private void ecrireRelation(String type, String idAuteur, String idDate, String id, HashMap<String, String> props, Element elt1, Element elt2) {
+			annot.println("<relation id=\""+id+"\">");
+			ecrireMetadata(idAuteur, idDate);
+			ecrireProps(type, props);
+			ecrireRel(elt1, elt2);
+			annot.println("</relation>");
+		}
+		private void ecrireSchema(String type, String idAuteur, String idDate, String id, HashMap<String, String> props, HashSet<Element> elts) {
+			annot.println("<schema id=\""+id+"\">");
+			ecrireMetadata(idAuteur, idDate);
+			ecrireProps(type, props);
+			ecrireSch(elts);
+			annot.println("</schema>");
+		}
+		private void ecrireMetadata(String idAuteur, String id) {
+			annot.println("<metadata>");
+			annot.println("<author>"+idAuteur+"</author>");
+			annot.println("<creation-date>"+id+"</creation-date>");
+			annot.println("</metadata>");
+		}
+		private void ecrireProps(String type, HashMap<String, String> props) {
+			annot.println("<characterisation>");
+			annot.println("<type>"+encodeXMLTexte(type)+"</type>");
+			if (props.isEmpty()) {
+				annot.println("<featureSet/>");
+			} else {
+				annot.println("<featureSet>");
+				for (String prop : props.keySet()) {
+					if (props.get(prop)!=null) {
+						annot.println("<feature name =\""+encodeXMLTexte(prop)+"\">"
+								+encodeXMLTexte(props.get(prop))+"</feature>");
+					}
+				}
+				annot.println("</featureSet>");
+
+			}
+			annot.println("</characterisation>");
+		}
+		private void ecrirePos(int deb, int fin) {
+			annot.println("<positioning>");
+			annot.println("<start>");
+			annot.println("<singlePosition index = \""+deb+"\"/>");
+			annot.println("</start>");
+			annot.println("<end>");
+			annot.println("<singlePosition index = \""+fin+"\"/>");
+			annot.println("</end>");
+			annot.println("</positioning>");
+		}
+		private void ecrireRel(Element elt1, Element elt2) {
+			annot.println("<positioning>");
+			annot.println("<term id = \""+getId(elt1)+"\"/>");
+			annot.println("<term id = \""+getId(elt2)+"\"/>");
+			annot.println("</positioning>");
+		}
+		private void ecrireSch(HashSet<Element> elts) {
+			annot.println("<positioning>");
+			for (Element elt : elts) {
+				Class classe = elt.getClass();
+				if (classe==Unite.class) {
+					annot.print("<embedded-unit ");
+				}
+				if (classe==Relation.class) {
+					annot.print("<embedded-relation ");
+				}
+				if (classe==Schema.class) {
+					annot.print("<embedded-schema ");
+				}
+				annot.println("id = \""+getId(elt)+"\"/>");
+			}
+			annot.println("</positioning>");
+		}
+	}
+
+	static class ModelGlozzPrinter {
+		Structure structure;
+		PrintWriter model;
+		ModelGlozzPrinter(Structure structure, PrintWriter model) {
+			this.structure = structure;
+			this.model = model;
+		}
+		void ecrireModel() {
+			model.println("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
+			model.println("<annotationModel>");
+			ecrireUnites();
+			ecrireRelations();
+			ecrireSchemas();
+			model.println("</annotationModel>");
+		}
+		private void ecrireUnites() {
+			model.println("<units>");
+			for (String type : structure.getTypes(Unite.class))
+				ecrireType(Unite.class, type);
+			model.println("</units>");
+		}
+		private void ecrireRelations() {
+			model.println("<relations>");
+			for (String type : structure.getTypes(Relation.class))
+				ecrireType(Relation.class, type);
+			model.println("</relations>");
+		}
+		private void ecrireSchemas() {
+			model.println("<schemas>");
+			for (String type : structure.getTypes(Schema.class))
+				ecrireType(Schema.class, type);
+			model.println("</schemas>");
+		}
+		private void ecrireType(Class<? extends Element> classe, String type) {
+			model.print("<type name=\""+encodeXMLTexte(type)+"\"");
+			if (classe==Relation.class) model.print(" oriented=\"true\"");
+			model.println(">");
+			model.println("<featureSet>");
+			for (String prop : structure.getNomsProps(classe, type))
+				ecrireProp(classe, type, prop);
+			model.println("</featureSet>");
+			model.println("</type>");
+		}
+		private void ecrireProp(Class<? extends Element> classe, String type, String prop) {
+			model.println("<feature name=\""+encodeXMLTexte(prop)+"\">");
+			if (structure.getValeursProp(classe, type, prop).isEmpty()) {
+				model.println("<value type=\"free\" default=\"\" />");
+			} else {
+				model.println("<possibleValues default = \""
+						+structure.getValeurParDefaut(classe, type, prop)+"\">");
+				for (String val : structure.getValeursProp(classe, type, prop))
+					model.println("<value>"+encodeXMLTexte(val)+"</value>");
+				model.println("</possibleValues>");
+			}
+			model.println("</feature>");
+
+		}
+	}
+	static String encodeXMLTexte(String ch) {
+		//    return ch;
+		return ch.replaceAll("&", "&amp;").replaceAll("<", "&lt;").
+				replaceAll(">", "&gt;").replaceAll("\"", "&quot;").
+				replaceAll("\'", "&apos;");
+	}
+
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersGlozz.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersGraphique.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersGraphique.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersGraphique.java	(revision 3653)
@@ -0,0 +1,195 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+import java.awt.*;
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class FichiersGraphique {
+
+  public static class CercleColore {
+
+    public int cx, cy, r;
+    public Color couleur;
+  }
+
+  public static interface GraphiqueExport {
+
+    public Dimension initExport();
+
+    public Rectangle getCadre();
+
+    public CercleColore[] getCerclesColores();
+  }
+
+  public static void exporterGraphiqueSVG(GraphiqueExport donnees) {
+    PrintWriter sortie = null;
+    File fichierGraphique;
+    if ((fichierGraphique = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier ?", Fichiers.TypeFichier.GRAPHIQUE_SVG)) == null) return;
+    try {
+      sortie = new PrintWriter(fichierGraphique, "UTF-8");
+      ecrireSVG(sortie, donnees);
+    } catch (FileNotFoundException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier",
+              JOptionPane.ERROR_MESSAGE);
+    } catch (UnsupportedEncodingException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier",
+              JOptionPane.ERROR_MESSAGE);
+    } finally {
+      if (sortie != null) sortie.close();
+    }
+  }
+
+  public static void ecrireSVG(PrintWriter sortie, GraphiqueExport donnees) {
+    sortie.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
+    sortie.println("<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"");
+    Dimension dim = donnees.initExport();
+    sortie.println("x=\"0px\" y=\"0px\" width=\"" + dim.width
+            + "px\" height=\"" + dim.height + "px\">");
+    Rectangle cadre = donnees.getCadre();
+    if (cadre != null)
+      sortie.println("<rect x=\"" + cadre.x + "\" y=\"" + cadre.y
+              + "\" fill=\"none\" stroke=\"#000000\" width=\"" + cadre.width
+              + "\" height=\"" + cadre.height + "\"/>");
+    CercleColore[] cercles = donnees.getCerclesColores();
+    for (CercleColore cercle : cercles)
+      sortie.println("<ellipse cx=\"" + cercle.cx + "\" cy=\""
+              + cercle.cy + "\" fill=\"" + ecritCouleurSVG(cercle.couleur)
+              + "\" stroke=\"#000000\" rx=\"" + cercle.r
+              + "\" ry=\"" + cercle.r + "\"/>");
+
+    sortie.println("</svg>");
+  }
+
+  private static String ecritCouleurSVG(Color c) {
+    String res = "#";
+    res += Integer.toHexString(c.getRGB()).substring(2);
+    return res;
+  }
+
+  public static void exporterGraphiqueEMF(GraphiqueExport donnees) {
+    FileChannel canal = null;
+    FileOutputStream sortie = null;
+    File fichierGraphique;
+    if ((fichierGraphique = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier ?", Fichiers.TypeFichier.GRAPHIQUE_EMF)) == null) return;
+    try {
+      sortie = new FileOutputStream(fichierGraphique);
+      canal = sortie.getChannel();
+      ByteBuffer buff = ecrireEMF(donnees);
+      canal.write(buff);
+    } catch (IOException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier",
+              JOptionPane.ERROR_MESSAGE);
+    } finally {
+      if (canal != null)
+        try {
+          canal.close();
+        } catch (IOException ex) {
+          JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier",
+                  JOptionPane.ERROR_MESSAGE);
+        }
+      if (sortie != null)
+        try {
+          sortie.close();
+        } catch (IOException ex) {
+          JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier",
+                  JOptionPane.ERROR_MESSAGE);
+        }
+    }
+  }
+
+  private static ByteBuffer ecrireEMF(GraphiqueExport donnees) {
+    ArrayList<Integer> dessin = new ArrayList<Integer>();
+        Dimension dim = donnees.initExport();
+    int nbrecords = 0;
+    dessin.add(1); // header
+    dessin.add(88); // taille du header 
+    dessin.addAll(Arrays.asList(0, 0, dim.width, dim.height)); 
+                                                   // taille du graphique en px 
+    dessin.addAll(Arrays.asList(0, 0, dim.width*32, dim.height*32)); 
+                                                  // taille en 0.01 mm (px * 32)
+    dessin.add(0x464D4520); // signature (" EMF" à l'endroit!!) 
+    dessin.add(0x00010000); // version 
+    int indTailles = dessin.size();  // endroit où mettre les tailles 
+    dessin.addAll(Arrays.asList(0, 0)); // taille du fichier, nb records : remplis à la fin
+    dessin.add(2); // nbobjs : pen et brush
+    dessin.addAll(Arrays.asList(0, 0));   //taille et offset de la description
+    dessin.add(0); // nb d'entrees de palette 
+    dessin.addAll(Arrays.asList(1024, 768, 320, 240)); // taille du device en px et en mm
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x11, 0xC, 0x8));  // mapmode : 0x8 (anisotropique)
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x12, 0xC, 0x1));  // bkmode : 0x1 (transparent)
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0xA, 0x10, 0, 0));  // setWindowOrgEx: 0,0
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0xC, 0x10, 0, 0));  // setViewPortOrgEx: 0,0
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x9, 0x10, dim.width, dim.height));  // setWindowExtEx
+    nbrecords++; // setWindowExtEx: 0,0
+    dessin.addAll(Arrays.asList(0xB, 0x10, dim.width, dim.height));  // setViewPortExtEx
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x27, 0x18, 1, 1, 0, 0));  // createBrushIndirect : 
+    nbrecords++;                                        //1 (NoObj) 1 (BS_NULL) 0 0
+    dessin.addAll(Arrays.asList(0x25, 0xC, 1));  // selectObject 1
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x5F, 0x34, 2, 0, 0, 0, 0, 0x12200, 0x4, 0, 0, 0, 0));
+    // extCreatePen : 2 (NoObj) 0 0 0 0 (absence de DIB) 
+    // 0x12200 (PS_GEOMETRIC, JOIN_MITER, ENDCAP_FLAT) 
+    // 0x4 (largeur) 0 (BS_NULL) 0 (Color) 0 (BrushHatch) 0 (numStyleEntries)     
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x25, 0xC, 2));  // selectObject 2
+    nbrecords++;
+      Rectangle cadre = donnees.getCadre();
+    if (cadre != null) {
+  
+    dessin.addAll(Arrays.asList(0x2B, 0x18, cadre.x, cadre.y, 
+            cadre.x+cadre.width, cadre.y+cadre.height));  //  Rectangle
+    nbrecords++;
+    }
+ CercleColore[] cercles = donnees.getCerclesColores();
+   for (CercleColore cercle : cercles) {
+//      sortie.println("<ellipse cx=\"" + cercle.cx + "\" cy=\""
+//              + cercle.cy + "\" fill=\"" + ecritCouleurSVG(cercle.couleur)
+//              + "\" stroke=\"#000000\" rx=\"" + cercle.r
+//              + "\" ry=\"" + cercle.r + "\"/>");
+    dessin.addAll(Arrays.asList(0x28, 0xC, 1));  // deleteObject 1
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x27, 0x18, 1, 0, ecritCouleurEMF(cercle.couleur), 0));  
+    nbrecords++;      // createBrushIndirect : 1 (NoObj) 0 (BS_SOLID) Color (0BGR) 0
+    dessin.addAll(Arrays.asList(0x25, 0xC, 1));  // selectObject 1
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x2A, 0x18, cercle.cx-cercle.r, cercle.cy-cercle.r,
+            cercle.cx+cercle.r, cercle.cy+cercle.r));  //  Ellipse
+    nbrecords++;
+   }
+    dessin.addAll(Arrays.asList(0xE, 0x14, 0, 0, 0x14));  //  EOF 0xE 
+    nbrecords++;                                      //+ taille (20?) et offset palette
+    dessin.set(indTailles++, dessin.size() * 4);
+    dessin.set(indTailles, nbrecords);
+    ByteBuffer buff = ByteBuffer.allocate(dessin.size() * 4).order(ByteOrder.LITTLE_ENDIAN);
+    buff.clear();
+    for (int n : dessin) buff.putInt(n);
+    buff.flip();
+    return buff;
+  }
+    private static int ecritCouleurEMF(Color c) {
+    return c.getRed() | (c.getGreen()<<8) | (c.getBlue()<<16);
+  }
+
+
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersGraphique.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersCoNLL.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersCoNLL.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersCoNLL.java	(revision 3653)
@@ -0,0 +1,212 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public abstract class FichiersCoNLL {
+  static final String TYPE_UNITES = "Token";
+  static final String TYPE_RELATION = "Dependency";
+  static final String TYPE_RELATION_PROJ = "Projective Dependency";
+  static final String PROP_LEMME = "Lemma";
+  static final String PROP_C_POS = "C-POS";
+  static final String PROP_POS = "POS";
+  static final String PROP_TRAITS = "Features";
+  static final String PROP_REL = "Function";
+  public static void importerCoNLL(Corpus corpus) {
+    BufferedReader in = null;
+    File ficCoNLL;
+    GCodage codage = new GCodage();
+    if ((ficCoNLL = Fichiers.choisirFichier(Commande.OUVRIR,
+            "Choix du fichier CoNLL", TypeFichier.CONLL))==null)
+      return;
+    try {
+      in = new BufferedReader(new InputStreamReader(
+              new FileInputStream(ficCoNLL), "UTF-8"));
+      CoNLLParser parseur = new CoNLLParser(corpus);
+      parseur.parser(in);
+      corpus.newCorpusLu();
+    } catch (IOException ex) {
+      corpus.fermer();
+      JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } finally {
+      try {
+        if (in!=null) in.close();
+      } catch (IOException ex) {
+        JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture du fichier lu", JOptionPane.ERROR_MESSAGE);
+      }
+    }
+  }
+
+  static class CoNLLParser {
+    private Corpus corpus;
+    private String texte="";
+    private ArrayList<String> noHeads = new ArrayList<String>();
+    private ArrayList<String> depRels = new ArrayList<String>();
+    private ArrayList<String> noPHeads = new ArrayList<String>();
+    private ArrayList<String> pDepRels = new ArrayList<String>();
+    private ArrayList<Unite> units = new ArrayList<Unite>();
+    private HashMap<String, Integer> noTokenUnits = new HashMap<String, Integer>();
+    CoNLLParser(Corpus corpus) {
+      this.corpus = corpus;
+    }
+    private void parser(BufferedReader in) throws IOException {
+      String ligne;
+      int noligne = 0;
+      while (true) {
+        ligne = in.readLine();
+        if (ligne==null) {
+          finDocument(noligne);
+          break;
+        }
+        noligne++;
+        if (ligne.trim().isEmpty()) finPhrase(noligne);
+        else parserToken(ligne, noligne);
+      }
+    }
+    private void parserToken(String ligne, int noligne) throws IOException {
+      String ch;
+      String[] items = ligne.split("\\t");
+      if (items.length!=10)
+        throw new CoNLLException("Nombre de colonnes incorrect ("
+                +items.length+")", noligne);
+      Unite unit = new Unite();
+      unit.setType(TYPE_UNITES);
+      units.add(unit);
+      // champ ID
+      ch = items[0].replace('_', ' ').trim();
+      if (ch.isEmpty())
+        throw new CoNLLException("Pas trouvé de numéro de token", noligne);
+      noTokenUnits.put(ch, units.size()-1);
+      // champ FORM
+      ch = items[1].replace('_', ' ').trim();
+      if (ch.isEmpty())
+        throw new CoNLLException("Pas trouvé de token", noligne);
+      if (isPonct1(ch)) texte = texte.trim();
+      unit.setDeb(texte.length());
+      texte += ch;
+      unit.setFin(texte.length());
+      if (!isPonct2(ch)) texte += " ";
+      // champ LEMMA    
+      ch = items[2].replace('_', ' ').trim();
+      if (!ch.isEmpty())
+        unit.putProp(PROP_LEMME, ch);
+      // champ CPOSTAG
+      ch = items[3].replace('_', ' ').trim();
+      if (ch.isEmpty())
+        throw new CoNLLException("Pas trouvé de C-POS", noligne);
+      unit.putProp(PROP_C_POS, ch);
+      // champ POSTAG
+      ch = items[4].replace('_', ' ').trim();
+      if (ch.isEmpty())
+        throw new CoNLLException("Pas trouvé de POS", noligne);
+      unit.putProp(PROP_POS, ch);
+      // champ FEATS
+      ch = items[5].replace('_', ' ').trim();
+      if (!ch.isEmpty()) {
+        String[] chs = ch.split("\\|");
+        String traits = "";
+        for (String trait : chs) {
+          String[] attval = trait.split("=");
+          if (attval.length==2)
+            unit.putProp(attval[0].trim(), attval[1].trim());
+          else {
+            if (!traits.isEmpty()) traits += '|';
+            traits += trait;
+          }
+        }
+        if (!traits.isEmpty())
+          unit.putProp(PROP_TRAITS, traits);
+      }
+      // champ HEAD
+      ch = items[6].replace('_', ' ').trim();
+      if (ch.isEmpty())
+        throw new CoNLLException("Pas trouvé de HEAD", noligne);
+      noHeads.add(ch);
+      // champ DEPREL
+      ch = items[7].replace('_', ' ').trim();
+      if (ch.isEmpty())
+        throw new CoNLLException("Pas trouvé de DEP-REL", noligne);
+      depRels.add(ch);
+      // champ PHEAD
+      ch = items[8].replace('_', ' ').trim();
+      noPHeads.add(ch);
+      // champ PDEPREL
+      ch = items[9].replace('_', ' ').trim();
+      pDepRels.add(ch);
+    }
+    static private boolean isPonct1(String ch) {
+      if (ch.length()!=1) return false;
+      return ".,;:)]}!?'".contains(ch);
+    }
+    static private boolean isPonct2(String ch) {
+      if (ch.length()!=1) return false;
+      return "([{'".contains(ch);
+    }
+    private void finPhrase(int noligne) throws CoNLLException {
+      for (Unite unit : units) corpus.addUniteLue(unit);
+      for (int i = 0; i<units.size(); i++) {
+        Unite unit = units.get(i);
+        String nohead = noHeads.get(i);
+        String deprel = depRels.get(i);
+        if (!nohead.equals("0")) {
+          Integer k = noTokenUnits.get(nohead);
+          if (k==null)
+            throw new CoNLLException("Erreur de numéro de token de HEAD : "
+                    +nohead+" sur l'une des lignes précédentes", noligne);
+          Relation rel = new Relation(TYPE_RELATION, units.get(i), units.get(k));
+          if (deprel.isEmpty())
+            throw new CoNLLException("Pas trouvé de DEP-REL"
+                    +" sur l'une des lignes précédentes", noligne);
+          rel.putProp(PROP_REL, deprel);
+          corpus.addRelationLue(rel);
+          nohead = noPHeads.get(i);
+          deprel = pDepRels.get(i);
+          if (!nohead.isEmpty()&&!nohead.equals("0")) {
+            k = noTokenUnits.get(nohead);
+            if (k==null)
+              throw new CoNLLException("Erreur de numéro de token de P-HEAD : "
+                      +nohead+" sur l'une des lignes précédentes", noligne);
+            rel = new Relation(TYPE_RELATION_PROJ, units.get(i), units.get(k));
+            if (deprel.isEmpty())
+              throw new CoNLLException("Pas trouvé de P-DEP-REL"
+                      +" sur l'une des lignes précédentes", noligne);
+            rel.putProp(PROP_REL, deprel);
+            corpus.addRelationLue(rel);
+          }
+        }
+      }
+      units.clear();
+      noTokenUnits.clear();
+      noHeads.clear();
+      depRels.clear();
+      noPHeads.clear();
+      pDepRels.clear();
+    }
+    private void finDocument(int noligne) throws IOException {
+      finPhrase(noligne);
+      texte = texte.trim();
+      corpus.setTexte(texte);
+      corpus.addFinParagraphe(texte.length());
+    }
+
+    static class CoNLLException extends IOException {
+      public CoNLLException(String ex, int noligne) {
+        super("Erreur de syntaxe ligne "+noligne+" :\n"+ex);
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersCoNLL.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersTexte.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersTexte.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersTexte.java	(revision 3653)
@@ -0,0 +1,283 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+import java.awt.*;
+import java.io.*;
+import javax.swing.*;
+import javax.swing.text.*;
+import javax.swing.text.rtf.*;
+import visuAnalec.PanneauEditeur;
+import visuAnalec.donnees.*;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public abstract class FichiersTexte {
+  public static void importerTexte(Corpus corpus) {
+    BufferedReader fluxIn = null;
+    File fichier;
+    GCodage codage = new GCodage();
+    if ((fichier = Fichiers.choisirFichier(Commande.OUVRIR,
+            "Choix du corpus", Fichiers.TypeFichier.TEXTE, codage.getContenant())) == null) return;
+    String code = codage.getCode();
+    try {
+      fluxIn = new BufferedReader(new InputStreamReader(new FileInputStream(fichier), code));
+    } catch (UnsupportedEncodingException ex) {
+      JOptionPane.showMessageDialog(null, "Codage de caractères non pris en charge : " + code,
+              "Erreur d'ouverture de fichier texte", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (FileNotFoundException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'ouverture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    }
+    try {
+      corpus.lireTexte(fluxIn);
+    } catch (IOException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } finally {
+      try {
+        if (fluxIn != null) fluxIn.close();
+      } catch (IOException ex) {
+        JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier lu", JOptionPane.ERROR_MESSAGE);
+        return;
+      }
+    }
+  }
+  public static void exporterTexteRTF(PanneauEditeur pEditeur) {
+    FileOutputStream fluxOut = null;
+    FiltreCorrectionRTFOutputStream filtre = null;
+    File fichierCorpus;
+    if ((fichierCorpus = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier texte", Fichiers.TypeFichier.TEXTE_RTF)) == null) return;
+    try {
+      fluxOut = new FileOutputStream(fichierCorpus);
+      filtre = new FiltreCorrectionRTFOutputStream(fluxOut);
+      Document doc = pEditeur.getTexteFormate();
+      RTFEditorKit editeur = new RTFEditorKit();
+      editeur.write(filtre, doc, 0, doc.getLength());
+    } catch (FileNotFoundException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (UnsupportedEncodingException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (IOException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (BadLocationException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } finally {
+      if (fluxOut != null) try {
+          fluxOut.close();
+        } catch (IOException ex) {
+          JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier", JOptionPane.ERROR_MESSAGE);
+        }
+    }
+  }
+
+  private static class FiltreCorrectionRTFOutputStream extends FilterOutputStream {
+    // Note: Windows versions of Word have never supported \cbN, 
+    //but it can be emulated by the control word sequence 
+    // \chshdng0\chcbpatN.
+    private final static char[] CodeCouleurFondcorrect = "\\chshdng0\\chcbpat".toCharArray();
+    private final static char[] CodeUnicodecorrect = "\\'".toCharArray();
+    private int etat;
+    private int[] buffer;
+    private int pt = 0;
+    private FiltreCorrectionRTFOutputStream(OutputStream out) {
+      super(out);
+      pt = etat = 0;
+      buffer = new int[10];
+    }
+    @Override
+    public void write(int car) throws IOException {
+      switch (etat) {
+        case 0:
+          if (car == '\\') {
+            buffer[pt++] = car;
+            etat = 1;
+          } else out.write(car);
+          return;
+        case 1:
+          if (car == 'c') {  // debut d'une couleur de fond : etats 2, 3, 4
+            buffer[pt++] = car;
+            etat = 2;
+          } else if (car == 'u') {  // début d'un caractère unicode non décodé : etats 5, 6
+            buffer[pt++] = car;
+            etat = 5;
+          } else raz(car);
+          return;
+        case 2:
+          if (car == 'b') {
+            buffer[pt++] = car;
+            etat = 3;
+
+          } else raz(car);
+          return;
+        case 3:
+          if (car >= '0' && car <= '9') {
+            buffer[pt++] = car;
+            etat = 4;
+          } else raz(car);
+          return;
+        case 4:
+          if (car >= '0' && car <= '9') buffer[pt++] = car;
+          else correctionCouleurFond(car);
+          return;
+        case 5:
+          if (car >= '0' && car <= '9') {
+            buffer[pt++] = car;
+            etat = 6;
+          } else raz(car);
+          return;
+        case 6:
+          if (car >= '0' && car <= '9') buffer[pt++] = car;
+          else if (car == ' ') etat = 7;
+          else raz(car);
+          return;
+        case 7:
+          if (car == '?') correctionUnicode();
+          else raz(car);
+          return;
+        default:
+          throw new UnsupportedOperationException("Etat " + etat + " non prévu");
+      }
+    }
+    private void raz(int b) throws IOException {
+      for (int pt0 = 0; pt0 < pt; pt0++) out.write(buffer[pt0]);
+      pt = etat = 0;
+      write(b);
+    }
+    private void correctionCouleurFond(int b) throws IOException {
+      for (int c : CodeCouleurFondcorrect) out.write(c);
+      for (int pt0 = 3; pt0 < pt; pt0++) out.write(buffer[pt0]);
+      pt = etat = 0;
+      write(b);
+    }
+    private void correctionUnicode() throws IOException {
+      for (int c : CodeUnicodecorrect) out.write(c);
+      int n = 0;
+      for (int pt0 = 2; pt0 < pt; pt0++) n = 10 * n + (buffer[pt0] - '0');
+      String nhex = Integer.toHexString(n % 256);
+      if (nhex.length() == 1) out.write('0');
+      out.write(nhex.charAt(0));
+      if (nhex.length() == 2) out.write(nhex.charAt(1));
+      pt = etat = 0;
+    }
+  }
+  public static void exporterTexteHTML(PanneauEditeur pEditeur) {
+    FileWriter fluxOut = null;
+//   FiltreCorrectionRTFOutputStream filtre = null;
+    File fichierCorpus;
+    if ((fichierCorpus = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier texte", Fichiers.TypeFichier.TEXTE_HTML)) == null) return;
+    try {
+      fluxOut = new FileWriter(fichierCorpus);
+      Document doc = pEditeur.getTexteFormate();
+      HTMLWriterCorrige htmlWriter = new HTMLWriterCorrige(fluxOut, (StyledDocument) doc);
+      htmlWriter.write();
+    } catch (FileNotFoundException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (UnsupportedEncodingException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (IOException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (BadLocationException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'encodage de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } finally {
+      if (fluxOut != null)
+        try {
+          fluxOut.close();
+        } catch (IOException ex) {
+          JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier", JOptionPane.ERROR_MESSAGE);
+        }
+    }
+  }
+
+  private static class HTMLWriterCorrige extends AbstractWriter {
+    public HTMLWriterCorrige(Writer w, StyledDocument doc) {
+      super(w, doc);
+    }
+    @Override
+    protected void write() throws IOException, BadLocationException {
+      write("<html>\n");
+      ElementIterator it = getElementIterator();
+      Element elt;
+      it.first();  // le premier (la racine) n'a pas l'info intéressante)
+      if((elt = it.next()) != null) writeTagBody(elt.getAttributes());
+      while(elt!=null) {
+        if (elt.isLeaf()) {
+          writeSpan(elt.getAttributes(), getText(elt));
+        }
+        elt = it.next();
+      }       
+      write("</body>\n");
+      write("</html>\n");
+    }
+    private void writeTagBody(AttributeSet attr) throws IOException {
+      write("<body style=\" ");
+      write("font-family: " + StyleConstants.getFontFamily(attr));
+      write("; font-size: " + StyleConstants.getFontSize(attr) + "pt");
+      write("; font-style: " + (StyleConstants.isItalic(attr) ? "italic" : "normal"));
+      write("; font-weight: " + (StyleConstants.isBold(attr) ? "bold" : "normal"));
+      write("; text-decoration: " + (StyleConstants.isUnderline(attr) ? "underline" : "none"));
+      write("; color: ");
+      writeColor(StyleConstants.getForeground(attr));
+      write("; background-color: ");
+      writeColor(StyleConstants.getBackground(attr));
+      write("\">\n");
+    }
+    private void writeSpan(AttributeSet attr, String texte) throws IOException {
+      write("<span style=\" ");
+      write("; font-style: " + (StyleConstants.isItalic(attr) ? "italic" : ""));
+      write("; font-weight: " + (StyleConstants.isBold(attr) ? "bold" : ""));
+      write("; text-decoration: " + (StyleConstants.isUnderline(attr) ? "underline" : ""));
+      write("; color: ");
+      writeColor(StyleConstants.getForeground(attr));
+      write("; background-color: ");
+      writeColor(StyleConstants.getBackground(attr));
+      write("\">");
+      for(int i=0; i<texte.length(); i++) writeCar(texte.charAt(i));
+      write("</span>\n");
+    }
+    private void writeColor(Color couleur) throws IOException {
+      write('#');
+      String str = Integer.toHexString(couleur.getRed() % 256);
+      if (str.length() == 1) write('0');
+      write(str.charAt(0));
+      if (str.length() == 2) write(str.charAt(1));
+      str = Integer.toHexString(couleur.getGreen() % 256);
+      if (str.length() == 1) write('0');
+      write(str.charAt(0));
+      if (str.length() == 2) write(str.charAt(1));
+      str = Integer.toHexString(couleur.getBlue() % 256);
+      if (str.length() == 1) write('0');
+      write(str.charAt(0));
+      if (str.length() == 2) write(str.charAt(1));
+    }
+
+  private void writeCar(char car) throws IOException {
+    switch(car) {
+      case '\n': write("<p>"); return;
+      case '"': write("&quot;");return;
+      case'<': write("&lt;");return;
+      case'>': write("&gt;");return;
+      default:
+        if(car>128) write("&#"+(car%256)+";");
+        else write(car);
+    }   
+   }   
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersTexte.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersSyntex.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersSyntex.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersSyntex.java	(revision 3653)
@@ -0,0 +1,152 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class FichiersSyntex {
+  public static void importerSyntex(Corpus corpus) {
+    BufferedReader analyse = null;
+    File fichierCorpus;
+    GCodage codage = new GCodage();
+    if ((fichierCorpus = Fichiers.choisirFichier(Commande.OUVRIR, "Choix du fichier de résultats d'analyse syntaxique",
+            Fichiers.TypeFichier.SYNTEX, codage.getContenant())) == null) return;
+    String code = codage.getCode();
+    int cadence = 1; 
+    try {
+      analyse = new BufferedReader(new InputStreamReader(new FileInputStream(fichierCorpus), code));
+      SyntexParser sp = new SyntexParser(corpus);
+      sp.parser(analyse, cadence);
+      corpus.newCorpusLu();
+    } catch (IOException ex) {
+      corpus.fermer();
+      JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } finally {
+      try {
+        if (analyse != null) analyse.close();
+      } catch (IOException ex) {
+        JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture du fichier lu", JOptionPane.ERROR_MESSAGE);
+      }
+    }
+  }
+
+  static class SyntexParser {
+    Corpus corpus;
+    String texte;
+    SyntexParser(Corpus corpus) {
+      this.corpus = corpus;
+      texte = "";
+    }
+    private void parser(BufferedReader anasynt, int cadence) throws IOException {
+      String ligne;
+      int natLigne = 0;
+      int nophr = 0;
+      Schema phr = null;
+      String txt = null;
+      while ((ligne = anasynt.readLine()) != null) {
+        if (ligne.trim().isEmpty()) continue;
+        switch (natLigne) {
+          case 0:
+            phr = parserSEQ(ligne);
+            break;
+          case 1:
+            txt = parserTXT(ligne);
+            texte += txt;
+            corpus.addFinParagraphe(texte.length());
+            break;
+          case 2:
+            if (++nophr % cadence == 0) {
+              parserETIQ(ligne, phr, texte.length() - txt.length());
+            }
+            break;
+        }
+        natLigne = ++natLigne % 3;
+      }
+      if (natLigne > 0) throw new IOException("Fin de fichier prématurée");
+      corpus.setTexte(texte);
+    }
+    private Schema parserSEQ(String ligne) throws IOException {
+      if (!ligne.startsWith("<SEQ id=")) throw new IOException("SEQ attendu ligne :\n" + ligne);
+      Schema phr = new Schema("Phrase");
+      phr.putProp("id", ligne.substring(8, ligne.indexOf(';')));
+      return phr;
+    }
+    private String parserTXT(String ligne) throws IOException {
+      if (!ligne.startsWith("<TXT>")) throw new IOException("TXT attendu ligne :\n" + ligne);
+      return supBlancs(ligne.substring(5));
+    }
+    private String supBlancs(String txt) {
+      return txt.replaceAll("([\\'\\(\\-\\{\\[]) ", "$1").replaceAll(" ([\\.\\,\\-\\)\\%\\}\\]])", "$1");
+    }
+    private void parserETIQ(String ligne, Schema phr, int offset) throws IOException {
+      if (!ligne.startsWith("<ETIQ>")) throw new IOException("ETIQ attendu ligne :\n" + ligne);
+      String[] etiqs = ligne.substring(6).split("\t");
+      Unite[] units = new Unite[etiqs.length];
+      for (int i = 0; i < units.length; i++) units[i] = new Unite();
+      ArrayList<Relation> rels = new ArrayList<Relation>();
+      for (int i = 0; i < units.length; i++) {
+        String[] data = etiqs[i].split("\\|", -1);
+        if (data.length < 5) throw new IOException("Nombre de champs insuffisant pour " + etiqs[i]);
+        if (Integer.parseInt(data[3]) != i + 1) throw new IOException("Problème de numérotation pour " + etiqs[i]);
+        data[2] = supBlancs(data[2]);
+        while (texte.charAt(offset) == ' ') offset++;
+        if (!texte.startsWith(data[2], offset)) throw new IOException("Attendu : " + data[2] +
+                  " au début de la chaîne\n" + texte.substring(offset));
+        units[i].setType(typeSyntex(data[0]));
+        units[i].setDeb(offset);
+        units[i].setFin(offset += data[2].length());
+        units[i].putProp("Catégorie Syntex", data[0]);
+        units[i].putProp("Lemme", data[1]);
+        if (data[4].isEmpty()) continue;
+        String[] ascs = data[4].split(",");
+        for (String asc : ascs) {
+          String[] dataAsc = asc.split(";");
+          int noAsc = Integer.parseInt(dataAsc[1]);
+          if (noAsc <= 0 || noAsc > units.length)
+            throw new IOException("Problème de numérotation pour l'ascendant de " + etiqs[i]);
+          Relation rel = new Relation("Dépendance", units[i], units[noAsc - 1]);
+          rel.putProp("Fonction syntex", dataAsc[0]);
+          rels.add(rel);
+        }
+      }
+      for (Unite unit : units) {
+        corpus.addUniteLue(unit);
+        phr.ajouter(unit);
+      }
+      for (Relation rel : rels) {  
+        corpus.addRelationLue(rel);
+        phr.ajouter(rel);
+      }
+      corpus.addSchemaLu(phr);
+    }
+    private String typeSyntex(String catSyntex) throws IOException {
+      if (catSyntex.startsWith("Adj")) return "Adjectif";
+      if (catSyntex.startsWith("Adv")) return "Adverbe";
+      if (catSyntex.startsWith("CCoord") || catSyntex.startsWith("TypoCoord")) return "Coordonnant";
+      if (catSyntex.equals("CSub")) return "Subordonnant";
+      if (catSyntex.startsWith("Det")) return "Déterminant";
+      if (catSyntex.equals("Elim")) return "Interjection";
+      if (catSyntex.startsWith("Nom") || catSyntex.equals("NUM")) return "Nom";
+      if (catSyntex.startsWith("Pp") || catSyntex.startsWith("V")) return "Verbe";
+      if (catSyntex.startsWith("Prep")) return "Préposition";
+      if (catSyntex.equals("Pro")) return "Pronom";
+      if (catSyntex.equals("ProRel")) return "Relatif";
+      if (catSyntex.equals("Typo")) return "Ponctuation";
+      throw new IOException("Catégorie syntex non reconnue : " + catSyntex);
+    }
+  }
+}
+  

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersSyntex.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersTableur.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersTableur.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersTableur.java	(revision 3653)
@@ -0,0 +1,165 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.table.TableModel;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.texte.PanneauOccurrences;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class FichiersTableur {
+  public static void importerExcel(Corpus corpus) {
+    BufferedReader enonces = null;
+    BufferedReader annot = null;
+    File fichierCorpus;
+    File fichierAnnot;
+    if ((fichierCorpus = Fichiers.choisirFichier(Commande.OUVRIR,
+            "Choix du fichier des énoncés", Fichiers.TypeFichier.TABLEUR_ENONCES))==null)
+      return;
+    if ((fichierAnnot = Fichiers.choisirFichier(Commande.OUVRIR,
+            "Choix du fichier des annotations", Fichiers.TypeFichier.TABLEUR_ANNOT))==null)
+      return;
+    try {
+      enonces = new BufferedReader(new InputStreamReader(new FileInputStream(fichierCorpus), "ISO-8859-1"));
+      annot = new BufferedReader(new InputStreamReader(new FileInputStream(fichierAnnot), "ISO-8859-1"));
+      ExcelParser ep = new ExcelParser(corpus);
+      corpus.setTexte(ep.parserEnonces(enonces, 2));
+      ep.parserAnnot(annot, 2, "<*", "*>");
+      corpus.newCorpusLu();
+    } catch (IOException ex) {
+      corpus.fermer();
+      GMessages.impossibiliteAction("Erreur de lecture de fichier : \n"
+              +ex.getLocalizedMessage());
+      return;
+    } finally {
+      try {
+        if (enonces!=null) enonces.close();
+        if (annot!=null) annot.close();
+      } catch (IOException ex) {
+        GMessages.impossibiliteAction("Erreur de fermeture du fichier lu : \n"
+                +ex.getLocalizedMessage());
+      }
+    }
+  }
+  public static void exporterTable(TableModel donnees) {
+    PrintWriter ecrittableur = null;
+    File fichierStats;
+    GCodage codage = new GCodage();
+    if ((fichierStats = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier ?", Fichiers.TypeFichier.TABLEUR_STATS,
+            codage.getContenant()))==null) return;
+    String code = codage.getCode();
+    try {
+      ecrittableur = new PrintWriter(fichierStats, code);
+      ecrireTable(ecrittableur, donnees);
+    } catch (FileNotFoundException ex) {
+      GMessages.impossibiliteAction("Erreur d'écriture de fichier : \n"
+              +"Codage de caractères non pris en charge : "+code);
+    } catch (UnsupportedEncodingException ex) {
+    } finally {
+      if (ecrittableur!=null) ecrittableur.close();
+    }
+  }
+  private static void ecrireTable(PrintWriter ecrittableur, TableModel donnees) {
+    int nbcol = donnees.getColumnCount();
+    for (int j = 0; j<nbcol; j++) {
+      ecrittableur.print(donnees.getColumnName(j));
+      ecrittableur.print(j==nbcol-1 ? '\n' : '\t');
+    }
+    int nblig = donnees.getRowCount();
+    for (int i = 0; i<nblig; i++) for (int j = 0; j<nbcol; j++) {
+        ecrittableur.print(donnees.getValueAt(i, j));
+        ecrittableur.print(j==nbcol-1 ? '\n' : '\t');
+      }
+
+  }
+
+  static class ExcelParser {
+    Corpus corpus;
+    HashMap<String, Unite> enonces;
+    ExcelParser(Corpus corpus) {
+      this.corpus = corpus;
+      this.enonces = new HashMap<String, Unite>();
+    }
+    private String parserEnonces(BufferedReader lEnonces, int nbPropEnonces) throws IOException {
+      String texte = "";
+      String lEnonce;
+      int nbcar = 0;
+      while ((lEnonce = lEnonces.readLine())!=null) {
+        if (lEnonce.trim().isEmpty()) continue;
+        String[] chs = lEnonce.split("\t");
+        if (chs.length!=2+nbPropEnonces) {
+          throw new IOException("Format incorrect de fichier d'énoncés ligne : \n"+lEnonce);
+        }
+        String idEnonce = chs[0].trim();
+        if (enonces.containsKey(idEnonce)) {
+          throw new IOException("Identifant d'énoncés non unique  : "+idEnonce);
+        }
+        String texteEnonce = chs[1].trim();
+        Unite enonce = new Unite("Enoncé", nbcar, nbcar += texteEnonce.length());
+        for (int i = 0; i<nbPropEnonces; i++) {
+          enonce.putProp("Propriété "+i, chs[i+2].trim());
+        }
+        enonces.put(idEnonce, enonce);
+        enonce.putProp("id", idEnonce);
+        corpus.addUniteLue(enonce);
+        corpus.addFinParagraphe(nbcar);
+        texte += texteEnonce;
+      }
+      return texte;
+    }
+    private void parserAnnot(BufferedReader lAnnots, int nbPropAnnots, String bGauche, String bDroite)
+            throws IOException {
+      String lAnnot;
+      while ((lAnnot = lAnnots.readLine())!=null) {
+        if (lAnnot.trim().isEmpty()) continue;
+        String[] chs = lAnnot.split("\t", -1);
+        if (chs.length!=2+nbPropAnnots) {
+          throw new IOException("Format incorrect de fichier d'énoncés ligne : \n"+lAnnot);
+        }
+        String idEnonce = chs[0].trim();
+        String texteEnonceAnnot = chs[1].trim();
+        if (!enonces.containsKey(idEnonce)) {
+          throw new IOException("Identifiant d'énoncés non trouvé : \n"+idEnonce);
+        }
+        int deb = texteEnonceAnnot.indexOf(bGauche);
+        if (texteEnonceAnnot.substring(deb+bGauche.length()).indexOf(bGauche)>=0) {
+          throw new IOException("Plusieurs bornes gauches dans : \n"+texteEnonceAnnot);
+        }
+        String texteEnonce = texteEnonceAnnot.replace(bGauche, "");
+        int fin = texteEnonce.indexOf(bDroite);
+        if (texteEnonce.substring(fin+bDroite.length()).indexOf(bDroite)>=0) {
+          throw new IOException("Plusieurs bornes droites dans : \n"+texteEnonceAnnot);
+        }
+        if (fin<=deb) {
+          throw new IOException("Borne droite précédant la borne gauche dans : \n"+texteEnonceAnnot);
+        }
+        texteEnonce = texteEnonce.replace(bDroite, "");
+        Unite enonce = enonces.get(idEnonce);
+        if (!texteEnonce.equals(corpus.getTexte().substring(enonce.getDeb(), enonce.getFin()))) {
+          throw new IOException("Erreur d'énoncé identifié par "+idEnonce+" : \n"+texteEnonceAnnot
+                  +"Enoncé dans le corpus : "+corpus.getTexte().substring(enonce.getDeb(), enonce.getFin()));
+        }
+        Unite marqueur = new Unite("Marqueur", enonce.getDeb()+deb, enonce.getDeb()+fin);
+        for (int i = 0; i<nbPropAnnots; i++) {
+          marqueur.putProp("Propriété "+i, chs[i+2].trim());
+        }
+        corpus.addUniteLue(marqueur);
+        Relation rel = new Relation("Inclusion", marqueur, enonce);
+        corpus.addRelationLue(rel);
+
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/fichiers/FichiersTableur.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/Fichiers.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/Fichiers.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/Fichiers.java	(revision 3653)
@@ -0,0 +1,327 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.util;
+
+import java.awt.*;
+import java.beans.*;
+import java.io.*;
+import java.util.*;
+import java.util.prefs.Preferences;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.filechooser.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public abstract class Fichiers {
+  public enum TypeFichier {
+    DOC_ANALEC("Document Analec", "ec"),
+    CORPUS_ANALEC("Fichiers Analec", "ec"),
+    STRUCTURE("Structure Analec", "ecs"),
+    VUE("Vue Analec", "ecv"),
+    TABLEUR_STATS("Tableur format texte (séparateur : tabulation)", "txt"),
+    GRAPHIQUE_SVG("Graphique vectoriel format svg", "svg"),
+    GRAPHIQUE_EMF("Graphique vectoriel format emf", "emf"),
+    GLOZZ_CORPUS("Corpus Glozz", "ac"),
+    GLOZZ_ANNOT("Annotations Glozz", "aa"),
+    GLOZZ_MODELE("Modèle Glozz", "aam"),
+    SYNTEX("Résultats Syntex", "anasynt"),
+    TABLEUR_ENONCES("Table des énoncés", "txt"),
+    TABLEUR_ANNOT("Table des annotations", "txt"),
+    TEI("Corpus format TEI", "xml"),
+    RHAPS("Corpus Rhapsodie format tabulaire", "tabular"),
+    CONLL("Document format CoNLL", "out"),
+    TEXTE("Texte brut", "txt"),
+    TEXTE_RTF("Texte format RTF", "rtf"),
+    TEXTE_HTML("Texte format HTML", "html");
+    String ext;
+    String nom;
+    TypeFichier(String nom, String ext) {
+      this.nom = nom;
+      this.ext = ext;
+    }
+    public String getNom() {
+      return nom;
+    }
+    public String getExtension() {
+      return ext;
+    }
+    public boolean importCorpus() {
+      return EnumSet.of(TypeFichier.TEXTE, TypeFichier.GLOZZ_CORPUS, TypeFichier.SYNTEX).contains(this);
+    }
+    public boolean resultats() {
+      return EnumSet.of(TypeFichier.TABLEUR_STATS, TypeFichier.GRAPHIQUE_SVG, TypeFichier.GRAPHIQUE_EMF).contains(this);
+    }
+  }
+
+  public enum Commande {
+    OUVRIR("Ouvrir"),
+    ENREGISTRER("Enregistrer");
+    String label;
+    Commande(String label) {
+      this.label = label;
+    }
+    public String getLabel() {
+      return label;
+    }
+  }
+
+  public static class FiltreExt implements java.io.FileFilter {
+    private TypeFichier type;
+    public FiltreExt(TypeFichier type) {
+      this.type = type;
+    }
+    public boolean accept(File fic) {
+      return type.getExtension().equals(getExtension(fic));
+    }
+  }
+  // Variables de classe
+  private static Preferences pref = Preferences.userNodeForPackage(Fichiers.class);
+  private static File repertoireCourantCorpus = new File(pref.get("repertoire", System.getProperty("user.dir")));
+  private static EnumMap<TypeFichier, File> fichiersCourants = new EnumMap<TypeFichier, File>(TypeFichier.class);
+  static {
+    String nomfic = pref.get("nomCorpus", "");
+    if (!nomfic.isEmpty())
+      fichiersCourants.put(TypeFichier.DOC_ANALEC, new File(repertoireCourantCorpus, nomfic+'.'+TypeFichier.DOC_ANALEC.getExtension()));
+  }
+  public static File trouverFichier(TypeFichier type, String nomFichier) {
+    File fichier = new File(repertoireCourantCorpus, nomFichier);
+    if (!getExtension(fichier).equals(type.getExtension()))
+      fichier = changerExtension(fichier, type.getExtension());
+    if (!fichier.exists()) return null;
+    majFichiersCourants(type, fichier);
+    return fichier;
+  }
+  public static File trouverFichier(TypeFichier type, File oldfichier) {
+    File fichier = changerExtension(oldfichier, type.getExtension());
+    if (!fichier.exists()) return null;
+    majFichiersCourants(type, fichier);
+    return fichier;
+  }
+  public static File creerFichier(File rep, TypeFichier type, File oldfichier) {
+    return ajouterExtension(new File(rep, extraireNom(oldfichier)), type.getExtension());
+  }
+  public static File creerFichier(File rep, TypeFichier type, String nom) {
+    return ajouterExtension(new File(rep, nom), type.getExtension());
+  }
+  public static File getRepertoireCourant(TypeFichier type) {
+    if (fichiersCourants.containsKey(type))
+      return fichiersCourants.get(type).getParentFile();
+    return repertoireCourantCorpus;
+  }
+  public static File getFichierCourant(TypeFichier type) {
+    if (fichiersCourants.containsKey(type)) return fichiersCourants.get(type);
+    return null;
+  }
+  public static String getNomFichierCourant(TypeFichier type) {
+    if (fichiersCourants.containsKey(type))
+      return extraireNom(fichiersCourants.get(type));
+    return "";
+  }
+  public static void removeFichierCourant(TypeFichier type) {
+    fichiersCourants.remove(type);
+  }
+  private static void majFichiersCourants(TypeFichier type, File fichier) {
+    fichiersCourants.put(type, fichier);
+    if (type==TypeFichier.GLOZZ_CORPUS) {
+      fichiersCourants.put(TypeFichier.GLOZZ_ANNOT, changerExtension(fichier, TypeFichier.GLOZZ_ANNOT.ext));
+      fichiersCourants.put(TypeFichier.GLOZZ_MODELE, changerExtension(fichier, TypeFichier.GLOZZ_MODELE.ext));
+    }
+    if (type==TypeFichier.DOC_ANALEC) {
+      repertoireCourantCorpus = fichier.getParentFile();
+      pref.put("repertoire", repertoireCourantCorpus.getPath());
+      pref.put("nomCorpus", extraireNom(fichier));
+    }
+
+  }
+  // Utilitaires de manipulation de noms de fichiers
+  private static File ajouterExtension(File fichier, String extension) {
+    String nom = fichier.getName();
+    return new File(fichier.getParentFile(), nom+"."+extension);
+  }
+  private static File changerExtension(File fichier, String extension) {
+    String nom = fichier.getName();
+    int ind = nom.lastIndexOf('.');
+    if (ind>=0) nom = nom.substring(0, ind);
+    return new File(fichier.getParentFile(), nom+"."+extension);
+  }
+  public static String extraireNom(File fichier) {
+    if (fichier==null) return null;
+    String nom = fichier.getName();
+    int ind = nom.lastIndexOf('.');
+    if (ind<0) return nom;
+    else return nom.substring(0, ind);
+  }
+  private static String getExtension(File fichier) {
+    String nom = fichier.getName();
+    int ind = nom.lastIndexOf('.');
+    if (ind>=0) return nom.substring(ind+1);
+    return "";
+  }
+  public static File[] listerFichiers(File rep, TypeFichier type) {
+    return rep.listFiles(new FiltreExt(type));
+  }
+  public static boolean existeDebutFichier(File rep, TypeFichier type, 
+          String debut) {
+    File[] fics = listerFichiers(rep, type);
+    for (int i = 0; i<fics.length; i++) 
+      if(extraireNom(fics[i]).startsWith(debut)) return true;
+    return false;
+  }
+  // Choix des fichiers
+  public static File choisirFichier(Commande commande, String titre, TypeFichier type) {
+    return choisirFichier(commande, titre, type, null);
+  }
+  public static File choisirFichier(Commande commande, String titre, TypeFichier type, JComponent complement) {
+    JFileChooser choixFichier = new JFileChooser();
+    choixFichier.resetChoosableFileFilters();
+    choixFichier.setFileFilter(new FileNameExtensionFilter(type.getNom(), type.getExtension()));
+    choixFichier.setDialogTitle(titre);
+    if (complement!=null) choixFichier.setAccessory(complement);
+    choixFichier.setCurrentDirectory(getRepertoireCourant(type));
+    File fichierPropose;
+    if (type.resultats()) {
+      String nom = extraireNom(getFichierCourant(TypeFichier.DOC_ANALEC));
+      if (nom==null) fichierPropose = null;
+      else fichierPropose = new File(getRepertoireCourant(type), nom+"_res");
+    } else {
+      fichierPropose = getFichierCourant(type);
+    }
+    if (fichierPropose!=null) {
+      if (commande==Commande.OUVRIR&&!fichierPropose.exists()) {
+        fichierPropose = new File(getRepertoireCourant(type), "*."+type.getExtension());
+      }
+      choixFichier.setSelectedFile(fichierPropose);
+    }
+    int reponse = choixFichier.showDialog(null, commande.getLabel());
+    if (reponse!=JFileChooser.APPROVE_OPTION) return null;
+    File fichierChoisi = choixFichier.getSelectedFile();
+    if (commande==Commande.ENREGISTRER) {
+      if (!getExtension(fichierChoisi).equals(type.getExtension()))
+        fichierChoisi = ajouterExtension(fichierChoisi, type.getExtension());
+      if (fichierChoisi.exists()) {
+        int rep = JOptionPane.showOptionDialog(null, "Remplacer "+fichierChoisi.getName()+" ?",
+                "Fichier existant", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+                null, new Object[]{"Remplacer", "Annuler"}, "Remplacer");
+        if (rep==1) return null;
+      }
+    }
+    majFichiersCourants(type, fichierChoisi);
+    if (commande==Commande.OUVRIR&&type.importCorpus())
+      fichiersCourants.remove(TypeFichier.DOC_ANALEC);
+    return fichierChoisi;
+  }
+  public static File choisirRepertoire(String titre) {
+    JFileChooser choixRep = new JFileChooser();
+    choixRep.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+    choixRep.setAcceptAllFileFilterUsed(false);
+    choixRep.setFileFilter(new FileNameExtensionFilter("Répertoire", "*"));
+    choixRep.setDialogTitle(titre);
+    choixRep.setCurrentDirectory(repertoireCourantCorpus);
+    int reponse = choixRep.showDialog(null, "Sélectionner");
+    if (reponse!=JFileChooser.APPROVE_OPTION) return null;
+    return choixRep.getSelectedFile();
+  }
+  public static File[] choisirCorpus(String titre, TypeFichier type) {
+    JFileChooser choixFichier = new JFileChooser();
+    FilesystemFilter filtre = new FilesystemFilter(type.getExtension(), "", false);
+    choixFichier.addPropertyChangeListener(new SelectFics(choixFichier, filtre));
+    choixFichier.resetChoosableFileFilters();
+    choixFichier.setFileFilter(new FileNameExtensionFilter(
+            type.getNom(), type.getExtension()));
+    choixFichier.setDialogTitle(titre);
+    choixFichier.setMultiSelectionEnabled(true);
+    File rep = getRepertoireCourant(type);
+    choixFichier.setCurrentDirectory(rep);
+    int reponse = choixFichier.showDialog(null, "Choisir");
+    if (reponse!=JFileChooser.APPROVE_OPTION) return new File[0];
+    File[] fics = choixFichier.getSelectedFiles();
+    if (fics==null||fics.length==0) return new File[0];
+    majFichiersCourants(TypeFichier.CORPUS_ANALEC, fics[0]);
+    return fics;
+  }
+
+  static class FilesystemFilter extends javax.swing.filechooser.FileFilter
+          implements FilenameFilter {
+    private String[] extensions;
+    private String description;
+    private boolean accepteReps;
+    public FilesystemFilter(String extension, String description,
+            boolean accepteReps) {
+      this(new String[]{extension}, description, accepteReps);
+    }
+    public FilesystemFilter(String[] extensions, String description,
+            final boolean accepteReps) {
+      this.extensions = extensions;
+      this.description = description;
+      this.accepteReps = accepteReps;
+    }
+    public boolean accept(File rep, String nom) {
+      return accept(new File(rep, nom));
+    }
+    public boolean accept(final File fic) {
+      if (fic.isDirectory()&&accepteReps) return true;
+      for (int i = 0; i<this.extensions.length; i++)
+        if (fic.getName().endsWith(this.extensions[i])) return true;
+      return false;
+    }
+    public String getDescription() {
+      return this.description;
+    }
+ }
+ public static class SelectFics implements PropertyChangeListener{
+    JFileChooser choix;
+    FilesystemFilter filtre;
+    SelectFics(JFileChooser choix, FilesystemFilter filtre) {
+      this.choix = choix;
+      this.filtre = filtre;
+    }
+    @Override
+       public void propertyChange(PropertyChangeEvent e) {
+        if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(e.getPropertyName())) {
+           choix.setSelectedFiles(choix.getCurrentDirectory().listFiles(filtre));
+        }
+    }
+  }
+
+  public static class GCodage {
+    JPanel contenant;
+    JComboBox saisieCodage;
+    public GCodage() {
+      saisieCodage = new JComboBox(new String[]{
+                "Microsoft (windows-1252)",
+                "UTF-8 (unicode 8 bits)",
+                "UTF-16 (unicode 16 bits)",
+                "ISO-8859-1 (latin-1)",
+                "<autre (à saisir)>"
+              });
+      saisieCodage.setEditable(true);
+      saisieCodage.setSelectedIndex(0);
+      contenant = new JPanel(new BorderLayout());
+      contenant.setBorder(new TitledBorder("Codage des caractères"));
+      contenant.add(saisieCodage, BorderLayout.NORTH);
+      contenant.add(new JPanel(), BorderLayout.CENTER);
+    }
+    public JComponent getContenant() {
+      return contenant;
+    }
+    public String getCode() {
+      switch (saisieCodage.getSelectedIndex()) {
+        case 0:
+          return "windows-1252";
+        case 1:
+          return "UTF-8";
+        case 2:
+          return "UTF-16";
+        case 3:
+          return "ISO-8859-1";
+        default:
+          return (String) saisieCodage.getSelectedItem();
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/Fichiers.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/GVisu.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/GVisu.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/GVisu.java	(revision 3653)
@@ -0,0 +1,512 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.util;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.util.ArrayList;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.GMessages.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public abstract class GVisu {
+  public static class TitreBarre extends JLabel {
+    public TitreBarre(String titre) {
+      super(titre);
+    }
+    public TitreBarre(String titre, Color couleur) {
+      super(titre);
+      setOpaque(true);
+      setBackground(couleur);
+    }
+  }
+
+  public static abstract class Boutons {
+    public static void setDefaut(JButton bouton, boolean oui) {
+      ((JFrame) bouton.getTopLevelAncestor()).getRootPane().setDefaultButton(oui ? bouton : null);
+      if (oui) bouton.requestFocusInWindow();
+    }
+  }
+  public static String styleIdPopup(String texte, String id) {
+    if (texte.length()>35)
+      texte = texte.substring(0, 18)+" [...] "+texte.substring(texte.length()-8);
+    return "<html>"+id+" (<span style=\"font-style:italic \">"+texte+"</span>)";
+  }
+  public static String styleIdTooltip(ArrayList<String> textes, ArrayList<String> ids) {
+    String tooltip = "<html>";
+    for (int i = 0; i<textes.size(); i++) {
+      String texte = textes.get(i);
+      if (texte.length()>35)
+        texte = texte.substring(0, 18)+" [...] "+texte.substring(texte.length()-8);
+      tooltip += "<p>"+ids.get(i)+" (<span style=\"font-style:italic \">"+texte+"</span>)";
+    }
+    return tooltip;
+  }
+  public static String styleDef(String nom) {
+    return "<html><span style=\"color:gray\"> &lt <span style=\"font-style:italic \">"
+            +nom+"</span> &gt";
+  }
+  private final static Font STYLE_COMBO = Font.decode("Arial plain 12");
+
+  public enum SensSpinnerBinaire {
+    SUIVANT, PRECEDENT
+  }
+
+  public static class ModeleSpinnerBinaire extends AbstractSpinnerModel {
+    private SensSpinnerBinaire sens;
+    public Object getValue() {
+      return sens;
+    }
+    public void setValue(Object value) {
+      sens = (SensSpinnerBinaire) value;
+      fireStateChanged();
+    }
+    public Object getNextValue() {
+      return SensSpinnerBinaire.PRECEDENT;
+    }
+    public Object getPreviousValue() {
+      return SensSpinnerBinaire.SUIVANT;
+    }
+  }
+  private static Dimension dimZero = new Dimension(20, 20);
+  private static Insets insetsZero = new Insets(0, 0, 0, 0);
+
+  public static class ElementComboBox extends Box implements ActionListener, ChangeListener {
+    private ArrayList<ActionListener> listeCorrespondants = new ArrayList<ActionListener>();
+    public JComboBox combo;
+    private JButton zero;
+    private JSpinner spin;
+    public Element[] elements;  // liste triée
+    public ElementComboBox() {
+      super(BoxLayout.X_AXIS);
+      zero = new JButton(new GAction("0") {
+        public void executer() {
+          effSelection();
+        }
+      });
+      zero.setMargin(insetsZero);
+      zero.setPreferredSize(dimZero);
+      spin = new JSpinner(new ModeleSpinnerBinaire());
+      spin.setEditor(new JLabel());
+      spin.addChangeListener(this);
+      combo = new JComboBox();
+      combo.setEditable(false);
+      combo.setFont(STYLE_COMBO);
+      combo.addActionListener(this);
+      add(combo);
+      add(spin);
+      add(zero);
+      setModeleVide();
+    }
+    public void addActionListener(ActionListener correspondant) {
+      listeCorrespondants.add(correspondant);
+    }
+    public void removeActionListener(ActionListener correspondant) {
+      listeCorrespondants.remove(correspondant);
+    }
+    public void actionPerformed(ActionEvent evt) {
+      try {
+        evt.setSource(this);
+        for (Object corresp : listeCorrespondants.toArray()) {
+          ((ActionListener) corresp).actionPerformed(evt);
+        }
+      } catch (Throwable ex) {
+        GMessages.erreurFatale(ex);
+      }
+    }
+    public void setModeleVide() {
+      combo.setModel(new DefaultComboBoxModel(new String[]{styleDef("identifiant")}));
+      elements = new Element[0];
+      setMaximumSize(getPreferredSize());
+    }
+    public void setModele(Element[] elts, String[] ids) {
+      // elts doit être trié et en correspondance avec ids
+      combo.setModel(new DefaultComboBoxModel(Tableaux.insererStringEnTete(ids, styleDef("identifiant"))));
+      elements = elts;
+      setMaximumSize(getPreferredSize());
+    }
+    public Element[] getElements() {
+      return elements;
+    }
+    public void gotoPrecedent() {
+      int index;
+      if ((index = combo.getSelectedIndex())==0) index = combo.getItemCount();
+      combo.setSelectedIndex(index-1);
+    }
+    public void gotoSuivant() {
+      int index = combo.getSelectedIndex()+1;
+      if (index==combo.getItemCount()) index = 0;
+      combo.setSelectedIndex(index);
+    }
+    public boolean pasdeSelection() {
+      return combo.getSelectedIndex()<1;
+    }
+    public Element getSelection() {
+      if (combo.getSelectedIndex()>0)
+        return elements[combo.getSelectedIndex()-1];
+      return null;
+    }
+    public void effSelection() {
+      combo.setSelectedIndex(0);
+    }
+    public void setSelection(Element elt) {
+      int no = Arrays.binarySearch(elements, elt);
+      if (no<0)
+        throw new ArrayIndexOutOfBoundsException("Element à sélectionner absent");
+      combo.setSelectedIndex(no+1);
+    }
+    public String getIdElement(Element elt) {
+      int no = Arrays.binarySearch(elements, elt);
+      if (no<0)
+        throw new ArrayIndexOutOfBoundsException("Element recherché absent");
+      return ((String) combo.getItemAt(no+1));
+
+    }
+    public void stateChanged(ChangeEvent e) {
+      try {
+        switch ((SensSpinnerBinaire) spin.getValue()) {
+          case SUIVANT:
+            gotoSuivant();
+            return;
+          case PRECEDENT:
+            gotoPrecedent();
+            return;
+        }
+      } catch (Throwable ex) {
+        GMessages.erreurFatale(ex);
+      }
+    }
+  }
+
+  public static class Val0ComboBox extends JComboBox {
+    private String[] vals;
+    private String val0;
+    public Val0ComboBox(String val0) {
+      super();
+      this.val0 = val0;
+      setEditable(false);
+      setFont(STYLE_COMBO);
+      setModeleVide();
+    }
+    public void setModeleVide() {
+      setModel(new DefaultComboBoxModel(new String[]{styleDef(val0)}));
+      vals = new String[0];
+      setMaximumSize(getPreferredSize());
+    }
+    public void setModele(String[] types) {
+      setModel(new DefaultComboBoxModel(Tableaux.insererStringEnTete(types, styleDef(val0))));
+      this.vals = types;
+      setMaximumSize(getPreferredSize());
+    }
+    public boolean pasdeSelection() {
+      return getSelectedIndex()<1;
+    }
+    public int nbItems() {
+      return vals.length;
+    }
+    public String getSelection() {
+      if (getSelectedIndex()>0) return vals[getSelectedIndex()-1];
+      return null;
+    }
+    public void effSelection() {
+      setSelectedIndex(0);
+    }
+    public void setSelection(String type) {
+      setSelectedItem(type);
+    }
+    public void setSelection(int i) {
+      setSelectedIndex(i+1);
+    }
+  }
+  public static String getNomClasse(Class<? extends Element> classe) {
+    if (classe==Element.class) return "élément";
+    else if (classe==Unite.class) return "unité";
+    else if (classe==Relation.class) return "relation";
+    else if (classe==Schema.class) return "schéma";
+    else
+      throw new UnsupportedOperationException("Sous-classe inconnue pour getNomClasse()");
+  }
+  public static String getNomDeClasse(Class<? extends Element> classe) {
+    if (classe==Element.class) return "d'élément";
+    else if (classe==Unite.class) return "d'unité";
+    else if (classe==Relation.class) return "de relation";
+    else if (classe==Schema.class) return "de schéma";
+    else
+      throw new UnsupportedOperationException("Sous-classe inconnue pour getNomTypedeClasse()");
+  }
+  public static String getNomDeLaClasse(Element elt) {
+    Class<? extends Element> classe = elt.getClass();
+    if (classe==Unite.class) return "de l'unité";
+    else if (classe==Relation.class) return "de la relation";
+    else if (classe==Schema.class) return "du schéma";
+    else
+      throw new UnsupportedOperationException("Sous-classe inconnue pour getNomTypedeClasse()");
+  }
+  public static Class<? extends Element> getClasse(String classeType) {
+    if (classeType==null) return null;
+    if (classeType.startsWith("REL-")) return Relation.class;
+    if (classeType.startsWith("SCH-")) return Schema.class;
+    return Unite.class;
+  }
+  public static String getType(String classeType) {
+    if (classeType==null) return null;
+    if (classeType.startsWith("REL-")) return classeType.substring(4);
+    if (classeType.startsWith("SCH-")) return classeType.substring(4);
+    return classeType;
+  }
+  private static String getClasseType(Class<? extends Element> classe, String type) {
+    if (classe==Unite.class) return type;
+    else if (classe==Relation.class) return "REL-"+type;
+    else if (classe==Schema.class) return "SCH-"+type;
+    else
+      throw new UnsupportedOperationException("Sous-classe inconnue pour getClasseType()");
+  }
+  public static String[] getClassesTypes(String[] typesUnit, String[] typesRel, String[] typesSch) {
+    String[] types = Arrays.copyOf(typesUnit, typesUnit.length+typesRel.length+typesSch.length);
+    for (int i = 0; i<typesRel.length; i++)
+      types[i+typesUnit.length] = "REL-"+typesRel[i];
+    for (int i = 0; i<typesSch.length; i++)
+      types[i+typesUnit.length+typesRel.length] = "SCH-"+typesSch[i];
+    return types;
+  }
+
+  public static class TypeComboBox extends Val0ComboBox {
+    private Class<? extends Element> classe;
+    public TypeComboBox(Class<? extends Element> classe) {
+      super("type "+getNomDeClasse(classe));
+      this.classe = classe;
+    }
+    @Override
+    public void setModele(String[] types) {
+      if (this.classe==Element.class)
+        throw new UnsupportedOperationException("pas pour la classe Element");
+      super.setModele(types);
+    }
+    public void setModele(String[] typesUnites, String[] typesRelations, String[] typesSchemas) {
+      if (this.classe!=Element.class)
+        throw new UnsupportedOperationException("uniquement pour la classe Element");
+      super.setModele(getClassesTypes(typesUnites, typesRelations, typesSchemas));
+    }
+    public String getTypeSelection() {
+      String classetype = getSelection();
+      if (classetype==null) return null;
+      if (classe==Element.class) return getType(classetype);
+      return classetype;
+    }
+    public Class<? extends Element> getClasseSelection() {
+      String classetype = getSelection();
+      if (classetype==null) return null;
+      if (classe==Element.class) return getClasse(classetype);
+      return classe;
+    }
+    public void setSelection(Class<? extends Element> classe, String type) {
+      if (this.classe!=Element.class)
+        throw new UnsupportedOperationException("uniquement pour la classe Element");
+      super.setSelection(getClasseType(classe, type));
+    }
+    @Override
+    public void setSelection(String type) {
+      if (this.classe==Element.class)
+        throw new UnsupportedOperationException("pas pour la classe Element");
+      super.setSelection(type);
+    }
+  }
+  private final static Color[] couleursEtNoirEtBlanc = new Color[]{Color.BLACK, Color.WHITE, Color.YELLOW,
+    Color.RED, Color.BLUE, Color.ORANGE, Color.GREEN, Color.CYAN, Color.MAGENTA, Color.PINK
+  };
+  private final static Color[] couleurs = new Color[]{Color.YELLOW, Color.RED, Color.BLUE,
+    Color.ORANGE, Color.GREEN, Color.CYAN, Color.MAGENTA, Color.PINK
+  };
+  public static Color[] getCouleursEtNoirEtBlanc() {
+    return couleursEtNoirEtBlanc;
+  }
+  public static Color getCouleur(int i) {
+    Color c = couleurs[i%couleurs.length];
+    for (int n = 0; n<i/couleurs.length; n++) {
+      float[] rgb = c.getRGBColorComponents(null);
+      c = new Color(0.499f+rgb[0]/3, 0.499f+rgb[1]/3, 0.499f+rgb[2]/3);
+    }
+    return c;
+  }
+  public static Color getCouleurSansValeur() {
+    return Color.LIGHT_GRAY;
+  }
+
+  public static class DisqueCouleurIcone implements Icon {
+    private Color couleur;
+    int rayon;
+    int marge;
+    public DisqueCouleurIcone(Color couleur, int rayon, int marge) {
+      this.couleur = couleur;
+      this.rayon = rayon;
+      this.marge = marge;
+    }
+    public void paintIcon(Component c, Graphics g, int x, int y) {
+      if (couleur==null) {
+        g.setColor(Color.BLACK);
+        g.drawLine(x+3*marge, y+3*marge, x+2*rayon-marge, y+2*rayon-marge);
+        g.drawLine(x+3*marge, y+2*rayon-marge, x+2*rayon-marge, y+3*marge);
+      } else {
+        g.setColor(couleur);
+        g.fillOval(x+marge, y+marge, 2*rayon, 2*rayon);
+        g.setColor(Color.BLACK);
+        g.drawOval(x+marge, y+marge, 2*rayon, 2*rayon);
+      }
+    }
+    public int getIconWidth() {
+      return 2*rayon+2*marge;
+    }
+    public int getIconHeight() {
+      return 2*rayon+2*marge;
+    }
+  }
+
+  public static class LegendeLabel {
+    String texte;
+    Icon icone;
+    public LegendeLabel(String texte, Color couleur) {
+      this.texte = texte;
+      this.icone = new DisqueCouleurIcone(couleur, 6, 2);
+    }
+  }
+
+  public static class LegendeCellRenderer extends JLabel implements ListCellRenderer {
+    public LegendeCellRenderer() {
+      setIconTextGap(12);
+    }
+    public Component getListCellRendererComponent(JList list, Object value,
+            int index, boolean isSelected, boolean cellHasFocus) {
+      LegendeLabel label = (LegendeLabel) value;
+      setText(label.texte);
+      setIcon(label.icone);
+      return this;
+    }
+  }
+
+  public static class RectangleCouleurIcone implements Icon {
+    private Color couleur;
+    private int largeur;
+    private int hauteur;
+    private int marge;
+    private boolean select;
+    public RectangleCouleurIcone(Color couleur, int largeur, int hauteur, int marge, boolean select) {
+      this.couleur = couleur;
+      this.largeur = largeur;
+      this.hauteur = hauteur;
+      this.marge = marge;
+      this.select = select;
+    }
+    void setCouleur(Color c) {
+      couleur = c;
+    }
+    public void paintIcon(Component c, Graphics g, int x, int y) {
+      g.setColor(couleur);
+      g.fillRect(x+marge, y+marge, largeur, hauteur);
+      if (select) {
+        g.setColor(Color.BLACK);
+        g.drawRect(x+marge, y+marge, largeur, hauteur);
+      }
+    }
+    public int getIconWidth() {
+      return largeur+2*marge;
+    }
+    public int getIconHeight() {
+      return hauteur+2*marge;
+    }
+  }
+
+  public static class CouleurCellRenderer extends JLabel implements ListCellRenderer, TableCellRenderer {
+    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
+            boolean cellHasFocus) {
+      if (index==list.getModel().getSize()-1||index<0) {
+        setText(index<0 ? "" : styleDef("autre"));
+        setIcon(null);
+      } else {
+        setText(null);
+        setIcon(new RectangleCouleurIcone((Color) value, 40, 10, 2, isSelected));
+      }
+      return this;
+    }
+    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+      setText(null);
+      setIcon(new RectangleCouleurIcone((Color) value, 80, 10, 2, true));
+      return this;
+    }
+  }
+
+  public static class CouleurComboBoxEditor implements ComboBoxEditor {
+    CouleurComboBox comboBox;
+    RectangleCouleurIcone icone;
+    JLabel editeur;
+    Color couleur;
+    public CouleurComboBoxEditor(CouleurComboBox cb) {
+      comboBox = cb;
+      editeur = new JLabel(icone = new RectangleCouleurIcone(null, 80, 10, 2, true));
+    }
+    public Component getEditorComponent() {
+      return editeur;
+    }
+    private void init(Color couleur) {
+      this.couleur = couleur;
+      icone.setCouleur(couleur);
+    }
+    public void setItem(Object anObject) {
+      if (anObject==null) {
+        Color c = JColorChooser.showDialog(editeur, "Choix de la couleur", couleur);
+        if (c!=null) couleur = c;
+      } else couleur = (Color) anObject;
+      icone.setCouleur(couleur);
+      comboBox.setSelectedItem(couleur);
+    }
+    public Object getItem() {
+      return couleur;
+    }
+    public void selectAll() {
+    }
+    public void addActionListener(ActionListener l) {
+    }
+    public void removeActionListener(ActionListener l) {
+    }
+  }
+
+  public static class CouleurComboBox extends JComboBox {
+    public CouleurComboBox(Color[] couleurs) {
+      super(couleurs);
+      addItem(null);
+      setRenderer(new CouleurCellRenderer());
+      setEditor(new CouleurComboBoxEditor(this));
+      setMaximumRowCount(couleurs.length+1);
+    }
+  }
+
+  public static class CouleurTableEditor extends AbstractCellEditor implements TableCellEditor, ActionListener {
+    private CouleurComboBox comboBox;
+    private Color couleur;
+    public CouleurTableEditor(Color[] couleurs) {
+      comboBox = new CouleurComboBox(couleurs);
+      comboBox.setEditable(true);
+      comboBox.addActionListener(this);
+    }
+    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
+      couleur = (Color) value;
+      comboBox.getEditor().setItem(value);
+      return comboBox;
+    }
+    public Object getCellEditorValue() {
+      return couleur;
+    }
+    public void actionPerformed(ActionEvent e) {
+      couleur = (Color) comboBox.getSelectedItem();
+      fireEditingStopped();
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/GVisu.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/GMessages.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/GMessages.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/GMessages.java	(revision 3653)
@@ -0,0 +1,99 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.util;
+
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class GMessages {
+  public static boolean confirmationAction(String texte) {
+    return (JOptionPane.showConfirmDialog(null, texte, "Confirmation d'action",
+            JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE)
+            !=JOptionPane.CANCEL_OPTION);
+  }
+
+  public static void pasImplemente() {
+    JOptionPane.showMessageDialog(null, "Désolé, cette fonctionnalité n'est pas encore implémentée",
+            "Patience...", JOptionPane.INFORMATION_MESSAGE);
+    return;
+  }
+
+  public static void impossibiliteAction(String texte) {
+    JOptionPane.showMessageDialog(null, texte,
+            "Désolé...", JOptionPane.INFORMATION_MESSAGE);
+    return;
+  }
+
+  public static void erreurFatale(Throwable ex) {
+    String message = "<center><b>Désolé pour ce bug... Vous allez devoir relancer Analec.</b></center>"
+            +"<i><br>Veuillez recopier  le message d'erreur ci-dessous et l'envoyer au concepteur du logiciel"
+            +" <br>en précisant les conditions dans lequel ce bug s'est produit</i>";
+    String erreur = "<p>"+ex.toString();
+    for (StackTraceElement tr : ex.getStackTrace())
+      if (tr.getClassName().startsWith("visuAnalec")||tr.getClassName().startsWith("JamaPlus") )
+        erreur += "<br>"+tr.getClassName()+" : "+tr.getMethodName()+" ligne "+tr.getLineNumber();
+    JEditorPane dialogue = new JEditorPane("text/html", message+erreur);
+    JOptionPane.showMessageDialog(null, dialogue, "Oups !", JOptionPane.ERROR_MESSAGE);
+    //System.exit(1);
+  }
+
+  public abstract static class GAction extends AbstractAction {
+    public GAction(String nom) {
+      super(nom);
+    }
+
+    public GAction(String nom, Icon icone) {
+      super(nom, icone);
+    }
+
+    public abstract void executer();
+
+    public void actionPerformed(ActionEvent evt) {
+      try {
+        executer();
+      } catch (Throwable ex) {
+        erreurFatale(ex);
+      }
+    }
+  }
+
+  public abstract static class GActionClavier extends GAction {
+    public GActionClavier(JComponent composant, String nom, String... touches) {
+      super(nom);
+      for(String touche: touches) {
+        composant.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
+                KeyStroke.getKeyStroke(touche), nom);
+      }
+      composant.getActionMap().put(nom, this);
+    }
+  }
+  public static class GProgression extends ProgressMonitor  {
+    private int compteur;
+    private String elementsTraites;
+
+    public GProgression(int max, String traitement, String elementsTraites) {
+      super(null, traitement + " en cours", "Démarrage", 0, max);
+      this.elementsTraites = elementsTraites;
+//      setMillisToPopup(0);
+      compteur = 0;
+     }
+
+    public void setNbTraites(int nb) {
+      compteur = nb;
+      SwingUtilities.invokeLater(new MiseAJour());
+    }
+
+    class MiseAJour implements Runnable {
+      public void run() {
+        setProgress(compteur);
+        setNote(compteur +" "+ elementsTraites + " traités");
+      }
+    }
+  }
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/GMessages.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/Tableaux.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/Tableaux.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/Tableaux.java	(revision 3653)
@@ -0,0 +1,86 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.util;
+
+import java.util.*;
+import visuAnalec.elements.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public abstract class Tableaux {
+  public static int compterValeursVraies(boolean[] bls) {
+    int nb = 0;
+    for(boolean b: bls) if(b) nb++;
+    return nb;
+  }
+  public static String[] insererString(String[] strs, String str) {
+    // renvoie un tableau trié
+    String[] strs1 = insererStringEnTete(strs, str);
+    Arrays.sort(strs1);
+    return strs1;
+  }
+  public static String[] insererStringEnTete(String[] strs, String str) {
+    String[] strs1 = new String[strs.length + 1];
+    System.arraycopy(strs, 0, strs1, 1, strs.length);
+    strs1[0] = str;
+    return strs1;
+  }
+  static String[] oterString(String[] strs, String str) {
+    // strs doit être triée
+    int ind = Arrays.binarySearch(strs, str);
+    if (ind < 0) return strs;
+    return oterString(strs, ind);
+  }
+  public static String[] oterString(String[] strs, int ind) {
+    String[] strs1 = new String[strs.length - 1];
+    System.arraycopy(strs, 0, strs1, 0, ind);
+    System.arraycopy(strs, ind + 1, strs1, ind, strs.length - ind - 1);
+    return strs1;
+  }
+  public static String[] oterStrings(String[] strs, ArrayList<Integer> inds) {
+    //  inds doit être croissant
+    String[] strs1 = new String[strs.length - inds.size()];
+    inds.add(strs.length);
+    System.arraycopy(strs, 0, strs1, 0, inds.get(0));
+    for (int i = 1; i < inds.size(); i++)
+      System.arraycopy(strs, inds.get(i - 1) + 1, strs1, inds.get(i - 1) - i + 1, inds.get(i) - inds.get(i - 1) - 1);
+    return strs1;
+  }
+//  public static String[][] oterStrings(String[][] strs, ArrayList<Integer> inds1, ArrayList<Integer> inds2) {
+//    //  inds1 et inds2 doivent être de même taille
+//    String[] strs1 = new String[strs.length - inds.size()];
+//    inds.add(strs.length);
+//    System.arraycopy(strs, 0, strs1, 0, inds.get(0));
+//    for (int i = 1; i < inds.size(); i++)
+//      System.arraycopy(strs, inds.get(i - 1) + 1, strs1, inds.get(i - 1) - i + 1, inds.get(i) - inds.get(i - 1) - 1);
+//    return strs1;
+//  }
+  public static Element[] insererElementEnTete(Element[] elts, Element elt) {
+    Element[] elts1 = new Element[elts.length + 1];
+    System.arraycopy(elts, 0, elts1, 1, elts.length);
+    elts1[0] = elt;
+    return elts1;
+  }
+  public static Element[] oterElements(Element[] elts, ArrayList<Integer> inds) {
+    //  inds doit être croissant
+    Element[] elts1 = new Element[elts.length - inds.size()];
+    inds.add(elts.length);
+    System.arraycopy(elts, 0, elts1, 0, inds.get(0));
+    for (int i = 1; i < inds.size(); i++)
+      System.arraycopy(elts, inds.get(i - 1) + 1, elts1, inds.get(i - 1) - i + 1, inds.get(i) - inds.get(i - 1) - 1);
+    return elts1;
+  }
+  public static Relation[] oterRelations(Relation[] elts, ArrayList<Integer> inds) {
+    //  inds doit être croissant
+    Relation[] elts1 = new Relation[elts.length - inds.size()];
+    inds.add(elts.length);
+    System.arraycopy(elts, 0, elts1, 0, inds.get(0));
+    for (int i = 1; i < inds.size(); i++)
+      System.arraycopy(elts, inds.get(i - 1) + 1, elts1, inds.get(i - 1) - i + 1, inds.get(i) - inds.get(i - 1) - 1);
+    return elts1;
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/util/Tableaux.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauCommandesRelations.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauCommandesRelations.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauCommandesRelations.java	(revision 3653)
@@ -0,0 +1,756 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.ArrayList;
+import javax.swing.*;
+import visuAnalec.Message.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.elements.*;
+import visuAnalec.texte.*;
+import visuAnalec.texte.PanneauAffTexte.*;
+import visuAnalec.texte.PanneauTexte.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class PanneauCommandesRelations extends PanneauCommandes implements ActionListener {
+  private PanneauChamps panneauChamps;
+  private TypeComboBox saisieTypeRelations;
+  private ElementComboBox saisieRelation;
+  private TypeComboBox saisieTypeElt1;
+  private ElementComboBox saisieElt1;
+  private TypeComboBox saisieTypeElt2;
+  private ElementComboBox saisieElt2;
+  private JButton creeRelation;
+  private JButton supprimeRelation;
+  private JButton creeUniteElt1;
+  private JButton creeUniteElt2;
+  private boolean uniteCreeElt1 = true; // pour la création d'unités en cours de route
+  private int[] bornesSelectTexte;
+  /*
+  
+   * CREATION PAR LE PANNEAU EDITEUR
+   */
+  PanneauCommandesRelations(Vue vue, PanneauAffTexte pTexte, PanneauChamps pChamps) {
+    super(vue, pTexte);
+    JToolBar barre1 = new JToolBar();
+    barre1.setPreferredSize(new Dimension(0, 22));
+    barre1.setAlignmentX(0.0f);
+    //    barre1.setFloatable(false);
+    add(barre1);
+    JToolBar barre2 = new JToolBar();
+//    barre2.setBackground(PanneauTexte.getCouleurFond2());
+    barre2.setPreferredSize(new Dimension(0, 22));
+    barre2.setAlignmentX(0.0f);
+//     barre2.setFloatable(false);
+    add(barre2);
+    JToolBar barre3 = new JToolBar();
+    barre3.setPreferredSize(new Dimension(0, 22));
+    barre3.setAlignmentX(0.0f);
+//    barre3.setBackground(PanneauTexte.getCouleurFond2());
+//     barre3.setFloatable(false);
+    add(barre3);
+
+    panneauChamps = pChamps;
+    saisieTypeRelations = new TypeComboBox(Relation.class);
+    saisieTypeRelations.addActionListener(this);
+    saisieRelation = new ElementComboBox();
+    saisieRelation.addActionListener(this);
+    saisieTypeElt1 = new TypeComboBox(Element.class);
+    saisieTypeElt1.addActionListener(this);
+    saisieElt1 = new ElementComboBox();
+    saisieElt1.addActionListener(this);
+    saisieTypeElt2 = new TypeComboBox(Element.class);
+    saisieTypeElt2.addActionListener(this);
+    saisieElt2 = new ElementComboBox();
+    saisieElt2.addActionListener(this);
+    creeRelation = new JButton(new GAction("Créer") {
+      public void executer() {
+        creerRelation();
+      }
+    });
+    supprimeRelation = new JButton(new GAction("Supprimer") {
+      public void executer() {
+        supprimerRelation();
+      }
+    });
+    creeUniteElt1 = new JButton(new GAction("Créer") {
+      public void executer() {
+        creerUniteElt1();
+      }
+    });
+    creeUniteElt2 = new JButton(new GAction("Créer") {
+      public void executer() {
+        creerUniteElt2();
+      }
+    });
+    barre1.addSeparator();
+    barre1.add(new TitreBarre("  Relation :  ", PanneauTexte.getCouleurFond1()));
+    barre1.addSeparator();
+    barre1.add(saisieTypeRelations);
+    barre1.add(saisieRelation);
+    barre1.addSeparator();
+    barre1.add(creeRelation);
+    barre1.addSeparator();
+    barre1.add(supprimeRelation);
+    barre2.addSeparator();
+    barre2.add(new TitreBarre("Elément 1 : ", PanneauTexte.getCouleurFond2()));
+    barre2.addSeparator();
+    barre2.add(saisieTypeElt1);
+    barre2.add(saisieElt1);
+    barre2.addSeparator();
+    barre2.add(creeUniteElt1);
+    barre3.addSeparator();
+    barre3.add(new TitreBarre("Elément 2 : ", PanneauTexte.getCouleurFond3()));
+    barre3.addSeparator();
+    barre3.add(saisieTypeElt2);
+    barre3.add(saisieElt2);
+    barre3.addSeparator();
+    barre3.add(creeUniteElt2);
+  }
+
+  /*
+   * COMMANDES UTILISEES PAR LE PANNEAU EDITEUR
+   */
+  public void reinitialiser() {
+    // typiquement, appelé par le panneau éditeur à la suite d'une modif de vue ou de structure
+    saisieTypeRelations.removeActionListener(this);
+    saisieTypeRelations.setModele(vue.getTypesRelationsAVoir());
+    saisieTypeRelations.effSelection();
+    saisieTypeRelations.addActionListener(this);
+    saisieTypeElt1.removeActionListener(this);
+    saisieTypeElt1.setModele(vue.getTypes(Unite.class), vue.getTypes(Relation.class), vue.getTypes(Schema.class));
+    saisieTypeElt1.effSelection();
+    saisieTypeElt1.addActionListener(this);
+    saisieTypeElt2.removeActionListener(this);
+    saisieTypeElt2.setModele(vue.getTypes(Unite.class), vue.getTypes(Relation.class), vue.getTypes(Schema.class));
+    saisieTypeElt2.effSelection();
+    saisieTypeElt2.addActionListener(this);
+    initSaisieRelation();
+    initSaisieElt1();
+    initSaisieElt2();
+    etatSelectRien();
+    revalidate();
+    repaint();
+  }
+  public void reafficher() {
+    // potentiellement appelé par le panneau éditeur ?
+    // appelé aussi par  traiterElementEvent
+    if (saisieRelation.pasdeSelection()) {
+      initSaisieRelation();
+      if (saisieElt1.pasdeSelection()) {
+        initSaisieElt1();
+        if (saisieElt2.pasdeSelection()) {
+          initSaisieElt2();
+          etatSelectRien();
+        } else {
+          Element elt2Courant = saisieElt2.getSelection();
+          initSaisieElt2(elt2Courant);
+          etatSelectElt2(elt2Courant);
+        }
+      } else {
+        Element elt1Courant = saisieElt1.getSelection();
+        initSaisieElt1(elt1Courant);
+        if (saisieElt2.pasdeSelection()) {
+          initSaisieElt2();
+          etatSelectElt1(elt1Courant);
+
+        } else {
+          Element elt2Courant = saisieElt2.getSelection();
+          initSaisieElt2(elt2Courant);
+          etatSelectElts(elt1Courant, elt2Courant);
+        }
+      }
+    } else {
+      Relation relCourant = (Relation) saisieRelation.getSelection();
+      initSaisieRelation(relCourant);
+      initSaisieElt1(relCourant.getElt1());
+      initSaisieElt2(relCourant.getElt2());
+      etatSelectRel(relCourant);
+    }
+  }
+  public void elementSuivant(int sens) {
+    if (sens>0) saisieRelation.gotoSuivant();
+    else saisieRelation.gotoPrecedent();
+  }
+ public Element elementSelectionne() {
+    if (saisieRelation.pasdeSelection()) return null;
+    return saisieRelation.getSelection();
+  }
+  public void editerElement(Element elt) {
+    // appelé par le panneauEditeur : elt est forcément une relation
+    if (elt.getClass()!=Relation.class)
+      throw new UnsupportedOperationException("Erreur : classe incorrecte");
+    editerRelation((Relation) elt);
+  }
+  public void traiterElementEvent(ElementEvent evt) {
+    switch (evt.getModif()) {
+      case AJOUT_RELATION:
+        Relation rel = (Relation) evt.getElement();
+        editerRelation(rel);
+        return;
+      case SUP_RELATION:
+        if (evt.getElement()==saisieRelation.getSelection()) {
+          initSaisieRelation();
+          initSaisieElt1();
+          initSaisieElt2();
+          etatSelectRien();
+        } else {
+          reafficher();
+        }
+        return;
+      case AJOUT_UNITE:
+        Unite unit = (Unite) evt.getElement();
+        boolean chgEtat = false;
+        if (!saisieTypeElt1.pasdeSelection()&&saisieTypeElt1.getClasseSelection()==Unite.class
+                &&saisieTypeElt1.getTypeSelection().equals(unit.getType())) {
+          initSaisieElt1(uniteCreeElt1 ? unit : null);
+          chgEtat = true;
+        }
+        if (!saisieTypeElt2.pasdeSelection()&&saisieTypeElt2.getClasseSelection()==Unite.class
+                &&saisieTypeElt2.getTypeSelection().equals(unit.getType())) {
+          initSaisieElt2(uniteCreeElt1 ? null : unit);
+          chgEtat = true;
+        }
+        if (chgEtat) {
+          if (uniteCreeElt1) etatSelectElt1(unit);
+          else etatSelectElt2(unit);
+          uniteCreeElt1 = true;
+        }
+        return;
+      case SUP_UNITE:
+      case BORNES_UNITE:
+      case AJOUT_SCHEMA:
+      case MODIF_SCHEMA:
+      case SUP_SCHEMA:
+      case MODIF_VALEUR:
+        reafficher();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getModif()+" oublié dans un switch");
+    }
+  }
+  public void editerRelation(Relation rel) {
+    // appelé  par traiterElementEvent, 
+    // et aussi directement par le panneau éditeur quand il est sollicité par d'autres fenêtres
+    if (!rel.getType().equals(saisieTypeRelations.getTypeSelection())) {
+      saisieTypeRelations.removeActionListener(this);
+      saisieTypeRelations.setSelection(rel.getType());
+      saisieTypeRelations.addActionListener(this);
+    }
+    initSaisieRelation(rel);
+    saisieRelation.setSelection(rel);
+  }
+  public ArrayList<ElementMarque> trouverElementsVises(Unite uniteVisee, TypeMarquage marqueUniteVisee,
+          boolean avecId) {
+    ArrayList<ElementMarque> eltsMarques = new ArrayList<ElementMarque>();
+    ArrayList<Element> eltsVises;
+    Element eltVise;
+    switch (marqueUniteVisee) {
+      case FOND1:
+        eltsVises = Element.trouverElementsParUniteSousjacente(saisieRelation.getElements(), uniteVisee);
+        for (Element elt : eltsVises)
+          eltsMarques.add(new ElementMarque(
+                  elt, marqueUniteVisee, avecId ? saisieRelation.getIdElement(elt) : null));
+        return eltsMarques;
+      case FOND2:
+        eltsVises = Element.trouverElementsParUniteSousjacente(saisieElt1.getElements(), uniteVisee);
+        for (Element elt : eltsVises)
+          eltsMarques.add(new ElementMarque(
+                  elt, marqueUniteVisee, avecId ? saisieElt1.getIdElement(elt) : null));
+        return eltsMarques;
+      case FOND3:
+        eltsVises = Element.trouverElementsParUniteSousjacente(saisieElt2.getElements(), uniteVisee);
+        for (Element elt : eltsVises)
+          eltsMarques.add(new ElementMarque(
+                  elt, marqueUniteVisee, avecId ? saisieElt2.getIdElement(elt) : null));
+        return eltsMarques;
+      case SELECT2:
+      case SELECT1_2:
+        eltVise = saisieElt1.getSelection();
+        eltsMarques.add(new ElementMarque(
+                eltVise, marqueUniteVisee, avecId ? saisieElt1.getIdElement(eltVise) : null));
+        return eltsMarques;
+      case SELECT3:
+      case SELECT1_3:
+        eltVise = saisieElt2.getSelection();
+        eltsMarques.add(new ElementMarque(
+                eltVise, marqueUniteVisee, avecId ? saisieElt2.getIdElement(eltVise) : null));
+        return eltsMarques;
+      default:
+        throw new UnsupportedOperationException("Marquage non prévu : "+marqueUniteVisee);
+
+    }
+  }
+
+  /*
+   * ACTIONS DE L'UTILISATEUR : CHANGEMENTS D'ETAT
+   */
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource()==saisieTypeRelations) {
+        initSaisieRelation();
+        if (saisieElt1.pasdeSelection()) {
+          if (saisieElt2.pasdeSelection()) etatSelectRien();
+          else etatSelectElt2(saisieElt2.getSelection());
+        } else {
+          if (saisieElt2.pasdeSelection())
+            etatSelectElt1(saisieElt1.getSelection());
+          else
+            checkEtatSelectElts(saisieElt1.getSelection(), saisieElt2.getSelection());
+        }
+        return;
+      }
+      if (evt.getSource()==saisieTypeElt1) {
+        forceEffSelectRel();
+        initSaisieElt1();
+        if (saisieElt2.pasdeSelection()) etatSelectRien();
+        else etatSelectElt2(saisieElt2.getSelection());
+        return;
+      }
+      if (evt.getSource()==saisieTypeElt2) {
+        forceEffSelectRel();
+        initSaisieElt2();
+        if (saisieElt1.pasdeSelection()) etatSelectRien();
+        else etatSelectElt1(saisieElt1.getSelection());
+        return;
+      }
+      if (evt.getSource()==saisieRelation) {
+        if (saisieRelation.pasdeSelection()) {
+          if (saisieElt1.pasdeSelection()) {
+            if (saisieElt2.pasdeSelection()) etatSelectRien();
+            else etatSelectElt2(saisieElt2.getSelection());
+          } else {
+            if (saisieElt2.pasdeSelection())
+              etatSelectElt1(saisieElt1.getSelection());
+            else
+              etatSelectElts(saisieElt1.getSelection(), saisieElt2.getSelection());
+          }
+        } else {
+          forceEtatSelectRel((Relation) saisieRelation.getSelection());
+        }
+        return;
+      }
+      if (evt.getSource()==saisieElt1) {
+        if (!saisieRelation.pasdeSelection()) {
+          saisieRelation.removeActionListener(this);
+          saisieRelation.effSelection();
+          saisieRelation.addActionListener(this);
+          saisieElt2.removeActionListener(this);
+          saisieElt2.effSelection();
+          saisieElt2.addActionListener(this);
+        }
+        if (saisieElt1.pasdeSelection()) {
+          if (saisieElt2.pasdeSelection()) etatSelectRien();
+          else etatSelectElt2(saisieElt2.getSelection());
+        } else {
+          if (saisieElt2.pasdeSelection())
+            etatSelectElt1(saisieElt1.getSelection());
+          else
+            checkEtatSelectElts(saisieElt1.getSelection(), saisieElt2.getSelection());
+        }
+        return;
+      }
+      if (evt.getSource()==saisieElt2) {
+        if (!saisieRelation.pasdeSelection()) {
+          saisieRelation.removeActionListener(this);
+          saisieRelation.effSelection();
+          saisieRelation.addActionListener(this);
+          saisieElt1.removeActionListener(this);
+          saisieElt1.effSelection();
+          saisieElt1.addActionListener(this);
+        }
+        if (saisieElt2.pasdeSelection()) {
+          if (saisieElt1.pasdeSelection()) etatSelectRien();
+          else etatSelectElt1(saisieElt1.getSelection());
+        } else {
+          if (saisieElt1.pasdeSelection())
+            etatSelectElt2(saisieElt2.getSelection());
+          else
+            checkEtatSelectElts(saisieElt1.getSelection(), saisieElt2.getSelection());
+        }
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  @Override
+  public void traiterSourisEvent(SourisEvent evt) {
+    switch (evt.getTypeEvent()) {
+      case SELECT_RIEN:
+        saisieElt1.removeActionListener(this);
+        saisieElt1.effSelection();
+        saisieElt1.addActionListener(this);
+        saisieElt2.removeActionListener(this);
+        saisieElt2.effSelection();
+        saisieElt2.addActionListener(this);
+        saisieRelation.removeActionListener(this);
+        saisieRelation.effSelection();
+        saisieRelation.addActionListener(this);
+        etatSelectRien();
+        return;
+      case SELECT_ELEMENT:
+        switch (evt.getMarquageElementVise()) {
+          case FOND1:
+            saisieRelation.setSelection(evt.getElementVise());
+            return;
+          case FOND2:
+            saisieElt1.setSelection(evt.getElementVise());
+            return;
+          case FOND3:
+            saisieElt2.setSelection(evt.getElementVise());
+            return;
+          case SELECT2:
+          case SELECT1_2:
+            forceEffSelectElt2();
+            return;
+          case SELECT3:
+          case SELECT1_3:
+            forceEffSelectElt1();
+            return;
+        }
+        return;
+      case SELECT_TEXTE:
+        if (!saisieElt1.pasdeSelection()&&!saisieElt2.pasdeSelection()) {
+          saisieElt1.removeActionListener(this);
+          saisieElt1.effSelection();
+          saisieElt1.addActionListener(this);
+          saisieElt2.removeActionListener(this);
+          saisieElt2.effSelection();
+          saisieElt2.addActionListener(this);
+          saisieRelation.removeActionListener(this);
+          saisieRelation.effSelection();
+          saisieRelation.addActionListener(this);
+        }
+        bornesSelectTexte = evt.getBornesSelectionTexte();
+        etatSelectTexte();
+        return;
+    }
+    throw new UnsupportedOperationException("Evénement non prévu : "+evt.getTypeEvent());
+  }
+  /*
+   * ACTIONS DE L'UTILISATEUR : BOUTONS
+   */
+  private void creerRelation() {
+    vue.getCorpus().addRelationSaisie((String) saisieTypeRelations.getTypeSelection(),
+            saisieElt1.getSelection(), saisieElt2.getSelection());
+  }
+  private void supprimerRelation() {
+    if (!GMessages.confirmationAction("Supprimer la relation sélectionnée ?"))
+      return;
+    vue.getCorpus().supRelation((Relation) saisieRelation.getSelection());
+  }
+  private void creerUniteElt1() {
+    if (vue.getCorpus().checkPresenceUnite(saisieTypeElt1.getTypeSelection(), bornesSelectTexte[0], bornesSelectTexte[1])
+            &&!GMessages.confirmationAction("Dupliquer cette unité  ?")) return;
+    uniteCreeElt1 = true;
+    vue.getCorpus().addUniteSaisie(saisieTypeElt1.getTypeSelection(), bornesSelectTexte[0], bornesSelectTexte[1]);
+  }
+  private void creerUniteElt2() {
+    if (vue.getCorpus().checkPresenceUnite(saisieTypeElt2.getTypeSelection(), bornesSelectTexte[0], bornesSelectTexte[1])
+            &&!GMessages.confirmationAction("Dupliquer cette unité  ?")) return;
+    uniteCreeElt1 = false;
+    vue.getCorpus().addUniteSaisie(saisieTypeElt2.getTypeSelection(), bornesSelectTexte[0], bornesSelectTexte[1]);
+  }
+
+  /* 
+   * GESTION INTERNE
+   */
+  private void etatSelectRien() {   // rien n'est sélectionné
+    if (saisieTypeRelations.pasdeSelection()) {
+      if (saisieTypeElt1.pasdeSelection()) {
+        if (saisieTypeElt2.pasdeSelection()) panneauTexte.pasDeMarquage();
+        else
+          panneauTexte.saisir(null,
+                  Element.getUnitesSousjacentes(saisieElt2.getElements()), TypeMarquage.FOND3);
+      } else {
+        if (saisieTypeElt2.pasdeSelection())
+          panneauTexte.saisir(null,
+                  Element.getUnitesSousjacentes(saisieElt1.getElements()), TypeMarquage.FOND2);
+        else
+          panneauTexte.saisir(null,
+                  Element.getUnitesSousjacentes(saisieElt1.getElements()), TypeMarquage.FOND2,
+                  Element.getUnitesSousjacentes(saisieElt2.getElements()), TypeMarquage.FOND3);
+      }
+    } else {
+      if (saisieTypeElt1.pasdeSelection()) {
+        if (saisieTypeElt2.pasdeSelection())
+          panneauTexte.saisir(null,
+                  Element.getUnitesSousjacentes(saisieRelation.getElements()), TypeMarquage.FOND1);
+        else
+          panneauTexte.saisir(null,
+                  Element.getUnitesSousjacentes(filtreElt2((Relation[]) saisieRelation.getElements())), TypeMarquage.FOND1,
+                  Element.getUnitesSousjacentes(saisieElt2.getElements()), TypeMarquage.FOND3);
+      } else {
+        if (saisieTypeElt2.pasdeSelection())
+          panneauTexte.saisir(null,
+                  Element.getUnitesSousjacentes(filtreElt1((Relation[]) saisieRelation.getElements())), TypeMarquage.FOND1,
+                  Element.getUnitesSousjacentes(saisieElt1.getElements()), TypeMarquage.FOND2);
+        else
+          panneauTexte.saisir(null,
+                  Element.getUnitesSousjacentes(filtreElts((Relation[]) saisieRelation.getElements())), TypeMarquage.FOND1,
+                  Element.getUnitesSousjacentes(saisieElt1.getElements()), TypeMarquage.FOND2,
+                  Element.getUnitesSousjacentes(saisieElt2.getElements()), TypeMarquage.FOND3);
+      }
+    }
+    panneauChamps.effacer();
+    creeRelation.setEnabled(false);
+    supprimeRelation.setEnabled(false);
+    creeUniteElt1.setEnabled(false);
+    creeUniteElt2.setEnabled(false);
+  }
+  private void etatSelectTexte() {   // du texte est sélectionné
+    if (saisieElt1.pasdeSelection()) {
+      if (saisieElt2.pasdeSelection()) panneauTexte.pasDeMarquage();
+      else
+        panneauTexte.saisir(null,
+                saisieElt2.getSelection().getUnitesSousjacentes(), TypeMarquage.SELECT3);
+    } else {
+      if (saisieElt2.pasdeSelection())
+        panneauTexte.saisir(null,
+                saisieElt1.getSelection().getUnitesSousjacentes(), TypeMarquage.SELECT2);
+      else // au moins un des 2 elt n'est pas sélectionné
+        throw new UnsupportedOperationException("Cas non prévu");
+    }
+    panneauChamps.effacer();
+    creeRelation.setEnabled(false);
+    supprimeRelation.setEnabled(false);
+    if (!saisieTypeElt1.pasdeSelection()&&saisieTypeElt1.getClasseSelection()==Unite.class
+            &&saisieElt1.pasdeSelection())
+      creeUniteElt1.setEnabled(true);
+    if (!saisieTypeElt2.pasdeSelection()&&saisieTypeElt2.getClasseSelection()==Unite.class
+            &&saisieElt2.pasdeSelection())
+      creeUniteElt2.setEnabled(true);
+  }
+  private void etatSelectElt1(Element elt1) { // seul Elt1 a été choisi
+    if (saisieTypeElt2.pasdeSelection()) {
+      if (saisieTypeRelations.pasdeSelection())
+        panneauTexte.saisir(elt1.getUnite0(), elt1.getUnitesSousjacentes(), TypeMarquage.SELECT2);
+      else
+        panneauTexte.saisir(elt1.getUnite0(), elt1.getUnitesSousjacentes(), TypeMarquage.SELECT2,
+                Element.getUnitesSousjacentes(filtreElt1((Relation[]) saisieRelation.getElements(), elt1)),
+                TypeMarquage.FOND1);
+    } else {
+      if (saisieTypeRelations.pasdeSelection())
+        panneauTexte.saisir(elt1.getUnite0(), elt1.getUnitesSousjacentes(), TypeMarquage.SELECT2,
+                Element.getUnitesSousjacentes(saisieElt2.getElements()), TypeMarquage.FOND3);
+      else
+        panneauTexte.saisir(elt1.getUnite0(), elt1.getUnitesSousjacentes(), TypeMarquage.SELECT2,
+                Element.getUnitesSousjacentes(filtreElt1(filtreElt2((Relation[]) saisieRelation.getElements()), elt1)),
+                TypeMarquage.FOND1,
+                Element.getUnitesSousjacentes(saisieElt2.getElements()), TypeMarquage.FOND3);
+    }
+    panneauChamps.afficher(elt1);
+    creeRelation.setEnabled(false);
+    supprimeRelation.setEnabled(false);
+    creeUniteElt1.setEnabled(false);
+    creeUniteElt2.setEnabled(false);
+  }
+  private void etatSelectElt2(Element elt2) {  // seul Elt2 a été choisi
+    if (saisieTypeElt1.pasdeSelection()) {
+      if (saisieTypeRelations.pasdeSelection())
+        panneauTexte.saisir(elt2.getUnite0(), elt2.getUnitesSousjacentes(), TypeMarquage.SELECT3);
+      else
+        panneauTexte.saisir(elt2.getUnite0(), elt2.getUnitesSousjacentes(), TypeMarquage.SELECT3,
+                Element.getUnitesSousjacentes(filtreElt2((Relation[]) saisieRelation.getElements(), elt2)),
+                TypeMarquage.FOND1);
+    } else {
+      if (saisieTypeRelations.pasdeSelection())
+        panneauTexte.saisir(elt2.getUnite0(), elt2.getUnitesSousjacentes(), TypeMarquage.SELECT3,
+                Element.getUnitesSousjacentes(saisieElt1.getElements()), TypeMarquage.FOND2);
+      else
+        panneauTexte.saisir(elt2.getUnite0(), elt2.getUnitesSousjacentes(), TypeMarquage.SELECT3,
+                Element.getUnitesSousjacentes(filtreElt2(filtreElt1((Relation[]) saisieRelation.getElements()), elt2)),
+                TypeMarquage.FOND1,
+                Element.getUnitesSousjacentes(saisieElt1.getElements()), TypeMarquage.FOND2);
+    }
+    panneauChamps.afficher(elt2);
+    creeRelation.setEnabled(false);
+    supprimeRelation.setEnabled(false);
+    creeUniteElt1.setEnabled(false);
+    creeUniteElt2.setEnabled(false);
+  }
+  private void etatSelectElts(Element elt1, Element elt2) { // Elt1 et Elt2 ont été choisis et ils ne forment pas encore de relation
+    panneauTexte.saisir(elt1.getUnite0(), elt1.getUnitesSousjacentes(), TypeMarquage.SELECT2,
+            elt2.getUnitesSousjacentes(), TypeMarquage.SELECT3);
+    panneauChamps.effacer();
+    if (!saisieTypeRelations.pasdeSelection()) {
+      creeRelation.setEnabled(true);
+//      Boutons.setDefaut(creeRelation, true);
+    }
+    supprimeRelation.setEnabled(false);
+    creeUniteElt1.setEnabled(false);
+    creeUniteElt2.setEnabled(false);
+  }
+  private void etatSelectRel(Relation rel) {  // une relation est sélectionnée
+    panneauTexte.saisir(rel.getElt1().getUnite0(),
+            rel.getElt1().getUnitesSousjacentes(), TypeMarquage.SELECT1_2,
+            rel.getElt2().getUnitesSousjacentes(), TypeMarquage.SELECT1_3);
+//            Element.getUnitesSousjacentes(saisieElt1.getElements()), TypeMarquage.FOND2,
+//            Element.getUnitesSousjacentes(saisieElt2.getElements()), TypeMarquage.FOND3);
+    panneauChamps.afficher(rel);
+    creeRelation.setEnabled(false);
+    supprimeRelation.setEnabled(true);
+    creeUniteElt1.setEnabled(false);
+    creeUniteElt2.setEnabled(false);
+  }
+  private Relation[] filtreElt1(Relation[] relations) {
+    Class classe = saisieTypeElt1.getClasseSelection();
+    String type = saisieTypeElt1.getTypeSelection();
+    ArrayList<Integer> indsAOter = new ArrayList<Integer>();
+    for (int i = 0; i<relations.length; i++) {
+      Element elt1 = relations[i].getElt1();
+      if (elt1.getClass()!=classe||!elt1.getType().equals(type))
+        indsAOter.add(i);
+    }
+    return Tableaux.oterRelations(relations, indsAOter);
+  }
+  private Relation[] filtreElt1(Relation[] relations, Element elt1) {
+    ArrayList<Relation> rels = new ArrayList<Relation>();
+    for (Relation rel : relations) if (elt1==rel.getElt1()) rels.add(rel);
+    return rels.toArray(new Relation[0]);
+  }
+  private Relation[] filtreElt2(Relation[] relations) {
+    Class classe = saisieTypeElt2.getClasseSelection();
+    String type = saisieTypeElt2.getTypeSelection();
+    ArrayList<Integer> indsAOter = new ArrayList<Integer>();
+    for (int i = 0; i<relations.length; i++) {
+      Element elt2 = relations[i].getElt2();
+      if (elt2.getClass()!=classe||!elt2.getType().equals(type))
+        indsAOter.add(i);
+    }
+    return Tableaux.oterRelations(relations, indsAOter);
+  }
+  private Relation[] filtreElt2(Relation[] relations, Element elt2) {
+    ArrayList<Relation> rels = new ArrayList<Relation>();
+    for (Relation rel : relations) if (elt2==rel.getElt2()) rels.add(rel);
+    return rels.toArray(new Relation[0]);
+  }
+  private Relation[] filtreElts(Relation[] relations) {
+    Class classe1 = saisieTypeElt1.getClasseSelection();
+    String type1 = saisieTypeElt1.getTypeSelection();
+    Class classe2 = saisieTypeElt2.getClasseSelection();
+    String type2 = saisieTypeElt2.getTypeSelection();
+    ArrayList<Integer> indsAOter = new ArrayList<Integer>();
+    for (int i = 0; i<relations.length; i++) {
+      Element elt1 = relations[i].getElt1();
+      Element elt2 = relations[i].getElt2();
+      if (elt1.getClass()!=classe1||!elt1.getType().equals(type1)
+              ||elt2.getClass()!=classe2||!elt2.getType().equals(type2))
+        indsAOter.add(i);
+    }
+    return Tableaux.oterRelations(relations, indsAOter);
+  }
+  private void checkEtatSelectElts(Element elt1, Element elt2) {
+    if (!saisieTypeRelations.pasdeSelection())
+      for (Relation rel : (Relation[]) saisieRelation.getElements()) {
+        if (rel.getElt1()==elt1&&rel.getElt2()==elt2) {
+          saisieRelation.setSelection(rel);
+          return;
+        }
+      }
+    etatSelectElts(elt1, elt2);
+  }
+  private void forceEtatSelectRel(Relation rel) {
+    if (saisieTypeElt1.pasdeSelection()||saisieTypeElt1.getClasseSelection()!=rel.getElt1().getClass()
+            ||!saisieTypeElt1.getTypeSelection().equals(rel.getElt1().getType())) {
+      saisieTypeElt1.removeActionListener(this);
+      saisieTypeElt1.setSelection(rel.getElt1().getClass(), rel.getElt1().getType());
+      saisieTypeElt1.addActionListener(this);
+    }
+    initSaisieElt1(rel.getElt1());
+    if (saisieTypeElt2.pasdeSelection()||saisieTypeElt2.getClasseSelection()!=rel.getElt2().getClass()
+            ||!saisieTypeElt2.getTypeSelection().equals(rel.getElt2().getType())) {
+      saisieTypeElt2.removeActionListener(this);
+      saisieTypeElt2.setSelection(rel.getElt2().getClass(), rel.getElt2().getType());
+      saisieTypeElt2.addActionListener(this);
+    }
+    initSaisieElt2(rel.getElt2());
+    etatSelectRel(rel);
+  }
+  private void forceEffSelectElt1() {
+    if (saisieElt1.pasdeSelection()) return;
+    if (!saisieRelation.pasdeSelection()) {
+      saisieRelation.removeActionListener(this);
+      saisieRelation.effSelection();
+      saisieRelation.addActionListener(this);
+    }
+    saisieElt1.effSelection();
+  }
+  private void forceEffSelectElt2() {
+    if (saisieElt2.pasdeSelection()) return;
+    if (!saisieRelation.pasdeSelection()) {
+      saisieRelation.removeActionListener(this);
+      saisieRelation.effSelection();
+      saisieRelation.addActionListener(this);
+    }
+    saisieElt2.effSelection();
+  }
+  private void forceEffSelectRel() {
+    if (saisieRelation.pasdeSelection()) return;
+    saisieRelation.removeActionListener(this);
+    saisieRelation.effSelection();
+    saisieRelation.addActionListener(this);
+  }
+  private void initSaisieRelation(Relation rel) {
+    saisieRelation.removeActionListener(this);
+    if (saisieTypeRelations.pasdeSelection()) saisieRelation.setModeleVide();
+    else {
+      String type0 = saisieTypeRelations.getTypeSelection();
+      Relation[] relations = vue.getRelationsAVoir(type0);
+      saisieRelation.setModele(relations, vue.getIdRelations(type0, relations));
+    }
+    if (rel==null) saisieRelation.effSelection();
+    else saisieRelation.setSelection(rel);
+    saisieRelation.addActionListener(this);
+    saisieRelation.revalidate();
+  }
+  private void initSaisieRelation() {
+    initSaisieRelation(null);
+  }
+  private void initSaisieElt1(Element elt1) {
+    saisieElt1.removeActionListener(this);
+    if (saisieTypeElt1.pasdeSelection()) saisieElt1.setModeleVide();
+    else {
+      Class<? extends Element> classe = saisieTypeElt1.getClasseSelection();
+      String type = saisieTypeElt1.getTypeSelection();
+      saisieElt1.setModele(vue.getElements(classe, type), vue.getIdElements(classe, type));
+    }
+    if (elt1==null) saisieElt1.effSelection();
+    else saisieElt1.setSelection(elt1);
+    saisieElt1.addActionListener(this);
+    saisieElt1.revalidate();
+  }
+  private void initSaisieElt1() {
+    initSaisieElt1(null);
+  }
+  private void initSaisieElt2(Element elt2) {
+    saisieElt2.removeActionListener(this);
+    if (saisieTypeElt2.pasdeSelection()) saisieElt2.setModeleVide();
+    else {
+      Class<? extends Element> classe = saisieTypeElt2.getClasseSelection();
+      String type = saisieTypeElt2.getTypeSelection();
+      saisieElt2.setModele(vue.getElements(classe, type), vue.getIdElements(classe, type));
+    }
+
+    if (elt2==null) saisieElt2.effSelection();
+    else saisieElt2.setSelection(elt2);
+    saisieElt2.addActionListener(this);
+    saisieElt2.revalidate();
+  }
+  private void initSaisieElt2() {
+    initSaisieElt2(null);
+  }
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauCommandesRelations.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/Vue.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/Vue.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/Vue.java	(revision 3653)
@@ -0,0 +1,1297 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.vue;
+
+import JamaPlus.*;
+import java.io.*;
+import java.util.*;
+import java.util.ArrayList;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
+import javax.swing.text.SimpleAttributeSet;
+import visuAnalec.*;
+import visuAnalec.util.*;
+import visuAnalec.Message.*;
+import visuAnalec.elements.*;
+import visuAnalec.donnees.*;
+import visuAnalec.donnees.Corpus.*;
+import visuAnalec.texte.PanneauTexte;
+import visuAnalec.texte.PanneauTexte.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class Vue implements CorpusListener {
+  public static interface VueListener extends EventListener {
+    void traiterEvent(Message e);     // relaie les messages de Corpus + envoie ses propres messages (VueEvent)
+  }
+
+  public static class Adresse implements Serializable {
+    ArrayList<Jalon> chemin;
+    String prop;
+    Adresse(Adresse adresse, String prop) {
+      this.prop = prop;
+      this.chemin = new ArrayList<Jalon>(adresse.chemin);
+    }
+    Adresse(Adresse adresse, Jalon jalon) {
+      this.prop = null;
+      ArrayList<Jalon> chemin1 = new ArrayList<Jalon>(adresse.chemin);
+      chemin1.add(jalon);
+      this.chemin = chemin1;
+    }
+    Adresse(Adresse adresse) {
+      this.prop = adresse.prop;
+      this.chemin = new ArrayList<Jalon>();
+      for (Jalon jalon : adresse.chemin) this.chemin.add(new Jalon(jalon));
+    }
+    Adresse(Jalon jalon, String prop) {
+      this.prop = prop;
+      chemin = new ArrayList<Jalon>(Arrays.asList(jalon));
+    }
+    Adresse(Jalon jalon) {
+      this.prop = null;
+      chemin = new ArrayList<Jalon>(Arrays.asList(jalon));
+    }
+    int getLongueur() {
+      return chemin.size();
+    }
+    Jalon getLastJalon() {
+      return chemin.get(chemin.size()-1);
+    }
+    void renommer(Class<? extends Element> classe, String oldType, String newType) {
+      for (Jalon jalon : chemin)
+        if (jalon.classe==classe&&jalon.type.equals(oldType))
+          jalon.type = newType;
+    }
+    boolean contient(Class<? extends Element> classe, String type) {
+      for (Jalon jalon : chemin) {
+        if (jalon.classe==classe&&jalon.type.equals(type)) return true;
+      }
+      return false;
+    }
+    @Override
+    public String toString() {
+      String nom = "";
+      for (Jalon jalon : chemin) {
+        nom += jalon;
+      }
+      nom += ": "+prop;
+      return nom;
+    }
+  }
+
+  public static class Jalon implements Serializable {
+    public enum Origine {
+      ELT_0, ELT_1, ELT_2, REL_SORTANTE, REL_ENTRANTE, SCH_CONTENANT
+    }
+    /**
+     * L'origine d'un jalon indique d'où ce jalon provient :
+     * ELT_0 est  un jalon de classe quelconque qui est toujours le premier jalon d'une adresse complète. 
+     * ELT_1 et ELT_2 sont des jalons de classe quelconque qui proviennent d'un jalon précédent de classe Relation  
+     * REL_S et REL_E sont des jalons de classe Relation qui proviennent d'un jalon précédent de classe quelconque
+     * SCH_C est un jalon de classe Schema qui provient d'un jalon précédent de classe quelconque
+     */
+    public Origine origine;
+    public Class<? extends Element> classe;
+    public String type;
+    Jalon(Origine origine, Class<? extends Element> classe, String type) {
+      this.classe = classe;
+      this.origine = origine;
+      this.type = type;
+    }
+    Jalon(Jalon jalon) {
+      this.classe = jalon.classe;
+      this.origine = jalon.origine;
+      this.type = jalon.type;
+    }
+    @Override
+    public String toString() {
+      switch (origine) {
+        case SCH_CONTENANT:
+          return "{"+type;
+        case REL_ENTRANTE:
+          return "<"+type+"<";
+        case REL_SORTANTE:
+          return ">"+type+">";
+        case ELT_0:
+          return type;
+        case ELT_1:
+          return type;
+        case ELT_2:
+          return type;
+        default:
+          return "ERREUR!!";
+      }
+    }
+  }
+  /** 
+   * Champs de la classe Vue :
+   * Données spécifiant la vue: 
+   *   - typesA voir, champs, adresses, modifiables
+   *   - champsId
+   * (ce sont les seuls champs à sauvegarder et à recharger) 
+   * Le champ unitesAVoir est un raccourci pour éviter de retrier chaque fois les données correspondantes de Corpus
+   */
+  private ArrayList<VueListener> listeCorrespondants = new ArrayList<VueListener>();
+  private Corpus corpus;
+  private boolean modifiee = false;
+  ;
+  // types d'éléments à voir pour chaque classe
+  private HashMap<Class<? extends Element>, String[]> typesAVoir =
+          new HashMap<Class<? extends Element>, String[]>();
+  // champs en ordre (niveau et position) pour chaque type d'éléments à voir pour chaque classe 
+  private HashMap<Class<? extends Element>, HashMap<String, String[][]>> champspos =
+          new HashMap<Class<? extends Element>, HashMap<String, String[][]>>();
+  // adresse pour chaque champ pour chaque  type d'élément à voir pour chaque classe
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Adresse>>> adresses =
+          new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Adresse>>>();
+  // modifiabilité pour chaque champ pour chaque  type d'élément à voir pour chaque classe
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>> modifiables =
+          new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>>();
+  // champ choisi comme identifiant (s'il existe) pour chaque type de chaque classe
+  private HashMap<Class<? extends Element>, HashMap<String, String>> champsId =
+          new HashMap<Class<? extends Element>, HashMap<String, String>>();
+// style pour tout le texte
+  private SimpleAttributeSet styleTexte;
+  // style (s'il existe) pour chaque type de chaque classe
+  private HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>> stylesElements =
+          new HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>>();
+  // style (s'il existe) pour chaque valeur de chaque champ de chaque type de chaque classe
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>> stylesValeursElements =
+          new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>>();
+  // unites par type d'unites à voir
+  private HashMap<String, Unite[]> unitesAVoir = new HashMap<String, Unite[]>();
+  /* Constructeur de la classe Vue */
+  @SuppressWarnings("unchecked")
+  public Vue(Corpus corpus) {
+    this.corpus = corpus;
+    corpus.addEventListener(this);
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      typesAVoir.put(classe, new String[0]);
+      champspos.put(classe, new HashMap<String, String[][]>());
+      adresses.put(classe, new HashMap<String, HashMap<String, Adresse>>());
+      modifiables.put(classe, new HashMap<String, HashMap<String, Boolean>>());
+      champsId.put(classe, new HashMap<String, String>());
+      stylesElements.put(classe, new HashMap<String, SimpleAttributeSet>());
+      stylesValeursElements.put(classe, new HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>());
+    }
+    this.styleTexte = new SimpleAttributeSet(PanneauTexte.STANDARD_DEFAUT);
+  }
+  public void addEventListener(VueListener correspondant) {
+    listeCorrespondants.add(correspondant);
+  }
+  public void removeEventListener(VueListener correspondant) {
+    listeCorrespondants.remove(correspondant);
+  }
+  private void fireMessage(Message evt) {
+    for (Object corresp : listeCorrespondants.toArray()) {
+      ((VueListener) corresp).traiterEvent(evt);
+    }
+  }
+  public boolean isModifiee() {
+    return modifiee;
+  }
+  public void ecrireJava(ObjectOutputStream oos) throws IOException {
+    oos.writeObject(typesAVoir);
+    oos.writeObject(champspos);
+    oos.writeObject(adresses);
+    oos.writeObject(modifiables);
+    oos.writeObject(champsId);
+    oos.writeObject(styleTexte);
+    oos.writeObject(stylesElements);
+    oos.writeObject(stylesValeursElements);
+    modifiee = false;
+  }
+  @SuppressWarnings("unchecked")
+  public boolean lireJava(ObjectInputStream ois) throws IOException, ClassNotFoundException, ClassCastException {
+    HashMap<Class<? extends Element>, String[]> typesAVoirLus =
+            (HashMap<Class<? extends Element>, String[]>) ois.readObject();
+    HashMap<Class<? extends Element>, HashMap<String, String[][]>> champsposLus =
+            (HashMap<Class<? extends Element>, HashMap<String, String[][]>>) ois.readObject();
+    HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Adresse>>> adressesLues =
+            (HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Adresse>>>) ois.readObject();
+    HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>> modifablesLus =
+            (HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>>) ois.readObject();
+    HashMap<Class<? extends Element>, HashMap<String, String>> champsIdLus =
+            (HashMap<Class<? extends Element>, HashMap<String, String>>) ois.readObject();
+    SimpleAttributeSet styleTexteLu = (SimpleAttributeSet) ois.readObject();
+    HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>> stylesElementsLus =
+            (HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>>) ois.readObject();
+    HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>> stylesValeursElementsLus =
+            (HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>>) ois.readObject();
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      for (String type : typesAVoirLus.get(classe)) {
+        if (!corpus.getStructure().getTypes(classe).contains(type))
+          return false;
+      }
+    }
+    // En prévision d'une compatibilité ascendante
+    boolean suite = false;
+    try {
+      suite = ois.readBoolean();
+    } catch (EOFException eOFException) {
+    }
+    if (suite) {
+      System.out.println("Il y a d'autres objets dans le .ecv");
+    }
+    typesAVoir = typesAVoirLus;
+    champspos = champsposLus;
+    adresses = adressesLues;
+    modifiables = modifablesLus;
+    champsId = champsIdLus;
+    styleTexte = styleTexteLu;
+    stylesElements = stylesElementsLus;
+    stylesValeursElements = stylesValeursElementsLus;
+    unitesAVoir.clear();
+    modifiee = false;
+    for (String type : typesAVoir.get(Unite.class)) majUnitesAVoir(type);
+    fireMessage(new VueEvent(this, TypeModifVue.NEW_VUE));
+    return true;
+  }
+  public void traiterEvent(Message evt) { // Messages de corpus
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        initVueParDefaut();
+        fireMessage(evt);
+        return;
+      case NEW_CORPUS:
+        initVueParDefaut();
+        fireMessage(evt);
+        return;
+      case MODIF_TEXTE:
+        fireMessage(evt);
+        return;
+      case MODIF_ELEMENT:
+        ElementEvent evtE = (ElementEvent) evt;
+        switch (evtE.getModif()) {
+          case AJOUT_UNITE:
+            if (!unitesAVoir.containsKey(evtE.getElement().getType())) return;
+            majUnitesAVoir(evtE.getElement().getType());
+            fireMessage(evt);
+            return;
+          case SUP_UNITE:
+            if (!unitesAVoir.containsKey(evtE.getElement().getType())) return;
+            majUnitesAVoir(evtE.getElement().getType());
+            fireMessage(evt);
+            return;
+          case AJOUT_RELATION:
+          case AJOUT_SCHEMA:
+          case SUP_RELATION:
+          case SUP_SCHEMA:
+          case BORNES_UNITE:
+          case MODIF_SCHEMA:
+          case MODIF_VALEUR:
+            fireMessage(evt);
+            return;
+          default:
+            throw new UnsupportedOperationException("Cas "+evtE.getModif()+" oublié dans un switch");
+        }
+      case MODIF_STRUCTURE:
+        StructureEvent evtS = (StructureEvent) evt;
+        switch (evtS.getModif()) {
+          case FUSION_TYPE:
+            fusionnerType(evtS.getClasse(), evtS.getArg(0), evtS.getArg(1));
+            fireMessage(evt);
+            return;
+          case RENOM_TYPE:
+            renommerType(evtS.getClasse(), evtS.getArg(0), evtS.getArg(1));
+            fireMessage(evt);
+            return;
+          case AJOUT_TYPE:
+            ajouterType(evtS.getClasse(), evtS.getArg());
+            fireMessage(evt);
+            return;
+          case AJOUT_TYPE_ET_ELEMENTS:
+            ajouterType(evtS.getClasse(), evtS.getArg());
+            if (evtS.getClasse()==Unite.class&&unitesAVoir.containsKey(evtS.getArg()))
+              majUnitesAVoir(evtS.getArg());
+            fireMessage(evt);
+            return;
+          case SUPPR_TYPE:
+            supprimerType(evtS.getClasse(), evtS.getArg());
+            fireMessage(evt);
+            return;
+          case AJOUT_PROP:
+            ajouterProp(evtS.getClasse(), evtS.getArg(0), evtS.getArg(1));
+            fireMessage(evt);
+            return;
+          case AJOUT_FORME_UNITE:
+            ajouterFormeUnite(evtS.getArg(0));
+            fireMessage(evt);
+            return;
+          case FUSION_PROP:
+            fusionnerProp(evtS.getClasse(), evtS.getArg(0), evtS.getArg(1), evtS.getArg(2));
+            fireMessage(evt);
+            return;
+          case RENOM_PROP:
+            renommerProp(evtS.getClasse(), evtS.getArg(0), evtS.getArg(1), evtS.getArg(2));
+            fireMessage(evt);
+            return;
+          case SUPPR_PROP:
+            supprimerProp(evtS.getClasse(), evtS.getArg(0), evtS.getArg(1));
+            fireMessage(evt);
+            return;
+          case RENOM_VALEUR:
+          case FUSION_VALEUR:
+          case SUPPR_VALEUR:
+          case AJOUT_VALEUR:
+            fireMessage(evt);
+            return;
+          case VALEUR_PAR_DEFAUT:
+            fireMessage(evt);
+            return;
+          default:
+            throw new UnsupportedOperationException("Cas "+evtS.getModif()+" oublié dans un switch");
+        }
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+  }
+  @SuppressWarnings("unchecked")
+  private void initVueParDefaut() {
+    unitesAVoir.clear();
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      String[] types = getTypes(classe);
+      Arrays.sort(types);
+      typesAVoir.put(classe, types);
+      champspos.get(classe).clear();
+      adresses.get(classe).clear();
+      champsId.get(classe).clear();
+      styleTexte = new SimpleAttributeSet(PanneauTexte.STANDARD_DEFAUT);
+      stylesElements.get(classe).clear();
+      stylesValeursElements.get(classe).clear();
+      for (String type : typesAVoir.get(classe)) {
+        Jalon jalon0 = new Jalon(Jalon.Origine.ELT_0, classe, type);
+        String[] chps = getNomsProps(new Adresse(jalon0));
+        champspos.get(classe).put(type, new String[1][]);
+        champspos.get(classe).get(type)[0] = chps;
+        adresses.get(classe).put(type, new HashMap<String, Adresse>());
+        modifiables.get(classe).put(type, new HashMap<String, Boolean>());
+        for (String chp : chps) {
+          adresses.get(classe).get(type).put(chp, new Adresse(jalon0, chp));
+          modifiables.get(classe).get(type).put(chp, true);
+        }
+        if (classe==Unite.class) majUnitesAVoir(type);
+      }
+    }
+    modifiee = false;
+    fireMessage(new VueEvent(this, TypeModifVue.VUE_DEFAUT));
+
+  }
+  private void majUnitesAVoir(String typeUnite) {
+    Unite[] unts = corpus.getUnites(typeUnite).toArray(new Unite[0]);
+    Arrays.sort(unts);
+    unitesAVoir.put(typeUnite, unts);
+  }
+  public void retablirVueParDefaut() {
+    initVueParDefaut();
+  }
+  public void setStyleTexte(SimpleAttributeSet att) {
+    styleTexte = att;
+  }
+  public SimpleAttributeSet getStyleTexte() {
+    return styleTexte;
+  }
+  public void modifierVueParSaisie(
+          HashMap<Class<? extends Element>, HashMap<String, Boolean>> newIsTypesAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> newAdressesAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> newChampsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, String>> newChampsId,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>> newModifables,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> newPositionsChamps,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> newNiveauxChamps,
+          HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>> newStylesElements,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>> newStylesValeursElements) {
+    setTypesAVoir(newIsTypesAVoir);
+    setChampsAdresses(newChampsAVoir, newAdressesAVoir, newPositionsChamps, newNiveauxChamps);
+    setChampsModifiables(newChampsAVoir, newModifables);
+    setChampsId(newChampsId);
+    setStylesElements(newStylesElements);
+    setStylesValeursElements(newStylesValeursElements);
+    unitesAVoir.clear();
+    for (String typeUnite : typesAVoir.get(Unite.class))
+      majUnitesAVoir(typeUnite);
+    modifiee = true;
+    fireMessage(new VueEvent(this, TypeModifVue.EXTRACTION));
+  }
+  @SuppressWarnings("unchecked")
+  private void setTypesAVoir(HashMap<Class<? extends Element>, HashMap<String, Boolean>> isAVoir) {
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      ArrayList<String> types = new ArrayList<String>();
+      for (String type : getTypes(classe)) if (isAVoir.get(classe).get(type))
+          types.add(type);
+      typesAVoir.put(classe, types.toArray(new String[0]));
+    }
+  }
+  @SuppressWarnings("unchecked")
+  private void setChampsAdresses(
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adressesAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> positionsChamps,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> niveauxChamps) {
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      adresses.get(classe).clear();
+      for (int i = 0; i<typesAVoir.get(classe).length; i++) {
+        String type = typesAVoir.get(classe)[i];
+        ArrayList<String> chps = champsAVoir.get(classe).get(type);
+        adresses.get(classe).put(type, new HashMap<String, Adresse>());
+        for (int j = 0; j<chps.size(); j++)
+          adresses.get(classe).get(type).put(chps.get(j), adressesAVoir.get(classe).get(type).get(j));
+        champspos.get(classe).put(type, ordonnerChamps(chps, niveauxChamps.get(classe).get(type),
+                positionsChamps.get(classe).get(type)));
+      }
+    }
+  }
+  private String[][] insererChamp(String[][] chpsenordre, String newchp) {
+    if (chpsenordre.length==0) {
+      String[][] chps = new String[1][1];
+      chps[0][0] = newchp;
+      return chps;
+    }
+    String[] chs1 = new String[chpsenordre[0].length+1];
+    chs1[0] = newchp;
+    System.arraycopy(chpsenordre[0], 0, chs1, 1, chpsenordre[0].length);
+    chpsenordre[0] = chs1;
+    return chpsenordre;
+  }
+  private String[][] ordonnerChamps(ArrayList<String> chps, HashMap<String, Integer> nivx, HashMap<String, Integer> poss) {
+    HashMap<Integer, HashMap<Integer, ArrayList<String>>> chpstries =
+            new HashMap<Integer, HashMap<Integer, ArrayList<String>>>();
+    for (String ch : chps) {
+      int niv = nivx.get(ch);
+      if (!chpstries.containsKey(niv))
+        chpstries.put(niv, new HashMap<Integer, ArrayList<String>>());
+      int pos = poss.get(ch);
+      if (!chpstries.get(niv).containsKey(pos))
+        chpstries.get(niv).put(pos, new ArrayList<String>());
+      chpstries.get(niv).get(pos).add(ch);
+    }
+    Integer[] niveaux = chpstries.keySet().toArray(new Integer[0]);
+    Arrays.sort(niveaux);
+    String[][] chpsenordre = new String[niveaux.length][];
+    int niveauenordre = 0;
+    for (int niv : niveaux) {
+      Integer[] positions = chpstries.get(niv).keySet().toArray(new Integer[0]);
+      Arrays.sort(positions);
+      int nbch = 0;
+      for (int pos : positions) nbch += chpstries.get(niv).get(pos).size();
+      chpsenordre[niveauenordre] = new String[nbch];
+      int positionenordre = 0;
+      for (int pos : positions) {
+        String[] chs = chpstries.get(niv).get(pos).toArray(new String[0]);
+        Arrays.sort(chs);
+        for (String ch : chs)
+          chpsenordre[niveauenordre][positionenordre++] = ch;
+      }
+      niveauenordre++;
+    }
+    return chpsenordre;
+  }
+  @SuppressWarnings("unchecked")
+  private void setChampsModifiables(HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> newChampsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>> newModifables) {
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      modifiables.get(classe).clear();
+      for (int i = 0; i<typesAVoir.get(classe).length; i++) {
+        String type = typesAVoir.get(classe)[i];
+        modifiables.get(classe).put(type, new HashMap<String, Boolean>());
+        for (String chp : newChampsAVoir.get(classe).get(type))
+          modifiables.get(classe).get(type).put(chp, newModifables.get(classe).get(type).get(chp));
+      }
+    }
+  }
+  @SuppressWarnings("unchecked")
+  private void setChampsId(HashMap<Class<? extends Element>, HashMap<String, String>> newChampsId) {
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      champsId.get(classe).clear();
+      champsId.get(classe).putAll(newChampsId.get(classe));
+    }
+  }
+  @SuppressWarnings("unchecked")
+  private void setStylesElements(HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>> newStylesElements) {
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      stylesElements.get(classe).clear();
+      stylesElements.get(classe).putAll(newStylesElements.get(classe));
+    }
+  }
+  @SuppressWarnings("unchecked")
+  private void setStylesValeursElements(HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>> newStylesValeursElements) {
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      stylesValeursElements.get(classe).clear();
+      stylesValeursElements.get(classe).putAll(newStylesValeursElements.get(classe));
+    }
+  }
+  public Corpus getCorpus() {
+    return corpus;
+  }
+  public String[] getTypes(Class<? extends Element> classe) {
+    String[] types = corpus.getStructure().getTypes(classe).toArray(new String[0]);
+    Arrays.sort(types);
+    return types;
+  }
+  @SuppressWarnings("unchecked")
+  public HashMap<Class<? extends Element>, HashMap<String, Boolean>> isTypesAVoir() {
+    HashMap<Class<? extends Element>, HashMap<String, Boolean>> isAVoir =
+            new HashMap<Class<? extends Element>, HashMap<String, Boolean>>();
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      isAVoir.put(classe, new HashMap<String, Boolean>());
+      for (String type : getTypes(classe)) isAVoir.get(classe).put(type, false);
+      for (String type : typesAVoir.get(classe))
+        isAVoir.get(classe).put(type, true);
+    }
+    return isAVoir;
+  }
+  String[] getTypesAVoir(Class<? extends Element> classe) {
+    return typesAVoir.get(classe);
+  }
+  public String[] getTypesUnitesAVoir() {
+    return getTypesAVoir(Unite.class);
+  }
+  public String[] getTypesRelationsAVoir() {
+    return getTypesAVoir(Relation.class);
+  }
+  public String[] getTypesSchemasAVoir() {
+    return getTypesAVoir(Schema.class);
+  }
+  public String getChampId(Class<? extends Element> classe, String type) {
+    return champsId.get(classe).get(type);
+  }
+  public SimpleAttributeSet getStyleElements(Class<? extends Element> classe, String type) {
+    return stylesElements.get(classe).get(type);
+  }
+  public HashMap<String, HashMap<String, SimpleAttributeSet>> getStyleValeursElements(
+          Class<? extends Element> classe, String type) {
+    return stylesValeursElements.get(classe).get(type);
+  }
+  public String[][] getChamps(Class<? extends Element> classe, String type) {
+    if (champspos.get(classe).containsKey(type)) {
+      return champspos.get(classe).get(type);
+    } else {
+      return new String[0][];
+    }
+  }
+  public String[] getNomsChamps(Class<? extends Element> classe, String type) {
+    return getListeChamps(classe, type).toArray(new String[0]);
+  }
+  ArrayList<String> getListeChamps(Class<? extends Element> classe, String type) {
+    // utilisé aussi par VisuVue
+    ArrayList<String> lchps = new ArrayList<String>();
+    if (champspos.get(classe).containsKey(type))
+      for (String[] champsniveau : champspos.get(classe).get(type))
+        lchps.addAll(Arrays.asList(champsniveau));
+    return lchps;
+  }
+  static String trouveNomChampParDefaut(Adresse ad, ArrayList<String> chps) {
+    String nom;
+    if (ad.chemin.size()==1) {
+      nom = ad.prop;
+      while (chps.contains(nom)) nom += "-0";
+      return nom;
+    }
+    for (int i = 1; true; i++) {
+      nom = ad.prop+"-"+i;
+      if (!chps.contains(nom)) {
+        return nom;
+      }
+    }
+  }
+  String[] getNomsProps(Adresse adresse) {
+    String[] props;
+    Jalon jalon = adresse.getLastJalon();
+    props = corpus.getStructure().getNomsProps(jalon.classe, jalon.type).toArray(new String[0]);
+    Arrays.sort(props);
+    return props;
+  }
+  String[] getValeursProp(Adresse adresse) {
+    String[] vals;
+    Jalon jalon = adresse.getLastJalon();
+    vals = corpus.getStructure().getValeursProp(jalon.classe, jalon.type, adresse.prop).toArray(new String[0]);
+    Arrays.sort(vals);
+    return vals;
+  }
+  @SuppressWarnings("unchecked")
+  Jalon[] getNextJalonsPotentiels(Adresse adresse) {
+    ArrayList<Jalon> nextJalons = new ArrayList<Jalon>();
+    Jalon jalon = adresse.getLastJalon();
+    switch (jalon.origine) {
+      case REL_ENTRANTE:
+        for (Class<? extends Element> cl : new Class[]{Unite.class, Relation.class, Schema.class}) {
+          for (String typeRel : getTypes(cl)) {
+            nextJalons.add(new Jalon(Jalon.Origine.ELT_1, cl, typeRel));
+          }
+        }
+        break;
+      case REL_SORTANTE:
+        for (Class<? extends Element> cl : new Class[]{Unite.class, Relation.class, Schema.class}) {
+          for (String typeRel : getTypes(cl)) {
+            nextJalons.add(new Jalon(Jalon.Origine.ELT_2, cl, typeRel));
+          }
+        }
+        break;
+      default:
+        for (String typeRel : getTypes(Relation.class)) {
+          nextJalons.add(new Jalon(Jalon.Origine.REL_SORTANTE, Relation.class, typeRel));
+        }
+        for (String typeRel : getTypes(Relation.class)) {
+          nextJalons.add(new Jalon(Jalon.Origine.REL_ENTRANTE, Relation.class, typeRel));
+        }
+        for (String typeSch : getTypes(Schema.class)) {
+          nextJalons.add(new Jalon(Jalon.Origine.SCH_CONTENANT, Schema.class, typeSch));
+        }
+        break;
+    }
+    return nextJalons.toArray(new Jalon[0]);
+  }
+  Adresse getAdresseChamps(Class<? extends Element> classe, String type, String nomChamp) {
+    if (adresses.get(classe).containsKey(type)) {
+      return adresses.get(classe).get(type).get(nomChamp);
+    } else {
+      return null;
+    }
+  }
+  public boolean isChampModifiable(Class<? extends Element> classe, String type, String champ) {
+    return modifiables.get(classe).get(type).get(champ);
+  }
+  public HashMap<String, Integer> getPositionsChampsAVoir(Class<? extends Element> classe, String type) {
+    HashMap<String, Integer> positions = new HashMap<String, Integer>();
+    if (champspos.get(classe).containsKey(type)) {
+      for (String[] champsniveau : champspos.get(classe).get(type)) {
+        int i = 0;
+        for (String ch : champsniveau) positions.put(ch, i++);
+      }
+    }
+    return positions;
+  }
+  public HashMap<String, Integer> getNiveauxChampsAVoir(Class<? extends Element> classe, String type) {
+    HashMap<String, Integer> niveaux = new HashMap<String, Integer>();
+    if (champspos.get(classe).containsKey(type)) {
+      int i = 0;
+      for (String[] champsniveau : champspos.get(classe).get(type)) {
+        for (String ch : champsniveau) niveaux.put(ch, i);
+        i++;
+      }
+    }
+    return niveaux;
+  }
+  public String[] getValeursChamp(Class<? extends Element> classe, String type, String champ) {
+    Adresse adresse = getAdresseChamps(classe, type, champ);
+    if (adresse==null) {
+      return new String[0];
+    }
+    return getValeursProp(adresse);
+  }
+  public String getValeurChamp(Element element, String champ) {
+    Adresse adresse = getAdresseChamps(element.getClass(), element.getType(), champ);
+    if (adresse==null) {
+      return "";
+    }
+    Element elt = element;
+    for (Jalon jalon : adresse.chemin) {
+      if ((elt = elt.getElementSuivant(jalon))==null) return "";
+    }
+    return elt.getProp(adresse.prop);
+  }
+  public boolean setValeurChamp(Element element, String champ, String newval) {
+    Adresse adresse = getAdresseChamps(element.getClass(), element.getType(), champ);
+    Element elt = element;
+    for (Jalon jalon : adresse.chemin) {
+      elt = elt.getElementSuivant(jalon);
+      if (elt==null) return false;
+    }
+    corpus.setValeurPropElement(elt, adresse.prop, newval);
+    return true;
+  }
+  public void copierValeurs(Element eltSource, Element eltCible) {
+    Class<? extends Element> classe = eltSource.getClass();
+    if (eltCible.getClass()!=classe) return;
+    String type = eltSource.getType();
+    if (!eltCible.getType().equals(type)) return;
+    for (String champ : getListeChamps(classe, type))
+      if (isChampModifiable(classe, type, champ))
+        setValeurChamp(eltCible, champ, getValeurChamp(eltSource, champ));
+  }
+  private void ajouterType(Class<? extends Element> classe, String newType) {
+
+//      ArrayList<String> typs = new ArrayList<String>(Arrays.asList(typesUnitesAVoir));
+//      typs.add(newType);
+//      typesUnitesAVoir = typs.toArray(new String[0]);
+//      Arrays.sort(typesUnitesAVoir);
+    typesAVoir.put(classe, Tableaux.insererString(typesAVoir.get(classe), newType));
+    champspos.get(classe).put(newType, new String[0][]);
+    adresses.get(classe).put(newType, new HashMap<String, Adresse>());
+    if (classe==Unite.class) unitesAVoir.put(newType, new Unite[0]);
+    modifiables.get(classe).put(newType, new HashMap<String, Boolean>());
+  }
+  private void renommerType(Class<? extends Element> classe, String oldType, String newType) {
+    for (Class<? extends Element> cl : adresses.keySet())
+      for (String type : adresses.get(cl).keySet())
+        for (String chp : adresses.get(cl).get(type).keySet()) {
+          adresses.get(cl).get(type).get(chp).renommer(classe, oldType, newType);
+        }
+    int ind = Arrays.binarySearch(typesAVoir.get(classe), oldType);
+    if (ind>=0) {
+      typesAVoir.get(classe)[ind] = newType;
+      Arrays.sort(typesAVoir.get(classe));
+      champspos.get(classe).put(newType, champspos.get(classe).get(oldType));
+      champspos.get(classe).remove(oldType);
+      adresses.get(classe).put(newType, adresses.get(classe).get(oldType));
+      adresses.get(classe).remove(oldType);
+      if (champsId.get(classe).containsKey(oldType)) {
+        champsId.get(classe).put(newType, champsId.get(classe).get(oldType));
+        champsId.get(classe).remove(oldType);
+      }
+      modifiables.get(classe).put(newType, modifiables.get(classe).get(oldType));
+      if (classe==Unite.class) {
+        unitesAVoir.put(newType, unitesAVoir.get(oldType));
+        unitesAVoir.remove(oldType);
+      }
+      if (stylesElements.get(classe).containsKey(oldType)) {
+        stylesElements.get(classe).put(newType, stylesElements.get(classe).get(oldType));
+        stylesElements.get(classe).remove(oldType);
+      }
+      if (stylesValeursElements.get(classe).containsKey(oldType)) {
+        stylesValeursElements.get(classe).put(newType, stylesValeursElements.get(classe).get(oldType));
+        stylesValeursElements.get(classe).remove(oldType);
+      }
+    }
+  }
+  private void fusionnerType(Class<? extends Element> classe, String oldType, String newType) {
+    int indold = Arrays.binarySearch(typesAVoir.get(classe), oldType);
+    if (indold>=0) {
+      int indnew = Arrays.binarySearch(typesAVoir.get(classe), newType);
+      if (indnew>=0) {
+        ArrayList<String> chpsnewtype = getListeChamps(classe, newType);
+        HashMap<String, Integer> nivxnewtype = getNiveauxChampsAVoir(classe, newType);
+        HashMap<String, Integer> possnewtype = getPositionsChampsAVoir(classe, newType);
+        for (String chpoldtype : getListeChamps(classe, oldType)) {
+          Adresse adroldtype = adresses.get(classe).get(oldType).get(chpoldtype);
+          String nomchamp = trouveNomChampParDefaut(adroldtype, chpsnewtype);
+          adresses.get(classe).get(newType).put(nomchamp, adroldtype);
+          chpsnewtype.add(nomchamp);
+          nivxnewtype.put(nomchamp, getNiveauxChampsAVoir(classe, oldType).get(chpoldtype));
+          possnewtype.put(nomchamp, getPositionsChampsAVoir(classe, oldType).get(chpoldtype));
+          modifiables.get(classe).get(newType).put(nomchamp, modifiables.get(classe).get(oldType).get(chpoldtype));
+          if (stylesValeursElements.get(classe).containsKey(oldType)&&stylesValeursElements.get(classe).get(oldType).containsKey(chpoldtype)) {
+            if (!stylesValeursElements.get(classe).containsKey(newType))
+              stylesValeursElements.get(classe).put(newType, new HashMap<String, HashMap<String, SimpleAttributeSet>>());
+            stylesValeursElements.get(classe).get(newType).put(nomchamp,
+                    stylesValeursElements.get(classe).get(oldType).get(chpoldtype));
+          }
+        }
+        champspos.get(classe).put(newType, ordonnerChamps(chpsnewtype, nivxnewtype, possnewtype));
+      }
+      typesAVoir.put(classe, Tableaux.oterString(typesAVoir.get(classe), indold));
+      champspos.get(classe).remove(oldType);
+      adresses.get(classe).remove(oldType);
+      champsId.get(classe).remove(oldType);
+      modifiables.get(classe).remove(oldType);
+      stylesElements.get(classe).remove(oldType);
+      stylesValeursElements.get(classe).remove(oldType);
+      if (classe==Unite.class) {
+        majUnitesAVoir(newType);
+        unitesAVoir.remove(oldType);
+      }
+    }
+    for (Class<? extends Element> cl : typesAVoir.keySet())
+      for (String typ : typesAVoir.get(cl)) {
+        ArrayList<String> chpsASup = new ArrayList<String>();
+        ArrayList<String> chps = getListeChamps(cl, typ);
+        HashMap<String, Integer> nivx = getNiveauxChampsAVoir(cl, typ);
+        HashMap<String, Integer> poss = getPositionsChampsAVoir(cl, typ);
+        for (String ch : chps) {
+          Adresse ad = adresses.get(cl).get(typ).get(ch);
+          if (ad.contient(classe, oldType)) {
+            Adresse ad1 = new Adresse(ad);
+            ad1.renommer(classe, oldType, newType);
+            boolean dejala = false;
+            for (String ch1 : chps)
+              if (adresses.get(cl).get(typ).get(ch1).toString().equals(ad1.toString())) {
+                dejala = true;
+                break;
+              }
+            if (!dejala) adresses.get(cl).get(typ).put(ch, ad1);
+            else {
+              chpsASup.add(ch);
+              if (ch.equals(champsId.get(cl).get(typ)))
+                champsId.get(cl).remove(typ);
+              modifiables.get(cl).get(typ).remove(ch);
+              if (stylesValeursElements.get(cl).containsKey(typ))
+                stylesValeursElements.get(cl).get(typ).remove(ch);
+              nivx.remove(ch);
+              poss.remove(ch);
+            }
+          }
+        }
+        chps.removeAll(chpsASup);
+        for (String ch : chpsASup) adresses.get(cl).get(typ).remove(ch);
+        champspos.get(cl).put(typ, ordonnerChamps(chps, nivx, poss));
+      }
+  }
+  private void supprimerType(Class<? extends Element> classe, String type) {
+    int ind = Arrays.binarySearch(typesAVoir.get(classe), type);
+    if (ind>=0) {
+      typesAVoir.put(classe, Tableaux.oterString(typesAVoir.get(classe), ind));
+      champspos.get(classe).remove(type);
+      adresses.get(classe).remove(type);
+      if (classe==Unite.class) unitesAVoir.remove(type);
+    }
+    champsId.get(classe).remove(type);
+    modifiables.get(classe).remove(type);
+    stylesElements.get(classe).remove(type);
+    stylesValeursElements.get(classe).remove(type);
+    for (Class<? extends Element> cl : typesAVoir.keySet())
+      for (String typ : typesAVoir.get(cl)) {
+        ArrayList<String> chpsASup = new ArrayList<String>();
+        ArrayList<String> chps = getListeChamps(cl, typ);
+        HashMap<String, Integer> nivx = getNiveauxChampsAVoir(cl, typ);
+        HashMap<String, Integer> poss = getPositionsChampsAVoir(cl, typ);
+        for (String ch : chps)
+          if (adresses.get(cl).get(typ).get(ch).contient(classe, type)) {
+            chpsASup.add(ch);
+            adresses.get(cl).get(typ).remove(ch);
+            if (ch.equals(champsId.get(cl).get(typ)))
+              champsId.get(cl).remove(typ);
+            modifiables.get(cl).get(typ).remove(ch);
+            if (stylesValeursElements.get(cl).containsKey(typ))
+              stylesValeursElements.get(cl).get(typ).remove(ch);
+            nivx.remove(ch);
+            poss.remove(ch);
+          }
+        chps.removeAll(chpsASup);
+        champspos.get(cl).put(typ, ordonnerChamps(chps, nivx, poss));
+      }
+  }
+  private void ajouterProp(Class<? extends Element> classe, String type, String prop) {
+    if (Arrays.binarySearch(typesAVoir.get(classe), type)>=0) {
+      Adresse ad = new Adresse(new Jalon(Jalon.Origine.ELT_0, classe, type), prop);
+      String newchp = trouveNomChampParDefaut(ad, getListeChamps(classe, type));
+      champspos.get(classe).put(type, insererChamp(champspos.get(classe).get(type), newchp));
+      adresses.get(classe).get(type).put(newchp, ad);
+      modifiables.get(classe).get(type).put(newchp, true);
+    }
+  }
+  private void ajouterFormeUnite(String type) {
+    if (Arrays.binarySearch(typesAVoir.get(Unite.class), type)>=0) {
+      Adresse ad = new Adresse(new Jalon(Jalon.Origine.ELT_0, Unite.class, type), Structure.FORME);
+      champspos.get(Unite.class).put(type, insererChamp(champspos.get(Unite.class).get(type), Structure.FORME));
+      adresses.get(Unite.class).get(type).put(Structure.FORME, ad);
+      modifiables.get(Unite.class).get(type).put(Structure.FORME, false);
+    }
+  }
+  private void renommerProp(Class<? extends Element> classe, String type, String oldNom, String newNom) {
+    // on ne change que les adresses : on ne renomme les champs que dans certains cas (cf. renommerChamp appelé à la fin)
+    for (Class<? extends Element> cl : adresses.keySet())
+      for (String typ : adresses.get(cl).keySet())
+        for (String chp : adresses.get(cl).get(typ).keySet()) {
+          if (adresses.get(cl).get(typ).get(chp).getLastJalon().classe==classe
+                  &&type.equals(adresses.get(cl).get(typ).get(chp).getLastJalon().type)
+                  &&oldNom.equals(adresses.get(cl).get(typ).get(chp).prop)) {
+            adresses.get(cl).get(typ).get(chp).prop = newNom;
+          }
+        }
+    renommerChamp(classe, type, oldNom, newNom);
+  }
+  private void renommerChamp(Class<? extends Element> classe, String type, String oldNom, String newNom) {
+    // renomme aussi le champ quand la correspondance prop<=>champ est directe (notamment dans la vue par défaut)
+    if (!champspos.get(classe).containsKey(type))
+      throw new IllegalArgumentException();
+    String[][] chps = champspos.get(classe).get(type);
+    if (!adresses.get(classe).get(type).containsKey(oldNom))
+      throw new IllegalArgumentException();
+    if (adresses.get(classe).get(type).get(oldNom).getLongueur()>1) return;
+    if (!adresses.get(classe).get(type).get(oldNom).prop.equals(oldNom)) return;
+    boolean fait = false;
+    for (int niv = 0; niv<chps.length; niv++) {
+      for (int pos = 0; pos<chps[niv].length; pos++)
+        if (chps[niv][pos].equals(oldNom)) {
+          chps[niv][pos] = newNom;
+          fait = true;
+          break;
+        }
+      if (fait) break;
+    }
+    if (!fait) throw new IllegalArgumentException();
+    adresses.get(classe).get(type).put(newNom, adresses.get(classe).get(type).get(oldNom));
+    adresses.get(classe).get(type).remove(oldNom);
+    modifiables.get(classe).get(type).put(newNom, modifiables.get(classe).get(type).get(oldNom));
+    modifiables.get(classe).get(type).remove(oldNom);
+    if (champsId.get(classe).containsKey(type)&&champsId.get(classe).get(type).equals(oldNom))
+      champsId.get(classe).put(type, newNom);
+    if (stylesValeursElements.get(classe).containsKey(type)
+            &&stylesValeursElements.get(classe).get(type).containsKey(oldNom)) {
+      stylesValeursElements.get(classe).get(type).put(newNom,
+              stylesValeursElements.get(classe).get(type).get(oldNom));
+      stylesValeursElements.get(classe).get(type).remove(oldNom);
+    }
+  }
+  private void fusionnerProp(Class<? extends Element> classe, String type, String oldNom, String newNom) {
+    // pour le moment, on se contente de supprimer tous les champs qui utilisent l'ancienne prop
+    // c'est un peu grossier...
+    supprimerProp(classe, type, oldNom);
+  }
+  private void supprimerProp(Class<? extends Element> classe, String type, String prop) {
+    // on parcourt tous les champs et les adresses correspondantes
+    for (Class<? extends Element> cl : typesAVoir.keySet())
+      for (String typ : typesAVoir.get(cl)) {
+        ArrayList<String> chpsASup = new ArrayList<String>();
+        ArrayList<String> chps = getListeChamps(cl, typ);
+        HashMap<String, Integer> nivx = getNiveauxChampsAVoir(cl, typ);
+        HashMap<String, Integer> poss = getPositionsChampsAVoir(cl, typ);
+        for (String ch : chps) {
+          Adresse ad = adresses.get(cl).get(typ).get(ch);
+          if (ad.getLastJalon().classe==classe&&type.equals(ad.getLastJalon().type)&&prop.equals(ad.prop)) {
+            chpsASup.add(ch);
+            adresses.get(cl).get(typ).remove(ch);
+            modifiables.get(cl).get(typ).remove(ch);
+            if (ch.equals(champsId.get(cl).get(typ)))
+              champsId.get(cl).remove(typ);
+            if (stylesValeursElements.get(cl).containsKey(typ))
+              stylesValeursElements.get(cl).get(typ).remove(ch);
+            nivx.remove(ch);
+            poss.remove(ch);
+          }
+        }
+        chps.removeAll(chpsASup);
+        champspos.get(cl).put(typ, ordonnerChamps(chps, nivx, poss));
+      }
+  }
+  public Unite[] getUnites(String type) {
+    Unite[] units = corpus.getUnites(type).toArray(new Unite[0]);
+    Arrays.sort(units);
+    return units;
+  }
+  public Unite[] getUnitesAVoir(String type) {
+    if (unitesAVoir.get(type)==null) {
+      return new Unite[0];
+    }
+    return unitesAVoir.get(type);
+  }
+  public Relation[] getRelations(String type) {
+    Relation[] rels = corpus.getRelations(type).toArray(new Relation[0]);
+    Arrays.sort(rels);
+    return rels;
+  }
+  public Relation[] getRelationsAVoir(String type) {
+    // Pour l'instant, toutes les relations de ce type, mais ça peut changer avec la mise en place des sélections
+    // nécessitera peut-être la mise en place d'une variable relationsAVoir (comme pour les unités) 
+    Relation[] rels = corpus.getRelations(type).toArray(new Relation[0]);
+    Arrays.sort(rels);
+    return rels;
+  }
+  public Schema[] getSchemas(String type) {
+    Schema[] schs = corpus.getSchemas(type).toArray(new Schema[0]);
+    Arrays.sort(schs);
+    return schs;
+  }
+  public Schema[] getSchemasAVoir(String type) {
+    // Pour l'instant, tous les schémas de ce type, mais ça peut changer avec la mise en place des sélections
+    // nécessitera peut-être la mise en place d'une variable schemasAVoir (comme pour les unités) 
+    Schema[] schs = corpus.getSchemas(type).toArray(new Schema[0]);
+    Arrays.sort(schs);
+    return schs;
+  }
+  public Element[] getElements(Class<? extends Element> classe, String type) {
+    if (classe==Unite.class) return getUnites(type);
+    if (classe==Relation.class) return getRelations(type);
+    if (classe==Schema.class) return getSchemas(type);
+    throw new UnsupportedOperationException("sous-classe non traitée");
+  }
+  public Element[] getElementsAVoir(Class<? extends Element> classe, String type) {
+    if (classe==Unite.class) return getUnitesAVoir(type);
+    if (classe==Relation.class) return getRelationsAVoir(type);
+    if (classe==Schema.class) return getSchemasAVoir(type);
+    throw new UnsupportedOperationException("sous-classe non traitée");
+  }
+  public String getTexteUnite(Unite unit) {  // utilisé par ModeleChaines et par ModeleStatsGeometrie - à revoir : pas très efficace
+    return corpus.getTexteUnite(unit);
+  }
+  public String getIdElement(Element elt) {  // utilisé  par PanneauOccurrences
+    String type = elt.getType();
+    Class<? extends Element> classe = elt.getClass();
+    String champId = getChampId(classe, type);
+    String id;
+    if (champId!=null) {
+      id = getValeurChamp(elt, champId);
+      if (!id.isEmpty()) return id;
+    }
+    Element[] listeElts = getElements(classe, type);
+    if (listeElts==null) return "";
+    int no = Arrays.binarySearch(listeElts, elt);
+    if (no<0) return "";
+    return type+"-"+Integer.toString(no+1);
+  }
+  private String[] getIdElements(Class<? extends Element> classe, String type,
+          Element[] eltsCorpus, Element[] eltsATraiter) {
+    // eltsATraiter doit être  trié ; s'il est null, on prend toutes les éléments du corpus de ce type 
+    String champId = getChampId(classe, type);
+    String[] ids = new String[eltsATraiter==null ? eltsCorpus.length : eltsATraiter.length];
+    String id;
+    int i = 0;
+    for (int no = 0; no<eltsCorpus.length; no++) {
+      if (eltsATraiter==null||eltsATraiter[i]==eltsCorpus[no]) {
+        id = champId==null ? "" : getValeurChamp(eltsCorpus[no], champId);
+        ids[i++] = id.isEmpty() ? type+"-"+Integer.toString(no+1) : id;
+      }
+    }
+    return ids;
+  }
+  public String[] getIdUnites(String type) {  // toutes les unités du corpus de ce type 
+    return getIdElements(Unite.class, type, getUnites(type), null);
+  }
+  public String[] getIdUnites(String type, Unite[] unites) {    // unites doit être  trié 
+    return getIdElements(Unite.class, type, getUnites(type), unites);
+  }
+  public String[] getIdRelations(String type) {  // toutes les relations du corpus de ce type 
+    return getIdElements(Relation.class, type, getRelations(type), null);
+  }
+  public String[] getIdRelations(String type, Relation[] relations) {   // relations doit être  trié 
+    return getIdElements(Relation.class, type, getRelations(type), relations);
+  }
+  public String[] getIdSchemas(String type) {  // tous les schémas du corpus de ce type 
+    return getIdElements(Schema.class, type, getSchemas(type), null);
+  }
+  public String[] getIdSchemas(String type, Schema[] schemas) {    // schemas doit être  trié 
+    return getIdElements(Schema.class, type, getSchemas(type), schemas);
+  }
+  public String[] getIdElements(Class<? extends Element> classe, String type) {
+    if (classe==Relation.class) return getIdRelations(type);
+    if (classe==Schema.class) return getIdSchemas(type);
+    return getIdUnites(type);
+  }
+  /**
+   * Fonction pour le coloriage
+   */
+  public UniteColoree[] getUnitesAColorier() {
+    ArrayList<UniteColoree> unites = new ArrayList<UniteColoree>();
+    for (Class<? extends Element> classe : stylesElements.keySet())
+      for (String type : stylesElements.get(classe).keySet()) {
+        for (Unite unit : Element.getUnitesSousjacentes(getElementsAVoir(classe, type)))
+          unites.add(new UniteColoree(unit, stylesElements.get(classe).get(type)));
+      }
+    for (Class<? extends Element> classe : stylesValeursElements.keySet())
+      for (String type : stylesValeursElements.get(classe).keySet())
+        for (String champ : stylesValeursElements.get(classe).get(type).keySet())
+          for (String valeur : stylesValeursElements.get(classe).get(type).get(champ).keySet()) {
+            for (Unite unit : Element.getUnitesSousjacentes(getElementsAVoirValeurChamp(classe, type, champ, valeur)))
+              unites.add(new UniteColoree(unit, stylesValeursElements.get(classe).get(type).get(champ).get(valeur)));
+          }
+    return unites.toArray(new UniteColoree[0]);
+  }
+  public Element[] getElementsAVoirValeurChamp(Class<? extends Element> classe,
+          String type, String champ, String valeur) {
+    ArrayList<Element> elts = new ArrayList<Element>();
+    for (Element elt : getElementsAVoir(classe, type))
+      if (valeur.equals(getValeurChamp(elt, champ))) elts.add(elt);
+    return elts.toArray(new Element[0]);
+  }
+  /**
+   * Fonctions de comptage pour les stats
+   */
+  public int getNbElementsAVoir(Class<? extends Element> classe, String type) {
+    return getElementsAVoir(classe, type).length;
+  }
+  public HashMap<String, Integer> compterOccurrencesFiltrees(Class<? extends Element> classe,
+          String type, String champCible, String champFiltre, String[] valeursChampFiltre) {
+    HashMap<String, Integer> compte = initCompte(classe, type, champCible);
+    for (Element elt : getElementsAVoir(classe, type)) {
+      String valCible = getValeurChamp(elt, champCible);
+      if (champFiltre==null) {
+        compte.put(valCible, compte.get(valCible)+1);
+      } else {
+        String valfiltre = getValeurChamp(elt, champFiltre);
+        for (Object valchfiltre : valeursChampFiltre) {
+          if (valfiltre.equals(valchfiltre)) {
+            compte.put(valCible, compte.get(valCible)+1);
+            break;
+          }
+        }
+      }
+    }
+    return compte;
+  }
+  public HashMap<String, HashMap<String, Integer>> compterOccurrencesCorrelees(
+          Class<? extends Element> classe, String type, String champ1, String champ2) {
+    HashMap<String, HashMap<String, Integer>> compte = new HashMap<String, HashMap<String, Integer>>();
+    for (String val : getValeursChamp(classe, type, champ1)) {
+      compte.put(val, initCompte(classe, type, champ2));
+    }
+    compte.put("", initCompte(classe, type, champ2));
+    for (Element elt : getElementsAVoir(classe, type)) {
+      String val1 = getValeurChamp(elt, champ1);
+      String val2 = getValeurChamp(elt, champ2);
+      compte.get(val1).put(val2, compte.get(val1).get(val2)+1);
+    }
+    return compte;
+  }
+  private HashMap<String, Integer> initCompte(Class<? extends Element> classe, String type, String champ) {
+    HashMap<String, Integer> hm = new HashMap<String, Integer>();
+    for (String val : getValeursChamp(classe, type, champ)) {
+      hm.put(val, 0);
+    }
+    hm.put("", 0);
+    return hm;
+  }
+  public Element[] getDoubleSelectionOccurrences(Class<? extends Element> classe, String type,
+          String champ1, String[] valeurs1, String champ2, String[] valeurs2) {
+    ArrayList<Element> aliste = new ArrayList<Element>();
+    for (Element elt : getElementsAVoir(classe, type)) {
+      if (verifierContrainteFiltre(elt, champ1, valeurs1)&&verifierContrainteFiltre(elt, champ2, valeurs2)) {
+        aliste.add(elt);
+      }
+    }
+    Element[] res = aliste.toArray(new Element[0]);
+    Arrays.sort(res);
+    return res;
+  }
+  private boolean verifierContrainteFiltre(Element elt, String champ, String[] valeurs) {
+    if (champ==null) {
+      return true;
+    }
+    String valeur = getValeurChamp(elt, champ);
+    for (String val : valeurs) {
+      if (val.equals(valeur)) {
+        return true;
+      }
+    }
+    return false;
+  }
+  public Matrix getMatrice(Class<? extends Element> classe, String type, String[] champsSelect, Element[] eltsSelect) {
+    HashMap<String, HashMap<String, Integer>> numeros = new HashMap<String, HashMap<String, Integer>>();
+    int nb = 0;
+    for (String champ : champsSelect) {
+      numeros.put(champ, new HashMap<String, Integer>());
+      numeros.get(champ).put("", nb++);
+      for (String val : getValeursChamp(classe, type, champ)) {
+        numeros.get(champ).put(val, nb++);
+      }
+    }
+    double[][] matrice = new double[eltsSelect.length][nb];
+    for (int i = 0; i<eltsSelect.length; i++) {
+      for (String champ : champsSelect) {
+        matrice[i][numeros.get(champ).get(getValeurChamp(eltsSelect[i], champ))] = 1.;
+      }
+    }
+    return new Matrix(matrice, eltsSelect.length, nb);
+  }
+  public SparseMatrix getMatriceCreuse(Class<? extends Element> classe, String type,
+          String[] champsSelect, Element[] eltsSelect) {
+    HashMap<String, HashMap<String, Integer>> numeros =
+            new HashMap<String, HashMap<String, Integer>>();
+    int nb = 0;
+    for (String champ : champsSelect) {
+      numeros.put(champ, new HashMap<String, Integer>());
+      numeros.get(champ).put("", nb++);
+      for (String val : getValeursChamp(classe, type, champ))
+        numeros.get(champ).put(val, nb++);
+    }
+//    double[][] matrice = new double[eltsSelect.length][nb];
+    ArrayList<Integer> rows = new ArrayList<Integer>();
+    ArrayList<Integer> cols = new ArrayList<Integer>();
+    for (int i = 0; i<eltsSelect.length; i++)
+      for (String champ : champsSelect) {
+        rows.add(i);
+        cols.add(numeros.get(champ).get(getValeurChamp(eltsSelect[i], champ)));
+      }
+    return new SparseMatrix(eltsSelect.length, nb, rows, cols, 1);
+  }
+
+  public static class TripletValTypique {
+    public String champ;
+    public String valeur;
+    public float pourcentage;
+    public TripletValTypique(String champ, String valeur, float pourcentage) {
+      this.champ = champ;
+      this.valeur = valeur;
+      this.pourcentage = pourcentage;
+    }
+  }
+  public TripletValTypique[] getValTypiques(Class<? extends Element> classe,
+          String type, Element[] elts) {
+    ArrayList<String> chps = new ArrayList<String>();
+    ArrayList<String> vals = new ArrayList<String>();
+    ArrayList<Float> pcts = new ArrayList<Float>();
+    HashMap<String, Integer> compte = new HashMap<String, Integer>();
+    int total = elts.length;
+    for (String champ : getListeChamps(classe, type)) {
+      compte.clear();
+      for (Element elt : elts) {
+        String val = getValeurChamp(elt, champ);
+        if (val.isEmpty()) continue;
+        if (compte.containsKey(val)) compte.put(val, compte.get(val)+1);
+        else compte.put(val, 1);
+      }
+      for (String val : compte.keySet()) if (2*compte.get(val)>total) {
+          chps.add(champ);
+          vals.add(val);
+          pcts.add(((float) compte.get(val))/total);
+          break;
+        }
+    }
+    TripletValTypique[] triplets = new TripletValTypique[chps.size()];
+    for (int i = 0; i<chps.size(); i++)
+      triplets[i] = new TripletValTypique(chps.get(i), vals.get(i), pcts.get(i));
+    return triplets;
+  }
+  public String[] getIdListeElements(Class<? extends Element> classe,
+          String type, Element[] elts) {
+    return getIdElements(classe, type, elts, null);
+  }
+  public String[][] getValeursChampsListeElements(String[] champs, Element[] elts) {
+    String[][] valeurs = new String[elts.length][champs.length];
+    for (int i = 0; i<elts.length; i++) for (int j = 0; j<champs.length; j++)
+        valeurs[i][j] = getValeurChamp(elts[i], champs[j]);
+    return valeurs;
+  }
+  public TableModel tableauUnites(String type) {
+    if (getUnitesAVoir(type).length==0) return null;
+    return new TableUnites(type, this);
+  }
+
+  static public class TableUnites extends AbstractTableModel {
+    String type;
+    Vue vue;
+    Unite[] unites;
+    String[] champs;
+    TableUnites(String type, Vue vue) {
+      super();
+      this.type = type;
+      this.vue = vue;
+    }
+    public int getRowCount() {
+      return vue.getUnitesAVoir(type).length;
+    }
+    public int getColumnCount() {
+      return vue.getNomsChamps(Unite.class, type).length+3;
+    }
+    @Override
+    public String getColumnName(int col) {
+      switch (col) {
+        case 0:
+          return "#Id";
+        case 1:
+          return "From";
+        case 2:
+          return "To";
+        default:
+          return vue.getNomsChamps(Unite.class, type)[col-3];
+      }
+    }
+    public Object getValueAt(int row, int col) {
+      switch (col) {
+        case 0:
+          return row+1;
+        case 1:
+          return vue.getUnitesAVoir(type)[row].getDeb();
+        case 2:
+          return vue.getUnitesAVoir(type)[row].getFin();
+        default:
+          return vue.getValeurChamp(
+                  vue.getUnitesAVoir(type)[row],
+                  vue.getNomsChamps(Unite.class, type)[col-3]);
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/Vue.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVuePresentation.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVuePresentation.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVuePresentation.java	(revision 3653)
@@ -0,0 +1,163 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.vue;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.table.*;
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class VisuVuePresentation extends JPanel implements ActionListener {
+  private VisuVue visuVue;
+  private Vue vue;
+  private JTable tableauChampsAVoir;
+  private JComboBox saisieChampId;
+  private Class<? extends Element> classeSelected;
+  private String typeSelected;
+  private HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir;
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>> modifiabiliteChampsAVoir;
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> niveauxChampsAVoir;
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> positionsChampsAVoir;
+  private HashMap<Class<? extends Element>, HashMap<String, String>> champsId;
+  VisuVuePresentation(VisuVue visuVue, Vue vue,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, String>> champsId,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>> modifiabiliteChampsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> niveauxChampsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> positionsChampsAVoir) {
+    super(new BorderLayout());
+    this.visuVue = visuVue;
+    this.vue = vue;
+    this.champsAVoir = champsAVoir;
+    this.champsId = champsId;
+    this.modifiabiliteChampsAVoir = modifiabiliteChampsAVoir;
+    this.niveauxChampsAVoir = niveauxChampsAVoir;
+    this.positionsChampsAVoir = positionsChampsAVoir;
+    classeSelected = null;
+    typeSelected = null;
+    // Panneau du champ identifiant
+    saisieChampId = new JComboBox();
+    saisieChampId.setEditable(false);
+    saisieChampId.addActionListener(this);
+    JPanel panneauChampId = new JPanel();
+    panneauChampId.add(new JLabel("Choix d'un champ identifiant"));
+    panneauChampId.add(saisieChampId);
+    add(panneauChampId, BorderLayout.NORTH);
+    // Le tableau des champs à visualiser
+    ModeleTableauChampsAVoir donneesChampsAVoir = new ModeleTableauChampsAVoir();
+    tableauChampsAVoir = new JTable(donneesChampsAVoir);
+    JScrollPane scroll2 = new JScrollPane(tableauChampsAVoir);
+    JPanel panneauChampsAVoir = new JPanel();
+    panneauChampsAVoir.add(scroll2);
+    add(panneauChampsAVoir, BorderLayout.CENTER);
+  }
+  void setTypeSelected(Class<? extends Element> classe, String type) {
+    classeSelected = classe;
+    typeSelected = type;
+    reinitialiser();
+  }
+  void reinitialiser() {
+    ((ModeleTableauChampsAVoir) tableauChampsAVoir.getModel()).fireTableDataChanged();
+    saisieChampId.removeActionListener(this);
+    if (typeSelected==null) saisieChampId.setModel(new DefaultComboBoxModel());
+    else {
+      String[] champs = champsAVoir.get(classeSelected).get(typeSelected).toArray(new String[0]);
+      champs = Tableaux.insererStringEnTete(champs, "<aucun>");
+      saisieChampId.setModel(new DefaultComboBoxModel(champs));
+      if (champsId.get(classeSelected).containsKey(typeSelected))
+        saisieChampId.setSelectedItem(champsId.get(classeSelected).get(typeSelected));
+      else saisieChampId.setSelectedIndex(0);
+    }
+    saisieChampId.addActionListener(this);
+  }
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource()==saisieChampId) {
+        if (saisieChampId.getSelectedIndex()==0)
+          champsId.get(classeSelected).remove(typeSelected);
+        else
+          champsId.get(classeSelected).put(typeSelected, (String) saisieChampId.getSelectedItem());
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  private static final String[] nomsColonnes = new String[]{
+    "<html><span style=\"font-weight:900 \">Champ</span>",
+    "<html><span style=\"font-weight:900 \">Niveau</span>",
+    "<html><span style=\"font-weight:900 \">Position</span>",
+    "<html><span style=\"font-weight:900 \">Modifiable ?</span>"
+  };
+  private static final Class[] classesColonnes = new Class[]{String.class, Integer.class, Integer.class, Boolean.class};
+
+  private class ModeleTableauChampsAVoir extends AbstractTableModel {
+    public int getColumnCount() {
+      return nomsColonnes.length;
+    }
+    public int getRowCount() {
+      return (typeSelected==null||!champsAVoir.get(classeSelected).containsKey(typeSelected)) ? 0 : champsAVoir.get(classeSelected).get(typeSelected).size();
+    }
+    public Object getValueAt(int row, int col) {
+      String champ = champsAVoir.get(classeSelected).get(typeSelected).get(row);
+      switch (col) {
+        case 0:
+          return champ;
+        case 1:
+          return niveauxChampsAVoir.get(classeSelected).get(typeSelected).get(champ);
+        case 2:
+          return positionsChampsAVoir.get(classeSelected).get(typeSelected).get(champ);
+        case 3:
+          return modifiabiliteChampsAVoir.get(classeSelected).get(typeSelected).get(champ);
+        default:
+          throw new IndexOutOfBoundsException();
+      }
+    }
+    @Override
+    public String getColumnName(int col) {
+      return nomsColonnes[col];
+    }
+    @Override
+    public Class getColumnClass(int col) {
+      return classesColonnes[col];
+    }
+    @Override
+    public boolean isCellEditable(int row, int col) {
+      if (col==3&&classeSelected==Unite.class) {
+        String champ = champsAVoir.get(classeSelected).get(typeSelected).get(row);
+        String prop = visuVue.getPropChamp(classeSelected, typeSelected, champ);
+        if (Structure.FORME.equals(prop)) return false;
+      }
+      return col>0;
+    }
+    @Override
+    public void setValueAt(Object aValue, int row, int col) {
+      String champ = champsAVoir.get(classeSelected).get(typeSelected).get(row);
+      switch (col) {
+        case 1:
+          niveauxChampsAVoir.get(classeSelected).get(typeSelected).put(champ, (Integer) aValue);
+          return;
+        case 2:
+          positionsChampsAVoir.get(classeSelected).get(typeSelected).put(champ, (Integer) aValue);
+          return;
+        case 3:
+          modifiabiliteChampsAVoir.get(classeSelected).get(typeSelected).put(champ, (Boolean) aValue);
+          return;
+        default:
+          throw new IndexOutOfBoundsException();
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVuePresentation.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVue.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVue.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVue.java	(revision 3653)
@@ -0,0 +1,430 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.vue;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+import javax.swing.text.SimpleAttributeSet;
+import visuAnalec.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class VisuVue extends JFrame implements VueListener, ListSelectionListener, ChangeListener {
+  static private VisuVue instance = null;
+  private Vue vue;
+  // Les données spécifiant la vue (échangées avec vue à l'initialisation et à la validation)
+  private HashMap<Class<? extends Element>, HashMap<String, Boolean>> isTypesAVoir =
+          new HashMap<Class<? extends Element>, HashMap<String, Boolean>>();
+  private HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adressesAVoir =
+          new HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>>();
+  private HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir =
+          new HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>>();
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> niveauxChampsAVoir =
+          new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>>();
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> positionsChampsAVoir =
+          new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>>();
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>> modifiabiliteChampsAVoir =
+          new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>>();
+  private HashMap<Class<? extends Element>, HashMap<String, String>> champsId =
+          new HashMap<Class<? extends Element>, HashMap<String, String>>();
+  private HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>> stylesElements =
+          new HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>>();
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>> stylesValeursElements =
+          new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>>();  // le tableau des types à voir
+  private JTable tableauTypes;
+  private JTabbedPane panneauTabule;
+  VisuVueExtraction visuVueExtraction;
+  VisuVuePresentation visuVuePresentation;
+  VisuVueColoriage visuVueColoriage;
+
+  static public void newVisuVue(Container fenetre, Vue vue) {
+    if (instance!=null) instance.fermerFenetre();
+    instance = new VisuVue(fenetre, vue);
+  }
+
+  @SuppressWarnings("unchecked")
+  private VisuVue(Container fenetre, Vue vue) {
+    super("Gestion de la vue");
+    Point locFenetre = new Point(fenetre.getX()+20, fenetre.getY()+50);
+    Dimension dimFenetre = new Dimension(fenetre.getWidth(), fenetre.getHeight()-30);
+    setLocation(locFenetre);
+    setSize(dimFenetre);
+    this.vue = vue;
+    vue.addEventListener(this);
+    // initialisation des données spécifiant la vue
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      isTypesAVoir.put(classe, new HashMap<String, Boolean>());
+      for (String type : vue.getTypes(classe))
+        isTypesAVoir.get(classe).put(type, false);
+      for (String type : vue.getTypesAVoir(classe))
+        isTypesAVoir.get(classe).put(type, true);
+      champsAVoir.put(classe, new HashMap<String, ArrayList<String>>());
+      adressesAVoir.put(classe, new HashMap<String, ArrayList<Adresse>>());
+      positionsChampsAVoir.put(classe, new HashMap<String, HashMap<String, Integer>>());
+      niveauxChampsAVoir.put(classe, new HashMap<String, HashMap<String, Integer>>());
+      modifiabiliteChampsAVoir.put(classe, new HashMap<String, HashMap<String, Boolean>>());
+      for (String type : vue.getTypes(classe)) {
+        champsAVoir.get(classe).put(type, new ArrayList<String>());
+        adressesAVoir.get(classe).put(type, new ArrayList<Adresse>());
+        niveauxChampsAVoir.get(classe).put(type, new HashMap<String, Integer>());
+        positionsChampsAVoir.get(classe).put(type, new HashMap<String, Integer>());
+        modifiabiliteChampsAVoir.get(classe).put(type, new HashMap<String, Boolean>());
+      }
+      for (String type : vue.getTypesAVoir(classe)) {
+        champsAVoir.get(classe).put(type, vue.getListeChamps(classe, type));
+        for (String nom : vue.getNomsChamps(classe, type))
+          adressesAVoir.get(classe).get(type).add(vue.getAdresseChamps(classe, type, nom));
+      }
+      champsId.put(classe, new HashMap<String, String>());
+      for (String type : vue.getTypesAVoir(classe))
+        if (vue.getChampId(classe, type)!=null)
+          champsId.get(classe).put(type, vue.getChampId(classe, type));
+      for (String type : vue.getTypesAVoir(classe)) {
+        positionsChampsAVoir.get(classe).put(type, vue.getPositionsChampsAVoir(classe, type));
+        niveauxChampsAVoir.get(classe).put(type, vue.getNiveauxChampsAVoir(classe, type));
+        modifiabiliteChampsAVoir.get(classe).put(type, new HashMap<String, Boolean>());
+        for (String champ : vue.getNomsChamps(classe, type))
+          modifiabiliteChampsAVoir.get(classe).get(type).put(champ, vue.isChampModifiable(classe, type, champ));
+      }
+      stylesElements.put(classe, new HashMap<String, SimpleAttributeSet>());
+      for (String type : vue.getTypesAVoir(classe))
+        if (vue.getStyleElements(classe, type)!=null)
+          stylesElements.get(classe).put(type, vue.getStyleElements(classe, type));
+      stylesValeursElements.put(classe, new HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>());
+      for (String type : vue.getTypesAVoir(classe))
+        if (vue.getStyleValeursElements(classe, type)!=null)
+          stylesValeursElements.get(classe).put(type, vue.getStyleValeursElements(classe, type));
+    }
+    // Tableau des types d'éléments à visualiser
+    Box panneauTypes = Box.createVerticalBox();
+
+    panneauTypes.add(Box.createVerticalGlue());
+    ModeleTableauTypes donneesTypes = new ModeleTableauTypes();
+    tableauTypes = new JTable(donneesTypes) {
+      @Override
+      public boolean isCellSelected(int row, int col) {
+        if (col==1) {
+          return false;
+        }
+        String classeType = ((ModeleTableauTypes) getModel()).classesTypes[row];
+        return isRowSelected(row)&&isTypesAVoir.get(GVisu.getClasse(classeType)).get(GVisu.getType(classeType));
+      }
+    };
+
+    tableauTypes.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+    tableauTypes.getSelectionModel().addListSelectionListener(this);
+
+    JScrollPane scroll1 = new JScrollPane(tableauTypes);
+
+    scroll1.setBorder(
+            new TitledBorder("Types d'éléments à visualiser"));
+    panneauTypes.add(scroll1);
+    // les boutons de validation
+
+    panneauTypes.add(Box.createVerticalGlue());
+    JPanel pCommandesValidation = new JPanel(new FlowLayout());
+    JButton valideModifs = new JButton(
+            new GAction("Valider") {
+              public void executer() {
+                validerModifVue();
+              }
+            ;
+    });
+
+    JButton annuleModifs = new JButton(
+            new GAction("Annuler") {
+              public void executer() {
+                annulerModifVue();
+              }
+            ;
+
+    });
+    pCommandesValidation.add(valideModifs, CENTER_ALIGNMENT);
+
+    pCommandesValidation.add(annuleModifs, CENTER_ALIGNMENT);
+
+    panneauTypes.add(pCommandesValidation);
+    // Les panneaux tabulés Extraction, Sélection, Présentation, Coloriage
+    panneauTabule = new JTabbedPane();
+
+    panneauTabule.addChangeListener(
+            this);
+    visuVueExtraction = new VisuVueExtraction(this, vue, champsAVoir, adressesAVoir);
+
+    panneauTabule.add(
+            "Extraction de propriétés", visuVueExtraction);
+    visuVuePresentation = new VisuVuePresentation(this, vue, champsAVoir, champsId,
+            modifiabiliteChampsAVoir, niveauxChampsAVoir, positionsChampsAVoir);
+
+    panneauTabule.add(
+            "Présentation des champs", visuVuePresentation);
+    visuVueColoriage = new VisuVueColoriage(this, vue, champsAVoir, adressesAVoir,
+            stylesElements, stylesValeursElements);
+
+    panneauTabule.add(
+            "Coloriage d'éléments", visuVueColoriage);
+    // cadre global de la fenêtre
+    JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, panneauTypes, panneauTabule);
+
+    setContentPane(split);
+
+    setVisible(
+            true);
+    split.setDividerLocation(
+            0.25);
+//    visuVueExtraction.agencerPanneaux();
+//
+    // initialisation de la sélection d'un premier type à voir (si possible)
+
+
+    for (int i = 0;
+            i<donneesTypes.getRowCount();
+            i++) {
+      if ((Boolean) donneesTypes.getValueAt(i, 1)) {
+        tableauTypes.setRowSelectionInterval(i, i);
+        tableauTypes.setColumnSelectionInterval(0, 0);
+        break;
+      }
+    }
+    // Fermeture de la fenêtre
+
+    setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+
+    addWindowListener(
+            new WindowAdapter() {
+              @Override
+              public void windowClosing(WindowEvent evt) {
+                confirmerFermerFenetre();
+              }
+            });
+  }
+
+  public void stateChanged(ChangeEvent evt) {
+    if (((JTabbedPane) evt.getSource())!=panneauTabule) return;
+    try {
+      switch (panneauTabule.getSelectedIndex()) {
+        case 0:
+          return;
+        case 1:
+          visuVuePresentation.reinitialiser();
+          return;
+        case 2:
+          visuVueColoriage.reinitialiser();
+          return;
+        default:
+          throw new IndexOutOfBoundsException();
+      }
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+
+  private void validerModifVue() {
+    vue.modifierVueParSaisie(isTypesAVoir, adressesAVoir, champsAVoir, champsId, modifiabiliteChampsAVoir,
+            positionsChampsAVoir, niveauxChampsAVoir, stylesElements, stylesValeursElements);
+  }
+
+  private void annulerModifVue() {
+    fermerFenetre();
+  }
+
+  void ajouterChamp(Class<? extends Element> classe, String type, Adresse ad) {
+    String champ = Vue.trouveNomChampParDefaut(ad, champsAVoir.get(classe).get(type));
+    champsAVoir.get(classe).get(type).add(champ);
+    adressesAVoir.get(classe).get(type).add(ad);
+    modifiabiliteChampsAVoir.get(classe).get(type).put(champ, ad.getLongueur()==1);
+    positionsChampsAVoir.get(classe).get(type).put(champ, 0);
+    niveauxChampsAVoir.get(classe).get(type).put(champ, 0);
+  }
+
+  void renommerChamp(Class<? extends Element> classe, String type, int rg, String newNom) {
+    String oldNom = champsAVoir.get(classe).get(type).get(rg);
+    champsAVoir.get(classe).get(type).set(rg, newNom);
+    if (champsId.get(classe).containsKey(type)&&oldNom.equals(champsId.get(classe).get(type))) {
+      champsId.get(classe).put(type, newNom);
+    }
+    modifiabiliteChampsAVoir.get(classe).get(type).put(newNom,
+            modifiabiliteChampsAVoir.get(classe).get(type).get(oldNom));
+    modifiabiliteChampsAVoir.get(classe).get(type).remove(oldNom);
+    positionsChampsAVoir.get(classe).get(type).put(newNom,
+            positionsChampsAVoir.get(classe).get(type).get(oldNom));
+    positionsChampsAVoir.get(classe).get(type).remove(oldNom);
+    niveauxChampsAVoir.get(classe).get(type).put(newNom,
+            niveauxChampsAVoir.get(classe).get(type).get(oldNom));
+    niveauxChampsAVoir.get(classe).get(type).remove(oldNom);
+    if (stylesValeursElements.get(classe).containsKey(type)
+            &&stylesValeursElements.get(classe).get(type).containsKey(oldNom)) {
+      stylesValeursElements.get(classe).get(type).
+              put(newNom, stylesValeursElements.get(classe).get(type).get(oldNom));
+      stylesValeursElements.get(classe).get(type).remove(oldNom);
+    }
+  }
+
+  void supprimerChamp(Class<? extends Element> classe, String type, int rg) {
+    String oldNom = champsAVoir.get(classe).get(type).get(rg);
+    champsAVoir.get(classe).get(type).remove(rg);
+    adressesAVoir.get(classe).get(type).remove(rg);
+    if (champsId.get(classe).containsKey(type)&&oldNom.equals(champsId.get(classe).get(type))) {
+      champsId.get(classe).remove(type);
+      modifiabiliteChampsAVoir.get(classe).get(type).remove(oldNom);
+      positionsChampsAVoir.get(classe).get(type).remove(oldNom);
+      niveauxChampsAVoir.get(classe).get(type).remove(oldNom);
+      if (stylesValeursElements.get(classe).containsKey(type)
+              &&stylesValeursElements.get(classe).get(type).containsKey(oldNom)) {
+        stylesValeursElements.get(classe).get(type).remove(oldNom);
+      }
+    }
+  }
+  String getPropChamp(Class<? extends Element> classe, String type, String champ) {
+    ArrayList<String> champs = champsAVoir.get(classe).get(type);
+    if(champs==null) return "";
+    int ind = champs.indexOf(champ);
+    if(ind<0) return "";
+     String prop = adressesAVoir.get(classe).get(type).get(ind).prop;
+     if(prop==null) return "";
+     return prop;
+   
+  }
+
+  public void valueChanged(ListSelectionEvent evt) {
+    if ((ListSelectionModel) evt.getSource()!=tableauTypes.getSelectionModel())
+      return;
+    try {
+      if (evt.getValueIsAdjusting()) {
+        return;
+      }
+      int row = ((ListSelectionModel) evt.getSource()).getMinSelectionIndex();
+      if (row<0) {
+        visuVueExtraction.setTypeSelected(null, null);
+        visuVuePresentation.setTypeSelected(null, null);
+        visuVueColoriage.setTypeSelected(null, null);
+      } else {
+        String classeType = ((ModeleTableauTypes) tableauTypes.getModel()).classesTypes[row];
+        Class<? extends Element> classeSelected = GVisu.getClasse(classeType);
+        String typeSelected = GVisu.getType(classeType);
+        if (isTypesAVoir.get(classeSelected).get(typeSelected)) {
+          visuVueExtraction.setTypeSelected(classeSelected, typeSelected);
+          visuVuePresentation.setTypeSelected(classeSelected, typeSelected);
+          visuVueColoriage.setTypeSelected(classeSelected, typeSelected);
+        } else {
+          visuVueExtraction.setTypeSelected(null, null);
+          visuVuePresentation.setTypeSelected(null, null);
+          visuVueColoriage.setTypeSelected(null, null);
+        }
+      }
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+
+  public void traiterEvent(Message evt) {
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        fermerFenetre();
+        return;
+      case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+        throw new UnsupportedOperationException("Fenêtre vue présente lors d'un message NEW_CORPUS ???");
+      case MODIF_TEXTE:
+        return;
+      case MODIF_VUE:
+        fermerFenetre();  // ferme même si la modif vient d'ici
+        return;
+      case MODIF_STRUCTURE:
+        fermerFenetre();
+        return;
+      case MODIF_ELEMENT:
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+  }
+
+  private void confirmerFermerFenetre() {
+    try {
+      int rep = JOptionPane.showOptionDialog(this, "Valider les modifications ?",
+              "Fermeture de la fenêtre \"Structure des annotations\"", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+              null, new Object[]{"Oui", "Non", "Annuler"}, "Non");
+      if (rep==2) {
+        return;
+      }
+      if (rep==0) {
+        validerModifVue();
+      }
+      annulerModifVue();
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+
+  private void fermerFenetre() {
+    vue.removeEventListener(this);
+    dispose();
+
+
+  }
+
+  private class ModeleTableauTypes extends AbstractTableModel {
+    String[] classesTypes;
+
+    private ModeleTableauTypes() {
+      super();
+      classesTypes = GVisu.getClassesTypes(vue.getTypes(Unite.class), vue.getTypes(Relation.class), vue.getTypes(Schema.class));
+    }
+
+    public int getColumnCount() {
+      return 2;
+    }
+
+    public int getRowCount() {
+      return classesTypes.length;
+    }
+
+    public Object getValueAt(int row, int col) {
+      String classeType = classesTypes[row];
+      return col==0 ? classeType : isTypesAVoir.get(GVisu.getClasse(classeType)).get(GVisu.getType(classeType));
+    }
+
+    @Override
+    public String getColumnName(int col) {
+      return col==0 ? "Types d'éléments" : "à voir";
+    }
+
+    @Override
+    public Class getColumnClass(int col) {
+      return col==0 ? String.class : Boolean.class;
+    }
+
+    @Override
+    public boolean isCellEditable(int row, int col) {
+      return col==1;
+    }
+
+    @Override
+    public void setValueAt(Object aValue, int row, int col) {
+      if (col==1) {
+        String classeType = classesTypes[row];
+        isTypesAVoir.get(GVisu.getClasse(classeType)).put(GVisu.getType(classeType), (Boolean) aValue);
+        tableauTypes.clearSelection();  // important : à faire même quand aValue est vrai
+        // pour que l'événement "ListSelection change" soit émis dans tous les cas
+        if ((Boolean) aValue) {
+          tableauTypes.setRowSelectionInterval(row, row);
+          tableauTypes.setColumnSelectionInterval(0, 0);
+        }
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVue.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVueExtraction.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVueExtraction.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVueExtraction.java	(revision 3653)
@@ -0,0 +1,243 @@
+package visuAnalec.vue;
+
+import java.awt.BorderLayout;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.TreeExpansionEvent;
+import javax.swing.event.TreeWillExpandListener;
+import javax.swing.table.*;
+import javax.swing.tree.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class VisuVueExtraction extends JPanel implements TreeWillExpandListener {
+  private VisuVue visuVue;
+  private Vue vue;
+  private JTable tableauChampsAVoir;
+  private JTree arbreChampsAExtraire;
+  private JPopupMenuChamp popupMenuChamp;
+  private Class<? extends Element> classeSelected;
+  private String typeSelected;
+  private HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adressesAVoir;
+  private HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir;
+  private JPanel panneauChampsExtraits;
+  private JPanel panneauAExtraire;
+  VisuVueExtraction(VisuVue visuVue, Vue vue,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adressesAVoir) {
+    super(new BorderLayout());
+    this.visuVue = visuVue;
+    this.vue = vue;
+    this.champsAVoir = champsAVoir;
+    this.adressesAVoir = adressesAVoir;
+    classeSelected = null;
+    typeSelected = null;
+//    // Panneau des champs extraits à visualiser
+  panneauChampsExtraits =new JPanel(new BorderLayout());
+    // Le tableau des champs à visualiser
+    ModeleTableauChampsAVoir donneesChampsAVoir = new ModeleTableauChampsAVoir();
+    tableauChampsAVoir = new JTable(donneesChampsAVoir);
+    popupMenuChamp = new JPopupMenuChamp();
+    popupMenuChamp.add(new ActionSupprimerChamp());
+
+    MouseListener popupListener = new MouseAdapter() {
+      @Override
+      public void mousePressed(MouseEvent e) {
+        maybeShowPopup(e);
+      }
+      @Override
+      public void mouseReleased(MouseEvent e) {
+        maybeShowPopup(e);
+      }
+      private void maybeShowPopup(MouseEvent e) {
+        try {
+          if (e.isPopupTrigger()) {
+            popupMenuChamp.rang = tableauChampsAVoir.rowAtPoint(e.getPoint());
+            ((JMenuItem) (popupMenuChamp.getSubElements()[0])).setText("supprimer le champ \"" +
+                    tableauChampsAVoir.getValueAt(popupMenuChamp.rang, 0) + "\"");
+            popupMenuChamp.show(e.getComponent(), e.getX(), e.getY());
+          }
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    };
+    tableauChampsAVoir.addMouseListener(popupListener);
+    tableauChampsAVoir.addKeyListener(new KeyAdapter() {
+      @Override
+      public void keyPressed(KeyEvent e) {
+        try {
+          if (e.getKeyCode() == KeyEvent.VK_DELETE && tableauChampsAVoir.getSelectedRowCount() == 1) {
+            ((ModeleTableauChampsAVoir) tableauChampsAVoir.getModel()).supprimerChamp(tableauChampsAVoir.getSelectedRow());
+          }
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    });
+    JScrollPane scroll2 = new JScrollPane(tableauChampsAVoir);
+    scroll2.setBorder(new TitledBorder("Propriétés à visualiser"));
+    panneauChampsExtraits.add(scroll2, BorderLayout.CENTER);
+
+    // Panneau des champs à extraire
+    panneauAExtraire = new JPanel(new BorderLayout());
+    ModeleArbreChampsAExtraire donneesChampsAExtraire = new ModeleArbreChampsAExtraire(vue);
+    arbreChampsAExtraire = new JTree(donneesChampsAExtraire);
+    arbreChampsAExtraire.addTreeWillExpandListener(this);
+    MouseListener ml2 = new MouseAdapter() {
+      @Override
+      public void mousePressed(MouseEvent e) {
+        try {
+          TreePath selPath = arbreChampsAExtraire.getPathForLocation(e.getX(), e.getY());
+          if (selPath != null && e.getClickCount() == 2) {
+            NoeudChampAExtraire noeud = (NoeudChampAExtraire) selPath.getLastPathComponent();
+            if (noeud.getAllowsChildren()) return;
+            else ajouterChamp(noeud.getAdresse());
+          }
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    };
+    arbreChampsAExtraire.addMouseListener(ml2);
+    JScrollPane scroll3 = new JScrollPane(arbreChampsAExtraire);
+    scroll3.setBorder(new TitledBorder("Extraction de nouvelles propriétés à visualiser"));
+    panneauAExtraire.add(scroll3, BorderLayout.CENTER);
+      // Dimensionnement 
+    add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,panneauChampsExtraits, panneauAExtraire),
+            BorderLayout.CENTER);
+  }
+//  void agencerPanneaux() {
+//        JSplitPane split = (JSplitPane) panneauChampsExtraits.getParent();
+//    split.setDividerLocation(2. / 3);
+//    revalidate();
+//    repaint();
+//  }
+  public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
+    NoeudChampAExtraire noeud = (NoeudChampAExtraire) event.getPath().getLastPathComponent();
+    if(noeud.isLeaf()) {
+      ModeleArbreChampsAExtraire donnees = (ModeleArbreChampsAExtraire) arbreChampsAExtraire.getModel();
+     donnees.setSousArbre(noeud);
+    }
+  }
+  public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
+    return;
+  }
+  void setTypeSelected(Class<? extends Element> classe, String type) {
+    classeSelected = classe;
+    typeSelected = type;
+    ((ModeleTableauChampsAVoir) tableauChampsAVoir.getModel()).fireTableDataChanged();
+    ((ModeleArbreChampsAExtraire) arbreChampsAExtraire.getModel()).setModele(classeSelected, typeSelected);
+  }
+  private void ajouterChamp(Adresse ad) {
+     for (Adresse ad0 : adressesAVoir.get(classeSelected).get(typeSelected)) {
+      if (ad.toString().equals(ad0.toString())) {
+        JOptionPane.showMessageDialog(tableauChampsAVoir.getTopLevelAncestor(),
+                "Ajout impossible : le champ d'adresse  " + ad.toString() + " existe déjà",
+                "Erreur d'ajout de champ", JOptionPane.ERROR_MESSAGE);
+        return;
+      }
+    }
+    visuVue.ajouterChamp(classeSelected, typeSelected, ad);
+    ((ModeleTableauChampsAVoir) tableauChampsAVoir.getModel()).fireTableDataChanged();
+  }
+
+  private class ModeleTableauChampsAVoir extends AbstractTableModel {
+    public int getColumnCount() {
+      return 2;
+    }
+    public int getRowCount() {
+      return (typeSelected == null || !champsAVoir.get(classeSelected).containsKey(typeSelected)) ? 0 : 
+        champsAVoir.get(classeSelected).get(typeSelected).size();
+    }
+    public Object getValueAt(int row, int col) {
+      return col == 0 ? champsAVoir.get(classeSelected).get(typeSelected).get(row) : 
+        adressesAVoir.get(classeSelected).get(typeSelected).get(row).toString();
+    }
+    @Override
+    public String getColumnName(int col) {
+      return col == 0 ? "Noms abrégés des champs" : "Noms complets des propriétés";
+    }
+    @Override
+    public boolean isCellEditable(int row, int col) {
+      return col == 0;
+    }
+    @Override
+    public void setValueAt(Object aValue, int row, int col) {
+      if (col != 0)   throw new IndexOutOfBoundsException();
+    visuVue.renommerChamp(classeSelected, typeSelected, row,  (String) aValue);
+    }
+    void supprimerChamp(int row) {
+      visuVue.supprimerChamp(classeSelected, typeSelected,row);
+      fireTableDataChanged();
+    }
+  }
+
+  private static class JPopupMenuChamp extends JPopupMenu {
+    int rang = -1;
+  }
+
+  private class ActionSupprimerChamp extends AbstractAction {
+    ActionSupprimerChamp() {
+      super("supprimer le champ");
+    }
+    public void actionPerformed(ActionEvent e) {
+      try {
+        int rg = ((JPopupMenuChamp) ((JMenuItem) e.getSource()).getParent()).rang;
+        ((ModeleTableauChampsAVoir) tableauChampsAVoir.getModel()).supprimerChamp(rg);
+      } catch (Throwable ex) {
+        GMessages.erreurFatale(ex);
+      }
+    }
+  }
+
+  private static class ModeleArbreChampsAExtraire extends DefaultTreeModel {
+    Vue vue;
+    ModeleArbreChampsAExtraire(Vue vue) {
+      super(null, true);
+      this.vue = vue;
+    }
+    void setModele(Class<? extends Element> classeRacine, String typeRacine) {
+      if (typeRacine == null) {
+        setRoot(null);
+      } else {
+        NoeudChampAExtraire racine = new NoeudChampAExtraire(
+                new Adresse(new Jalon(Jalon.Origine.ELT_0, classeRacine, typeRacine)));
+        setRoot(racine);
+        setSousArbre(racine);
+      }
+      reload();
+    }
+    void setSousArbre(NoeudChampAExtraire noeud) {
+      Adresse adresse = noeud.getAdresse();
+      for (String prop : vue.getNomsProps(adresse)) {
+        noeud.add(new NoeudChampAExtraire(new Adresse(adresse, prop)));
+      }
+      Jalon[] jalons = vue.getNextJalonsPotentiels(adresse);
+      for (Jalon jalon : jalons) {
+        noeud.add(new NoeudChampAExtraire(new Adresse(adresse, jalon)));
+      }
+    }
+  }
+
+  private static class NoeudChampAExtraire extends DefaultMutableTreeNode {
+    NoeudChampAExtraire(Adresse adresse) {
+      super(adresse, adresse.prop == null);
+    }
+    Adresse getAdresse() {
+      return (Adresse) getUserObject();
+    }
+    @Override
+    public String toString() {
+      if (getAdresse().prop == null) return getAdresse().getLastJalon().toString();
+      return getAdresse().prop;
+    }
+  }
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVueExtraction.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVueColoriage.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVueColoriage.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVueColoriage.java	(revision 3653)
@@ -0,0 +1,434 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.vue;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.util.ArrayList;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.StyleConstants;
+import javax.swing.tree.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class VisuVueColoriage extends JPanel implements TreeWillExpandListener {
+  private VisuVue visuVue;
+  private int indexTab;
+  private Vue vue;
+  private JTable tableauValeursAColorier;
+  private JTree arbreValeursAChoisir;
+  private JPopupMenuValeur popupMenuValeur;
+  private Class<? extends Element> classeSelected;
+  private String typeSelected;
+  private HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir;
+  private HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adressesAVoir;
+  private HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>> stylesElements;
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>> stylesValeursElements;
+  private JPanel panneauValeursChoisies;
+  private JPanel panneauValeursAChoisir;
+  VisuVueColoriage(VisuVue visuVue, Vue vue,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adressesAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>> stylesElements,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>> stylesValeursElements) {
+    super(new BorderLayout());
+    this.visuVue = visuVue;
+    this.vue = vue;
+    this.champsAVoir = champsAVoir;
+    this.adressesAVoir = adressesAVoir;
+    this.stylesElements = stylesElements;
+    this.stylesValeursElements = stylesValeursElements;
+    classeSelected = null;
+    typeSelected = null;
+//    // Panneau des valeurs choisies à colorier
+    panneauValeursChoisies = new JPanel();
+    // Le tableau des valeurs à colorier
+    ModeleTableauValeursAColorier donneesValeursAColorier = new ModeleTableauValeursAColorier();
+    tableauValeursAColorier = new JTable(donneesValeursAColorier);
+    GVisu.CouleurTableEditor couleurcombo =
+            new GVisu.CouleurTableEditor(GVisu.getCouleursEtNoirEtBlanc());
+    tableauValeursAColorier.setDefaultEditor(Color.class, couleurcombo);
+    tableauValeursAColorier.setDefaultRenderer(Color.class, new GVisu.CouleurCellRenderer());
+    popupMenuValeur = new JPopupMenuValeur();
+    popupMenuValeur.add(new ActionSupprimerValeur());
+
+    MouseListener popupListener = new MouseAdapter() {
+      @Override
+      public void mousePressed(MouseEvent e) {
+        maybeShowPopup(e);
+      }
+      @Override
+      public void mouseReleased(MouseEvent e) {
+        maybeShowPopup(e);
+      }
+      private void maybeShowPopup(MouseEvent e) {
+        try {
+          if (e.isPopupTrigger()) {
+            int rg = popupMenuValeur.rang;
+            popupMenuValeur.rang = tableauValeursAColorier.rowAtPoint(e.getPoint());
+            ((JMenuItem) (popupMenuValeur.getSubElements()[0])).setText("supprimer ce coloriage");
+            popupMenuValeur.show(e.getComponent(), e.getX(), e.getY());
+          }
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    };
+    tableauValeursAColorier.addMouseListener(popupListener);
+    tableauValeursAColorier.addKeyListener(new KeyAdapter() {
+      @Override
+      public void keyPressed(KeyEvent e) {
+        try {
+          if (e.getKeyCode()==KeyEvent.VK_DELETE&&tableauValeursAColorier.getSelectedRowCount()==1) {
+            ((ModeleTableauValeursAColorier) tableauValeursAColorier.getModel()).supprimerRangee(
+                    tableauValeursAColorier.getSelectedRow());
+          }
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    });
+    JScrollPane scroll2 = new JScrollPane(tableauValeursAColorier);
+    scroll2.setBorder(new TitledBorder("Elements à colorier"));
+    panneauValeursChoisies.add(scroll2, BorderLayout.CENTER);
+    // Panneau des valeurs à choisir
+    panneauValeursAChoisir = new JPanel(new BorderLayout());
+    // L'arbre des champs à extraire
+    ModeleArbreValeursAChoisir donneesValeursAChoisir =
+            new ModeleArbreValeursAChoisir(vue, champsAVoir, adressesAVoir);
+    arbreValeursAChoisir = new JTree(donneesValeursAChoisir);
+    arbreValeursAChoisir.addTreeWillExpandListener(this);
+    MouseListener ml2 = new MouseAdapter() {
+      @Override
+      public void mousePressed(MouseEvent e) {
+        try {
+          TreePath selPath = arbreValeursAChoisir.getPathForLocation(e.getX(), e.getY());
+          if (selPath!=null&&e.getClickCount()==2) {
+            NoeudValeurAChoisir noeud = (NoeudValeurAChoisir) selPath.getLastPathComponent();
+            if (noeud.getAllowsChildren()) return;
+            else ajouterValeur(noeud.champ, noeud.valeur);
+          }
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    };
+    arbreValeursAChoisir.addMouseListener(ml2);
+    JScrollPane scroll3 = new JScrollPane(arbreValeursAChoisir);
+    scroll3.setBorder(new TitledBorder("Choix de nouvelles valeurs à colorier"));
+    panneauValeursAChoisir.add(scroll3, BorderLayout.CENTER);
+    // Dimensionnement 
+    add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, panneauValeursChoisies, panneauValeursAChoisir),
+            BorderLayout.CENTER);
+  }
+//    void agencerPanneaux() {
+//        JSplitPane split = (JSplitPane) panneauValeursChoisies.getParent();
+//    split.setDividerLocation(2. / 3);
+//    revalidate();
+//    repaint();
+//    }
+  public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
+    NoeudValeurAChoisir noeud = (NoeudValeurAChoisir) event.getPath().getLastPathComponent();
+    if (noeud.isLeaf()) {
+      ModeleArbreValeursAChoisir donnees = (ModeleArbreValeursAChoisir) arbreValeursAChoisir.getModel();
+      donnees.setSousArbre(noeud);
+    }
+  }
+  public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
+    return;
+  }
+  void setTypeSelected(Class<? extends Element> classe, String type) {
+    classeSelected = classe;
+    typeSelected = type;
+    ((ModeleTableauValeursAColorier) tableauValeursAColorier.getModel()).reinitialiser();
+    ((ModeleArbreValeursAChoisir) arbreValeursAChoisir.getModel()).setModele(classeSelected, typeSelected);
+  }
+  private void ajouterValeur(String champ, String valeur) {
+    if (champ.isEmpty())
+      ((ModeleTableauValeursAColorier) tableauValeursAColorier.getModel()).ajouterTousAColorier();
+    else
+      ((ModeleTableauValeursAColorier) tableauValeursAColorier.getModel()).ajouterValeurAColorier(champ, valeur);
+  }
+  void reinitialiser() {
+    ((ModeleTableauValeursAColorier) tableauValeursAColorier.getModel()).reinitialiser();
+    ((ModeleArbreValeursAChoisir) arbreValeursAChoisir.getModel()).setModele(classeSelected, typeSelected);
+  }
+  private static final String[] nomsColonnes = new String[]{
+    "Champ",
+    "Valeur",
+    "<html><span style=\"font-weight:900 \">Gras</span>",
+    "<html><span style=\"font-style:italic \">Italique</span>",
+    "<html><span style=\"text-decoration:underline \">Souligné</span>",
+    "<html><span style=\"color:red \">Couleur</span>",
+    "<html><span style=\"background-color:yellow \">Fond</span>",};
+  private static final Class[] classesColonnes = new Class[]{
+    String.class, String.class, Boolean.class, Boolean.class, Boolean.class, Color.class, Color.class
+  };
+
+  private class ModeleTableauValeursAColorier extends AbstractTableModel {
+    private ArrayList<String> champs = new ArrayList<String>();
+    private ArrayList<String> valeurs = new ArrayList<String>();
+    private ArrayList<Boolean> gras = new ArrayList<Boolean>();
+    private ArrayList<Boolean> italiques = new ArrayList<Boolean>();
+    private ArrayList<Boolean> soulignes = new ArrayList<Boolean>();
+    private ArrayList<Color> couleurs = new ArrayList<Color>();
+    private ArrayList<Color> fonds = new ArrayList<Color>();
+    private void reinitialiser() {
+      viderTableau();
+      AttributeSet att;
+      if (typeSelected!=null) {
+        if (stylesElements.get(classeSelected).containsKey(typeSelected)) {
+          att = stylesElements.get(classeSelected).get(typeSelected);
+          ajouterRangee("", "", att);
+        }
+        if (stylesValeursElements.get(classeSelected).containsKey(typeSelected))
+          for (String champ : stylesValeursElements.get(classeSelected).get(typeSelected).keySet())
+            for (String valeur : stylesValeursElements.get(classeSelected).get(typeSelected).get(champ).keySet()) {
+              att = stylesValeursElements.get(classeSelected).get(typeSelected).get(champ).get(valeur);
+              ajouterRangee(champ, valeur, att);
+            }
+        fireTableDataChanged();
+      }
+    }
+    private void viderTableau() {
+      champs.clear();
+      valeurs.clear();
+      gras.clear();
+      italiques.clear();
+      soulignes.clear();
+      couleurs.clear();
+      fonds.clear();
+    }
+    private void ajouterTousAColorier() {
+      if (!champs.isEmpty()&&champs.get(0).isEmpty()) return;
+      stylesElements.get(classeSelected).put(typeSelected, new SimpleAttributeSet());
+      insererRangee(0, "", "", vue.getStyleTexte());
+      fireTableDataChanged();
+    }
+    private void ajouterValeurAColorier(String champ, String valeur) {
+      for (int i = 0; i<champs.size(); i++)
+        if (champs.get(i).equals(champ)&&valeurs.get(i).equals(valeur)) return;
+      if (!stylesValeursElements.get(classeSelected).containsKey(typeSelected))
+        stylesValeursElements.get(classeSelected).put(typeSelected, new HashMap<String, HashMap<String, SimpleAttributeSet>>());
+      if (!stylesValeursElements.get(classeSelected).get(typeSelected).containsKey(champ))
+        stylesValeursElements.get(classeSelected).get(typeSelected).put(champ, new HashMap<String, SimpleAttributeSet>());
+      stylesValeursElements.get(classeSelected).get(typeSelected).get(champ).put(valeur, new SimpleAttributeSet());
+      ajouterRangee(champ, valeur, vue.getStyleTexte());
+      fireTableDataChanged();
+    }
+    private void ajouterRangee(String champ, String valeur, AttributeSet att) {
+      insererRangee(champs.size(), champ, valeur, att);
+    }
+    private void insererRangee(int row, String champ, String valeur, AttributeSet att) {
+      SimpleAttributeSet att0 = vue.getStyleTexte();
+      champs.add(row, champ);
+      valeurs.add(row, valeur);
+      if (att.isDefined(StyleConstants.Bold))
+        gras.add(row, StyleConstants.isBold(att));
+      else gras.add(row, StyleConstants.isBold(att0));
+      if (att.isDefined(StyleConstants.Italic))
+        italiques.add(row, StyleConstants.isItalic(att));
+      else italiques.add(row, StyleConstants.isItalic(att0));
+      if (att.isDefined(StyleConstants.Underline))
+        soulignes.add(row, StyleConstants.isUnderline(att));
+      else soulignes.add(row, StyleConstants.isUnderline(att0));
+      if (att.isDefined(StyleConstants.Foreground))
+        couleurs.add(row, StyleConstants.getForeground(att));
+      else couleurs.add(row, StyleConstants.getForeground(att0));
+      if (att.isDefined(StyleConstants.Background))
+        fonds.add(row, StyleConstants.getBackground(att));
+      else fonds.add(row, StyleConstants.getBackground(att0));
+      fireTableDataChanged();
+    }
+    void supprimerRangee(int row) {
+      if (champs.get(row).isEmpty())
+        stylesElements.get(classeSelected).remove(typeSelected);
+      else
+        stylesValeursElements.get(classeSelected).get(typeSelected).get(champs.get(row)).remove(valeurs.get(row));
+      champs.remove(row);
+      valeurs.remove(row);
+      gras.remove(row);
+      italiques.remove(row);
+      soulignes.remove(row);
+      couleurs.remove(row);
+      fonds.remove(row);
+
+      fireTableDataChanged();
+    }
+    public int getColumnCount() {
+      return nomsColonnes.length;
+    }
+    public int getRowCount() {
+      return (valeurs.size());
+    }
+    public Object getValueAt(int row, int col) {
+      switch (col) {
+        case 0:
+          if (champs.get(row).isEmpty()) return GVisu.styleDef("tous");
+          return champs.get(row);
+        case 1:
+          if (champs.get(row).isEmpty()) return GVisu.styleDef("toutes");
+          return valeurs.get(row);
+        case 2:
+          return gras.get(row);
+        case 3:
+          return italiques.get(row);
+        case 4:
+          return soulignes.get(row);
+        case 5:
+          return couleurs.get(row);
+        case 6:
+          return fonds.get(row);
+        default:
+          throw new IndexOutOfBoundsException();
+      }
+    }
+    @Override
+    public String getColumnName(int col) {
+      return nomsColonnes[col];
+    }
+    @Override
+    public Class getColumnClass(int col) {
+      return classesColonnes[col];
+    }
+    @Override
+    public boolean isCellEditable(int row, int col) {
+      return col>1;
+    }
+    @Override
+    public void setValueAt(Object aValue, int row, int col) {
+      Boolean valbool;
+      Color valcoul;
+      SimpleAttributeSet att = champs.get(row).isEmpty() ? stylesElements.get(classeSelected).get(typeSelected) : stylesValeursElements.get(classeSelected).get(typeSelected).get(champs.get(row)).get(valeurs.get(row));
+      SimpleAttributeSet att0 = vue.getStyleTexte();
+      switch (col) {
+        case 2:
+          valbool = (Boolean) aValue;
+          gras.set(row, valbool);
+          if (StyleConstants.isBold(att0)==valbool)
+            att.removeAttribute(StyleConstants.Bold);
+          else StyleConstants.setBold(att, valbool);
+          break;
+        case 3:
+          valbool = (Boolean) aValue;
+          italiques.set(row, valbool);
+          if (StyleConstants.isItalic(att0)==valbool)
+            att.removeAttribute(StyleConstants.Italic);
+          else StyleConstants.setItalic(att, valbool);
+          break;
+        case 4:
+          valbool = (Boolean) aValue;
+          soulignes.set(row, valbool);
+          if (StyleConstants.isUnderline(att0)==valbool)
+            att.removeAttribute(StyleConstants.Underline);
+          else StyleConstants.setUnderline(att, valbool);
+          break;
+        case 5:
+          valcoul = (Color) aValue;
+          couleurs.set(row, valcoul);
+          if (StyleConstants.getForeground(att0)==valcoul)
+            att.removeAttribute(StyleConstants.Foreground);
+          else StyleConstants.setForeground(att, valcoul);
+          break;
+        case 6:
+          valcoul = (Color) aValue;
+          fonds.set(row, valcoul);
+          if (StyleConstants.getBackground(att0)==valcoul)
+            att.removeAttribute(StyleConstants.Background);
+          else StyleConstants.setBackground(att, valcoul);
+          break;
+        default:
+          throw new IndexOutOfBoundsException("col = "+col);
+      }
+      fireTableCellUpdated(row, col);
+    }
+  }
+
+  private static class JPopupMenuValeur extends JPopupMenu {
+    int rang = -1;
+  }
+
+  private class ActionSupprimerValeur extends AbstractAction {
+    ActionSupprimerValeur() {
+      super("supprimer le champ");
+    }
+    public void actionPerformed(ActionEvent e) {
+      try {
+        int rg = ((JPopupMenuValeur) ((JMenuItem) e.getSource()).getParent()).rang;
+        ((ModeleTableauValeursAColorier) tableauValeursAColorier.getModel()).supprimerRangee(rg);
+      } catch (Throwable ex) {
+        GMessages.erreurFatale(ex);
+      }
+    }
+  }
+
+  private static class ModeleArbreValeursAChoisir extends DefaultTreeModel {
+    HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champs;
+    HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adresses;
+    Vue vue;
+    ModeleArbreValeursAChoisir(Vue vue, HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAvoir,
+            HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adressesAVoir) {
+      super(null, true);
+      this.champs = champsAvoir;
+      this.adresses = adressesAVoir;
+      this.vue = vue;
+    }
+    void setModele(Class<? extends Element> classeRacine, String typeRacine) {
+      if (typeRacine==null) {
+        setRoot(null);
+      } else {
+        NoeudValeurAChoisir racine = new NoeudValeurAChoisir(
+                classeRacine, typeRacine, null, null);
+        setRoot(racine);
+        setSousArbre(racine);
+      }
+      reload();
+    }
+    void setSousArbre(NoeudValeurAChoisir noeud) {
+      if (noeud.champ==null) {
+        noeud.add(new NoeudValeurAChoisir(noeud.classe, noeud.type, "", GVisu.styleDef("tous les éléments")));
+        for (String champ : champs.get(noeud.classe).get(noeud.type))
+          noeud.add(new NoeudValeurAChoisir(noeud.classe, noeud.type, champ, null));
+      } else {
+        int nochamp = champs.get(noeud.classe).get(noeud.type).indexOf(noeud.champ);
+        for (String valeur : vue.getValeursProp(adresses.get(noeud.classe).get(noeud.type).get(nochamp)))
+          noeud.add(new NoeudValeurAChoisir(noeud.classe, noeud.type, noeud.champ, valeur));
+      }
+    }
+  }
+
+  private static class NoeudValeurAChoisir extends DefaultMutableTreeNode {
+    Class<? extends Element> classe;
+    String type;
+    String champ;
+    String valeur;
+    NoeudValeurAChoisir(Class<? extends Element> classe, String type, String champ, String valeur) {
+      super();
+      this.classe = classe;
+      this.type = type;
+      this.champ = champ;
+      this.valeur = valeur;
+      setAllowsChildren(valeur==null);
+
+    }
+    @Override
+    public String toString() {
+      if (champ==null) return type;
+      if (valeur==null) return champ;
+      return valeur;
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/vue/VisuVueColoriage.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauCommandesSchemas.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauCommandesSchemas.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauCommandesSchemas.java	(revision 3653)
@@ -0,0 +1,524 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.Message.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.elements.*;
+import visuAnalec.texte.*;
+import visuAnalec.texte.PanneauAffTexte.*;
+import visuAnalec.texte.PanneauTexte.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class PanneauCommandesSchemas extends PanneauCommandes implements ActionListener {
+  private PanneauChamps panneauChamps;
+  private TypeComboBox saisieTypeSchemas;
+  private ElementComboBox saisieSchema;
+  private TypeComboBox saisieTypeElt;
+  private ElementComboBox saisieElt;
+  private JButton creeSchema;
+  private JButton supprimeSchema;
+  private JButton ajouteElement;
+  private JButton oteElement;
+  private JButton creeUniteElt;
+  private int[] bornesSelectTexte;
+  /*
+  
+   * CREATION PAR LE PANNEAU EDITEUR
+   */
+  PanneauCommandesSchemas(Vue vue, PanneauAffTexte pTexte, PanneauChamps pChamps) {
+    super(vue, pTexte);
+    JToolBar barre1 = new JToolBar();
+    barre1.setPreferredSize(new Dimension(0, 22));
+//    barre1.setBackground(PanneauTexte.getCouleurFond1());
+    barre1.setAlignmentX(0.0f);
+    //    barre1.setFloatable(false);
+    add(barre1);
+    JToolBar barre2 = new JToolBar();
+    barre2.setPreferredSize(new Dimension(0, 22));
+//    barre2.setBackground(PanneauTexte.getCouleurFond2());
+    barre2.setAlignmentX(0.0f);
+//     barre2.setFloatable(false);
+    add(barre2);
+    panneauChamps = pChamps;
+    saisieTypeSchemas = new TypeComboBox(Schema.class);
+    saisieTypeSchemas.addActionListener(this);
+    saisieSchema = new ElementComboBox();
+    saisieSchema.addActionListener(this);
+    saisieTypeElt = new TypeComboBox(Element.class);
+    saisieTypeElt.addActionListener(this);
+    saisieElt = new ElementComboBox();
+    saisieElt.addActionListener(this);
+    creeSchema = new JButton(new GAction("Créer") {
+      public void executer() {
+        creerSchema();
+      }
+    });
+    supprimeSchema = new JButton(new GAction("Supprimer") {
+      public void executer() {
+        supprimerSchema();
+      }
+    });
+    ajouteElement = new JButton(new GAction("Ajouter") {
+      public void executer() {
+        ajouterElement();
+      }
+    });
+    oteElement = new JButton(new GAction("Oter") {
+      public void executer() {
+        oterElement();
+      }
+    });
+    creeUniteElt = new JButton(new GAction("Créer") {
+      public void executer() {
+        creerUniteElt();
+      }
+    });
+    barre1.addSeparator();
+    barre1.add(new TitreBarre("Schéma : ", PanneauTexte.getCouleurFond1()));
+    barre1.addSeparator();
+    barre1.add(saisieTypeSchemas);
+    barre1.add(saisieSchema);
+    barre1.addSeparator();
+    barre1.add(creeSchema);
+    barre1.addSeparator();
+    barre1.add(supprimeSchema);
+    barre2.addSeparator();
+    barre2.add(new TitreBarre("Elément : ", PanneauTexte.getCouleurFond2()));
+    barre2.addSeparator();
+    barre2.add(saisieTypeElt);
+    barre2.add(saisieElt);
+    barre2.addSeparator();
+    barre2.add(ajouteElement);
+    barre2.add(oteElement);
+    barre2.add(creeUniteElt);
+  }
+
+  /*
+   * COMMANDES UTILISEES PAR LE PANNEAU EDITEUR
+   */
+  public void reinitialiser() {
+    // typiquement, appelé par le panneau éditeur à la suite d'une modif de vue ou de structure
+    saisieTypeSchemas.removeActionListener(this);
+    saisieTypeSchemas.setModele(vue.getTypesSchemasAVoir());
+    saisieTypeSchemas.effSelection();
+    saisieTypeSchemas.addActionListener(this);
+    saisieTypeElt.removeActionListener(this);
+    saisieTypeElt.setModele(vue.getTypes(Unite.class), vue.getTypes(Relation.class), vue.getTypes(Schema.class));
+    saisieTypeElt.effSelection();
+    saisieTypeElt.addActionListener(this);
+    initSaisieSchema();
+    initSaisieElt();
+    etatSelectRien();
+    revalidate();
+    repaint();
+  }
+  public void reafficher() {
+    // potentiellement appelé par le panneau éditeur ?
+    // appelé aussi par  traiterElementEvent
+    if (saisieSchema.pasdeSelection()) {
+      initSaisieSchema();
+      if (saisieElt.pasdeSelection()) {
+        initSaisieElt();
+        etatSelectRien();
+      } else {
+        Element eltCourant = saisieElt.getSelection();
+        initSaisieElt(eltCourant);
+        etatSelectElt(eltCourant);
+      }
+    } else {
+      Schema schCourant = (Schema) saisieSchema.getSelection();
+      initSaisieSchema(schCourant);
+      if (saisieElt.pasdeSelection()) {
+        initSaisieElt();
+        etatSelectSchema(schCourant);
+      } else {
+        Element eltCourant = saisieElt.getSelection();
+        initSaisieElt(eltCourant);
+        etatSelectSchemaElt(schCourant, eltCourant);
+      }
+    }
+  }
+   public void elementSuivant(int sens) {
+    if (sens>0) saisieSchema.gotoSuivant();
+    else saisieSchema.gotoPrecedent();
+  }
+ public Element elementSelectionne() {
+    if (saisieSchema.pasdeSelection()) return null;
+    return saisieSchema.getSelection();
+  }
+  public void editerElement(Element elt) {
+    // appelé par le panneauEditeur : elt est forcément un schéma
+    if (elt.getClass() != Schema.class) throw new UnsupportedOperationException("Erreur : classe incorrecte");
+    editerSchema((Schema) elt);
+  }
+  public void traiterElementEvent(ElementEvent evt) {
+    switch (evt.getModif()) {
+      case AJOUT_SCHEMA:
+      case MODIF_SCHEMA:
+        Schema sch = (Schema) evt.getElement();
+        editerSchema(sch);
+        return;
+      case SUP_SCHEMA:
+        if (evt.getElement() == saisieSchema.getSelection()) {
+          initSaisieSchema();
+          initSaisieElt();
+          etatSelectRien();
+        } else {
+          reafficher();
+        }
+        return;
+      case AJOUT_UNITE:
+        if (saisieTypeElt.getClasseSelection() == Unite.class ||
+                evt.getElement().getType().equals(saisieTypeElt.getTypeSelection())) {
+          initSaisieElt(evt.getElement());
+        }
+        reafficher();
+        return;
+      case SUP_UNITE:
+      case SUP_RELATION:
+      case BORNES_UNITE:
+      case AJOUT_RELATION:
+      case MODIF_VALEUR:
+        reafficher();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas " + evt.getModif() + " oublié dans un switch");
+    }
+  }
+  public void editerSchema(Schema sch) {
+    // appelé  par traiterElementEvent, 
+    // et aussi directement par le panneau éditeur quand il est sollicité par d'autres fenêtres
+    if (!sch.getType().equals(saisieTypeSchemas.getTypeSelection())) {
+      saisieTypeSchemas.removeActionListener(this);
+      saisieTypeSchemas.setSelection(sch.getType());
+      saisieTypeSchemas.addActionListener(this);
+    }
+    initSaisieSchema(sch);
+    saisieSchema.setSelection(sch);
+  }
+  public void editerSchemaElement(Schema sch, Element elt) {
+    // appelé  par le panneau éditeur  sollicité par VisuChaines 
+    if (!sch.getType().equals(saisieTypeSchemas.getTypeSelection())) {
+      saisieTypeSchemas.removeActionListener(this);
+      saisieTypeSchemas.setSelection(sch.getType());
+      saisieTypeSchemas.addActionListener(this);
+    }
+    initSaisieSchema(sch);
+    forceElt(elt);
+  }
+ public void editerElementTypeSchema(Element elt, String typesch) {
+    // appelé  par le panneau éditeur  sollicité par VisuChaines 
+    if (!typesch.equals(saisieTypeSchemas.getTypeSelection())) {
+      saisieTypeSchemas.removeActionListener(this);
+      saisieTypeSchemas.setSelection(typesch);
+      saisieTypeSchemas.addActionListener(this);
+    }
+    initSaisieSchema();
+    forceElt(elt);
+  }
+  public ArrayList<ElementMarque> trouverElementsVises(Unite uniteVisee, TypeMarquage marqueUniteVisee,
+          boolean avecId) {
+    ArrayList<ElementMarque> eltsMarques = new ArrayList<ElementMarque>();
+    ArrayList<Element> eltsVises;
+    Element eltVise;
+    switch (marqueUniteVisee) {
+      case FOND1:
+        eltsVises = Element.trouverElementsParUniteSousjacente(saisieSchema.getElements(), uniteVisee);
+        for (Element elt : eltsVises) eltsMarques.add(new ElementMarque(
+                  elt, marqueUniteVisee, avecId ? saisieSchema.getIdElement(elt) : null));
+        return eltsMarques;
+      case FOND1_2:
+      case FOND2:
+        eltsVises = Element.trouverElementsParUniteSousjacente(saisieElt.getElements(), uniteVisee);
+        for (Element elt : eltsVises) eltsMarques.add(new ElementMarque(
+                  elt, marqueUniteVisee, avecId ? saisieElt.getIdElement(elt) : null));
+        return eltsMarques;
+      case SELECT1:
+        eltVise = saisieSchema.getSelection();
+        eltsMarques.add(new ElementMarque(
+                  eltVise, marqueUniteVisee, avecId ? saisieSchema.getIdElement(eltVise) : null));
+        return eltsMarques;
+      case SELECT1_2:
+      case SELECT2:
+        eltVise = saisieElt.getSelection();
+        eltsMarques.add(new ElementMarque(
+                eltVise, marqueUniteVisee, avecId ? saisieElt.getIdElement(eltVise) : null));
+        return eltsMarques;       
+      default:
+        throw new UnsupportedOperationException("Marquage non prévu : " + marqueUniteVisee);
+
+    }
+  }
+  /*
+   * ACTIONS DE L'UTILISATEUR : CHANGEMENTS D'ETAT
+   */
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource() == saisieTypeSchemas) {
+        initSaisieSchema();
+        if (saisieElt.pasdeSelection()) etatSelectRien();
+        else etatSelectElt(saisieElt.getSelection());
+        return;
+      }
+      if (evt.getSource() == saisieTypeElt) {
+        initSaisieElt();
+        if (saisieSchema.pasdeSelection()) etatSelectRien();
+        else etatSelectSchema((Schema) saisieSchema.getSelection());
+        return;
+      }
+      if (evt.getSource() == saisieSchema) {
+        if (saisieSchema.pasdeSelection()) {
+          if (saisieElt.pasdeSelection()) etatSelectRien();
+          else etatSelectElt(saisieElt.getSelection());
+        } else {
+          if (saisieElt.pasdeSelection()) etatSelectSchema((Schema) saisieSchema.getSelection());
+          else etatSelectSchemaElt((Schema) saisieSchema.getSelection(), saisieElt.getSelection());
+        }
+        return;
+      }
+      if (evt.getSource() == saisieElt) {
+        if (saisieElt.pasdeSelection()) {
+          if (saisieSchema.pasdeSelection()) etatSelectRien();
+          else etatSelectSchema((Schema) saisieSchema.getSelection());
+        } else {
+          if (saisieSchema.pasdeSelection()) etatSelectElt(saisieElt.getSelection());
+          else etatSelectSchemaElt((Schema) saisieSchema.getSelection(), saisieElt.getSelection());
+        }
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : " + evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  @Override
+  public void traiterSourisEvent(SourisEvent evt) {
+    switch (evt.getTypeEvent()) {
+      case SELECT_RIEN:
+        saisieElt.removeActionListener(this);
+        saisieElt.effSelection();
+        saisieElt.addActionListener(this);
+        saisieSchema.effSelection();
+        return;
+      case SELECT_ELEMENT:
+        switch (evt.getMarquageElementVise()) {
+          case SELECT1:
+            forceElt(evt.getElementVise());
+            return;
+          case SELECT2:
+          case SELECT1_2:
+            saisieSchema.effSelection();
+            return;
+          case FOND1:
+            saisieSchema.setSelection(evt.getElementVise());
+            return;
+          case FOND2:
+          case FOND1_2:
+            saisieElt.setSelection(evt.getElementVise());
+            return;
+          default:
+            throw new UnsupportedOperationException("Marquage non prévu : " + evt.getTypeEvent());
+        }
+      case SELECT_TEXTE:
+        saisieElt.removeActionListener(this);
+        saisieElt.effSelection();
+        saisieElt.addActionListener(this);
+        saisieSchema.removeActionListener(this);
+        saisieSchema.effSelection();
+        saisieSchema.addActionListener(this);
+        bornesSelectTexte = evt.getBornesSelectionTexte();
+        etatSelectTexte();
+        return;
+    }
+    throw new UnsupportedOperationException("Evénement non prévu : " + evt.getTypeEvent());
+  }
+
+  /*
+   * ACTIONS DE L'UTILISATEUR : BOUTONS
+   */
+  private void creerSchema() {
+    vue.getCorpus().addSchemaSaisi(saisieTypeSchemas.getTypeSelection(), saisieElt.getSelection());
+  }
+  private void creerUniteElt() {
+    if (vue.getCorpus().checkPresenceUnite(saisieTypeElt.getTypeSelection(), bornesSelectTexte[0], bornesSelectTexte[1]) &&
+            !GMessages.confirmationAction("Dupliquer cette unité  ?")) return;
+    vue.getCorpus().addUniteSaisie(saisieTypeElt.getTypeSelection(),  bornesSelectTexte[0], bornesSelectTexte[1]);
+  }
+  private void supprimerSchema() {
+    if (!GMessages.confirmationAction("Supprimer le schéma sélectionné ?")) return;
+    vue.getCorpus().supSchema((Schema) saisieSchema.getSelection());
+  }
+  private void ajouterElement() {
+    vue.getCorpus().ajouterElementSchemaSaisi(saisieElt.getSelection(), (Schema) saisieSchema.getSelection());
+  }
+  private void oterElement() {
+    vue.getCorpus().oterElementSchema(saisieElt.getSelection(), (Schema) saisieSchema.getSelection());
+  }
+
+  /* 
+   * GESTION INTERNE
+   */
+  private void etatSelectRien() { // ni Sch ni Elt n'ont été saisis
+    if (saisieTypeElt.pasdeSelection()) {
+      if (saisieTypeSchemas.pasdeSelection()) panneauTexte.pasDeMarquage();
+      else panneauTexte.saisir(null,
+                Element.getUnitesSousjacentes(saisieSchema.getElements()), TypeMarquage.FOND1);
+    } else {
+      if (saisieTypeSchemas.pasdeSelection()) panneauTexte.saisir(null,
+                Element.getUnitesSousjacentes(saisieElt.getElements()), TypeMarquage.FOND2);
+      else panneauTexte.saisir(null,
+                Element.getUnitesSousjacentes(saisieSchema.getElements()), TypeMarquage.FOND1,
+                Element.getUnitesSousjacentes(saisieElt.getElements()), TypeMarquage.FOND2);
+    }
+    panneauChamps.effacer();
+    creeSchema.setEnabled(false);
+    supprimeSchema.setEnabled(false);
+    ajouteElement.setEnabled(false);
+    oteElement.setEnabled(false);
+    creeUniteElt.setEnabled(false);
+  }
+  private void etatSelectTexte() { // du texte a été sélectionné
+    if (saisieTypeElt.pasdeSelection()) {
+      if (saisieTypeSchemas.pasdeSelection()) panneauTexte.pasDeMarquage();
+      else panneauTexte.saisir(null,
+                Element.getUnitesSousjacentes(saisieSchema.getElements()), TypeMarquage.FOND1);
+    } else {
+      if (saisieTypeSchemas.pasdeSelection()) panneauTexte.saisir(null,
+                Element.getUnitesSousjacentes(saisieElt.getElements()), TypeMarquage.FOND2);
+      else panneauTexte.saisir(null,
+                Element.getUnitesSousjacentes(saisieSchema.getElements()), TypeMarquage.FOND1,
+                Element.getUnitesSousjacentes(saisieElt.getElements()), TypeMarquage.FOND2);
+    }
+    panneauChamps.effacer();
+    creeSchema.setEnabled(false);
+    supprimeSchema.setEnabled(false);
+    ajouteElement.setEnabled(false);
+    oteElement.setEnabled(false);
+    if (!saisieTypeElt.pasdeSelection() && saisieTypeElt.getClasseSelection() == Unite.class)
+      creeUniteElt.setEnabled(true);
+  }
+  private void etatSelectElt(Element elt) {  // seul Elt a été choisi 
+    if (saisieTypeSchemas.pasdeSelection()) panneauTexte.saisir(elt.getUnite0(),
+              elt.getUnitesSousjacentes(), TypeMarquage.SELECT2);
+    else panneauTexte.saisir(elt.getUnite0(), elt.getUnitesSousjacentes(), TypeMarquage.SELECT2,
+              Element.getUnitesSousjacentes(saisieSchema.getElements()), TypeMarquage.FOND1);
+    panneauChamps.afficher(elt);
+    if (!saisieTypeSchemas.pasdeSelection()) {
+      creeSchema.setEnabled(true);
+      Boutons.setDefaut(creeSchema, true);
+    }
+    supprimeSchema.setEnabled(false);
+    ajouteElement.setEnabled(false);
+    oteElement.setEnabled(false);
+    creeUniteElt.setEnabled(false);
+  }
+  private void etatSelectSchema(Schema sch) { // seul Sch a été choisi
+    if (saisieTypeElt.pasdeSelection()) panneauTexte.saisir(sch.getUnite0(),
+              sch.getUnitesSousjacentes(), TypeMarquage.SELECT1);
+    else panneauTexte.saisir(sch.getUnite0(),
+              sch.getUnitesSousjacentes(), TypeMarquage.SELECT1,
+              Element.getUnitesSousjacentes(filtreSch(saisieElt.getElements(), (Schema[])saisieSchema.getElements())),
+              TypeMarquage.FOND1_2,
+              Element.getUnitesSousjacentes(saisieElt.getElements()), TypeMarquage.FOND2);
+    panneauChamps.afficher(sch);
+    creeSchema.setEnabled(false);
+    supprimeSchema.setEnabled(true);
+    ajouteElement.setEnabled(false);
+    oteElement.setEnabled(false);
+    creeUniteElt.setEnabled(false);
+  }
+  private void etatSelectSchemaElt(Schema sch, Element elt) {
+    if (sch.contient(elt)) etatSelectSchemaEltInterne(sch, elt);
+    else etatSelectSchemaEltExterne(sch, elt);
+  }
+  private void etatSelectSchemaEltInterne(Schema sch, Element elt) {
+    panneauTexte.saisir(elt.getUnite0(),
+            elt.getUnitesSousjacentes(), TypeMarquage.SELECT1_2,
+            sch.getUnitesSousjacentes(), TypeMarquage.SELECT1);
+    panneauChamps.afficher(elt);
+    creeSchema.setEnabled(false);
+    ajouteElement.setEnabled(false);
+    if (sch.getContenu().size() > 1) {
+      oteElement.setEnabled(true);
+      supprimeSchema.setEnabled(false);
+    } else {
+      oteElement.setEnabled(false);
+      supprimeSchema.setEnabled(true);
+    }
+    creeUniteElt.setEnabled(false);
+  }
+  private void etatSelectSchemaEltExterne(Schema sch, Element elt) {
+    panneauTexte.saisir(elt.getUnite0(),
+            sch.getUnitesSousjacentes(), TypeMarquage.SELECT1,
+            elt.getUnitesSousjacentes(), TypeMarquage.SELECT2);
+    panneauChamps.afficher(sch);
+    creeSchema.setEnabled(false);
+    supprimeSchema.setEnabled(false);
+    ajouteElement.setEnabled(true);
+    oteElement.setEnabled(false);
+    creeUniteElt.setEnabled(false);
+  }
+  private void forceElt(Element elt) {
+    if (saisieTypeElt.getClasseSelection() != elt.getClass() || !elt.getType().equals(saisieTypeElt.getTypeSelection())) {
+      saisieTypeElt.removeActionListener(this);
+      saisieTypeElt.setSelection(elt.getClass(), elt.getType());
+      saisieTypeElt.addActionListener(this);
+      initSaisieElt();
+    }
+    saisieElt.setSelection(elt);
+  }
+  private Element[] filtreSch(Element[] elts, Schema[] schs) {
+    ArrayList<Element> elts1 = new ArrayList<Element>();
+    for (Element elt : elts) for(Schema sch: schs) if(sch.getContenu().contains(elt)) {
+      elts1.add(elt);
+      break;
+    }
+    return elts1.toArray(new Element[0]);
+  }
+  private void initSaisieSchema(Schema sch) {
+    saisieSchema.removeActionListener(this);
+    if (saisieTypeSchemas.pasdeSelection()) saisieSchema.setModeleVide();
+    else {
+      String type0 = saisieTypeSchemas.getTypeSelection();
+      Schema[] schemas = vue.getSchemasAVoir(type0);
+      saisieSchema.setModele(schemas, vue.getIdSchemas(type0, schemas));
+    }
+    if (sch == null) saisieSchema.effSelection();
+    else saisieSchema.setSelection(sch);
+    saisieSchema.addActionListener(this);
+    saisieSchema.revalidate();
+  }
+  private void initSaisieSchema() {
+    initSaisieSchema(null);
+  }
+  private void initSaisieElt(Element elt) {
+    saisieElt.removeActionListener(this);
+    if (saisieTypeElt.pasdeSelection()) saisieElt.setModeleVide();
+    else {
+      Class<? extends Element> classe = saisieTypeElt.getClasseSelection();
+      String type = saisieTypeElt.getTypeSelection();
+      saisieElt.setModele(vue.getElements(classe, type), vue.getIdElements(classe, type));
+    }
+    if (elt == null) saisieElt.effSelection();
+    else saisieElt.setSelection(elt);
+    saisieElt.addActionListener(this);
+    saisieElt.revalidate();
+  }
+  private void initSaisieElt() {
+    initSaisieElt(null);
+  }
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauCommandesSchemas.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/VisuStatsCorrelations.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/VisuStatsCorrelations.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/VisuStatsCorrelations.java	(revision 3653)
@@ -0,0 +1,251 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.statistiques;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import visuAnalec.*;
+import visuAnalec.Message.*;
+import visuAnalec.elements.*;
+import visuAnalec.fichiers.*;
+import visuAnalec.texte.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.vue.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class VisuStatsCorrelations extends JFrame
+        implements VueListener, ActionListener, ListSelectionListener {
+  private Vue vue;
+  private ModeleStatsCorrelations donneesCorrelations = new ModeleStatsCorrelations();
+  private Class<? extends Element> classe;
+  private String type;
+  private String champ1;
+  private String champ2;
+  private TypeComboBox saisieTypeElements;
+  private JComboBox saisieChamp1 = new JComboBox();
+  private JComboBox saisieChamp2 = new JComboBox();
+  private JTable tableau;
+  private PanneauOccurrences panneauOccurrences;
+  public VisuStatsCorrelations(Container fenetre, Vue vue, PanneauEditeur pEditeur) {
+    super("Corrélations");
+    Point pos = new Point(fenetre.getX()+20, fenetre.getY()+50);
+    Dimension dim = new Dimension(fenetre.getWidth(), fenetre.getHeight()-30);
+    setLocation(pos);
+    setSize(dim);
+    this.vue = vue;
+    vue.addEventListener(this);
+    // Panneau des commandes
+    Box panneauCommandes = Box.createVerticalBox();
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieType = new JPanel(new FlowLayout());
+    pSaisieType.setBorder(new TitledBorder("Eléments"));
+    saisieTypeElements = new TypeComboBox(Element.class);
+    saisieTypeElements.setModele(vue.getTypesUnitesAVoir(), vue.getTypesRelationsAVoir(),
+            vue.getTypesSchemasAVoir());
+    saisieTypeElements.setMaximumRowCount(saisieTypeElements.getModel().getSize());
+    saisieTypeElements.setEditable(false);
+    saisieTypeElements.addActionListener(this);
+    pSaisieType.add(saisieTypeElements, CENTER_ALIGNMENT);
+    panneauCommandes.add(pSaisieType);
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieChamp1 = new JPanel(new FlowLayout());
+    pSaisieChamp1.setBorder(new TitledBorder("Champ 1 (horizontal)"));
+    saisieChamp1.setEditable(false);
+    saisieChamp1.addActionListener(this);
+    pSaisieChamp1.add(saisieChamp1, CENTER_ALIGNMENT);
+    panneauCommandes.add(pSaisieChamp1);
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieChamp2 = new JPanel(new FlowLayout());
+    pSaisieChamp2.setBorder(new TitledBorder("Champ 2 (vertical)"));
+    saisieChamp2.setEditable(false);
+    saisieChamp2.addActionListener(this);
+    pSaisieChamp2.add(saisieChamp2, CENTER_ALIGNMENT);
+    panneauCommandes.add(pSaisieChamp2);
+    panneauCommandes.add(Box.createVerticalGlue());
+    // Panneau du tableau de résultats
+    JPanel panneauAfficheTableau = new JPanel(new BorderLayout());
+    panneauAfficheTableau.setBorder(new TitledBorder("Résultats"));
+    tableau = new JTable(donneesCorrelations);
+    tableau.setDefaultRenderer(Number.class, new CorrelationsRenderer(donneesCorrelations));
+    tableau.setDefaultRenderer(Object.class, new CorrelationsRenderer(donneesCorrelations));
+    tableau.setName("tableauCorrelations");
+    tableau.setCellSelectionEnabled(true);
+    tableau.setRowHeight(40);
+    tableau.getTableHeader().setPreferredSize(new Dimension(tableau.getPreferredSize().width, 40));
+    tableau.getSelectionModel().addListSelectionListener(this);
+    JScrollPane scroll1 = new JScrollPane(tableau);
+    panneauAfficheTableau.add(scroll1, BorderLayout.CENTER);
+    JPanel pExporterCorrelations = new JPanel(new FlowLayout());
+    JButton exporterCorrelations = new JButton(new GAction("Exporter le tableau") {
+      public void executer() {
+        FichiersTableur.exporterTable(donneesCorrelations);
+      }
+    });
+    pExporterCorrelations.add(exporterCorrelations, CENTER_ALIGNMENT);
+    panneauAfficheTableau.add(pExporterCorrelations, BorderLayout.SOUTH);
+    panneauAfficheTableau.setPreferredSize(new Dimension(
+            getWidth()-panneauCommandes.getPreferredSize().width,
+            panneauCommandes.getPreferredSize().height));
+    // Panneau de visualisation des occurrences
+    panneauOccurrences = new PanneauOccurrences(vue, pEditeur);
+    JScrollPane scrollPanneauOccurrences = new JScrollPane(panneauOccurrences);
+    scrollPanneauOccurrences.setBorder(new TitledBorder("Visualisation des occurrences"));
+    JButton exporterConcordances = new JButton(
+            new GAction("Exporter les concordances") {
+              public void executer() {
+                FichiersTableur.exporterTable(panneauOccurrences.getModeleTableur());
+              }
+            });
+    JPanel pExporterConcordances = new JPanel(new FlowLayout());
+    pExporterConcordances.add(exporterConcordances, CENTER_ALIGNMENT);
+    // cadre global de la fenêtre
+    JPanel bas = new JPanel(new BorderLayout());
+    bas.add(scrollPanneauOccurrences, BorderLayout.CENTER);
+    bas.add(pExporterConcordances, BorderLayout.SOUTH);
+    JSplitPane haut = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+            panneauCommandes, panneauAfficheTableau);
+    JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, haut, bas);
+    getContentPane().add(split);
+    setVisible(true);
+    split.setDividerLocation(2./3);
+    // Fermeture de la fenêtre
+    setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+    addWindowListener(new WindowAdapter() {
+      @Override
+      public void windowClosing(WindowEvent evt) {
+        fermerFenetre();
+      }
+    });
+    // Initialisation
+    saisieTypeElements.effSelection();
+    afficherOccurrences();
+  }
+  private void fermerFenetre() {
+    vue.removeEventListener(this);
+    dispose();
+  }
+  private void initSaisieChamps() {
+    for (JComboBox saisieChamp : new JComboBox[]{saisieChamp1, saisieChamp2}) {
+      saisieChamp.removeActionListener(this);
+      saisieChamp.removeAllItems();
+      if (classe!=null) for (String ch : vue.getNomsChamps(classe, type))
+          saisieChamp.addItem(ch);
+      saisieChamp.setSelectedIndex(-1);
+      saisieChamp.addActionListener(this);
+    }
+    champ1 = champ2 = null;
+  }
+  void afficherOccurrences() {
+    ArrayList<Integer> rows = new ArrayList<Integer>();
+    ArrayList<Integer> cols = new ArrayList<Integer>();
+    for (int row : tableau.getSelectedRows()) {
+      for (int col : tableau.getSelectedColumns()) {
+        if (tableau.isCellSelected(row, col)) {
+          rows.add(row);
+          cols.add(col);
+        }
+      }
+    }
+    panneauOccurrences.init(classe, type,
+            donneesCorrelations.getListeElementsSelected(rows.toArray(new Integer[0]),
+            cols.toArray(new Integer[0]), vue, classe, type, champ1, champ2));
+  }
+  void changerDonnees() {
+    donneesCorrelations.setModele(vue, classe, type, champ1, champ2);
+  }
+  public void traiterEvent(Message evt) {
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        fermerFenetre();
+        return;
+      case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+        throw new UnsupportedOperationException("Fenêtre stat présente lors d'un message NEW_CORPUS ???");
+      case MODIF_TEXTE:
+        afficherOccurrences();
+        return;
+      case MODIF_VUE:
+        fermerFenetre();
+        return;
+      case MODIF_STRUCTURE:
+        switch (((StructureEvent) evt).getModif()) {
+          case AJOUT_VALEUR:
+          case RENOM_VALEUR:
+          case FUSION_VALEUR:
+          case SUPPR_VALEUR:
+          case AJOUT_FORME_UNITE:
+          case VALEUR_PAR_DEFAUT:
+            changerDonnees();
+            return;
+          case AJOUT_TYPE:  // à affiner : trop brutal
+          case AJOUT_TYPE_ET_ELEMENTS:
+          case RENOM_TYPE:
+          case FUSION_TYPE:
+          case SUPPR_TYPE:
+          case AJOUT_PROP:
+          case RENOM_PROP:
+          case FUSION_PROP:
+          case SUPPR_PROP:
+            fermerFenetre();
+            return;
+          default:
+            throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+        }
+      case MODIF_ELEMENT:
+        ElementEvent evtE = (ElementEvent) evt;
+        if (evtE.getModif()!=TypeModifElement.BORNES_UNITE) changerDonnees();
+        else afficherOccurrences();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+  }
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource().equals(saisieTypeElements)) {
+        classe = saisieTypeElements.getClasseSelection();
+        type = saisieTypeElements.getTypeSelection();
+        initSaisieChamps();
+        changerDonnees();
+        return;
+      }
+      if (evt.getSource().equals(saisieChamp1)) {
+        champ1 = (String) saisieChamp1.getSelectedItem();
+        changerDonnees();
+        return;
+      }
+      if (evt.getSource().equals(saisieChamp2)) {
+        champ2 = (String) saisieChamp2.getSelectedItem();
+        changerDonnees();
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.toString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  public void valueChanged(ListSelectionEvent evt) {
+    try {
+      if (evt.getValueIsAdjusting())
+        return;
+      if (evt.getSource().equals(tableau.getSelectionModel())) {
+        afficherOccurrences();
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.toString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/VisuStatsCorrelations.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/GPlanAFC.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/GPlanAFC.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/GPlanAFC.java	(revision 3653)
@@ -0,0 +1,420 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.statistiques;
+
+import JamaPlus.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.plaf.*;
+import visuAnalec.elements.*;
+import visuAnalec.fichiers.FichiersGraphique.*;
+import visuAnalec.statistiques.ModeleStatsGeometrie.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class GPlanAFC extends JComponent
+        implements DonneesGrapheListener, MouseListener, GraphiqueExport {
+
+  private static class Ellipse {
+
+    double xcentre, ycentre;
+    double grandAxe, petitAxe;
+    double xrotation, yrotation;
+
+    private Ellipse(double xc, double yc, double ga, double pa, double xr, double yr) {
+      xcentre = xc;
+      ycentre = yc;
+      petitAxe = pa;
+      grandAxe = ga;
+      xrotation = xr;
+      yrotation = yr;
+    }
+  }
+  private final static int marge = 20;
+  private final static int delta = 1;
+  private final static int bord = marge - delta;
+  private final static int rayon = 3;
+  private final static int epaisseurSelection = 3;
+  private final static double epsilon = 0.0001;
+  private final static BasicStroke ligneEpaisse = new BasicStroke(epaisseurSelection);
+  private final static BasicStroke ligneFine = new BasicStroke();
+  private final static int dimExport = 500;
+  private double xRange, yRange, xMin, yMin;
+  private double[] xPts, yPts;
+  private int nbPts;
+  private Color[] couleurs;
+  private boolean[] etatPts;
+  private Rectangle[] rects;
+  private Ellipse ellipse;
+  private ModeleStatsGeometrie donnees;
+  private JPopupMenu menu;
+  private double echelleExport;  // pour exporter le graphique
+
+  GPlanAFC(ModeleStatsGeometrie donnees) {
+    super();
+    this.donnees = donnees;
+    donnees.addEventListener(this);
+    addMouseListener(this);
+    menu = new JPopupMenu();
+    menu.add(new GAction("Tout déselectionner") {
+
+      public void executer() {
+        deselectionnerTout();
+      }
+    });
+    menu.add(new GAction("Entourer la sélection") {
+
+      public void executer() {
+        entourerSelection();
+      }
+    });
+    menu.add(new GAction("Supprimer les points") {
+
+      public void executer() {
+        supprimerPts();
+      }
+    });
+    ToolTipManager.sharedInstance().registerComponent(this);
+  }
+
+  @Override
+  public JToolTip createToolTip() {
+    JToolTip jt = new JToolTip();
+//    jt.setBackground(JAUNE_TRES_CLAIR);
+    return jt;
+  }
+
+  public void traiterEvent(DonneesGrapheEvent evt) {
+    switch (evt.getType()) {
+      case NEW_DONNEES:
+      case MODIF_DONNEES:
+        setPts(donnees.getPts());
+        couleurs = new Color[donnees.getPts().getRowDimension()];
+        Arrays.fill(couleurs, GVisu.getCouleurSansValeur());
+        etatPts = donnees.getEtatsChoixtPts();
+        clearEllipse();
+        repaint();
+        return;
+      case NEW_COORDS:
+        setPts(donnees.getPts());
+        repaint();
+        return;
+      case CLEAR_DONNEES:
+        clearPts();
+        repaint();
+        return;
+      case NEW_COULEURS:
+        couleurs = donnees.getCouleurs();
+        repaint();
+        return;
+      case NEW_SELECT_PTS:
+        etatPts = donnees.getEtatsChoixtPts();
+        repaint();
+        return;
+      default:
+        throw new UnsupportedOperationException("cas " + evt.getType() + " non traité");
+    }
+  }
+
+  public void mouseClicked(MouseEvent e) {
+    try {
+      ArrayList<Integer> nos = getPts(getMousePosition());
+      if (!nos.isEmpty() && e.getButton() == MouseEvent.BUTTON1) {
+        clearEllipse();
+        donnees.majPtsChoisis(nos);
+      }
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+
+  public void mousePressed(MouseEvent e) {
+    try {
+      if (e.isPopupTrigger()) {
+        showPopup(e);
+      }
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+
+  public void mouseReleased(MouseEvent e) {
+    try {
+      if (e.isPopupTrigger()) {
+        showPopup(e);
+      }
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+
+  private void showPopup(MouseEvent e) {
+    menu.show(e.getComponent(), e.getX(), e.getY());
+  }
+
+  public void mouseEntered(MouseEvent e) {
+  }
+
+  public void mouseExited(MouseEvent e) {
+  }
+
+  @Override
+  public String getToolTipText() {
+    Point pt = getMousePosition();
+    if (pt == null) return "";
+    ArrayList<Integer> nopts = getPts(pt);
+    if (nopts.isEmpty()) return "";
+    ArrayList<ArrayList<String>> textesEtIds = donnees.getTexteIdElements(nopts);
+    return GVisu.styleIdTooltip(textesEtIds.get(0), textesEtIds.get(1));
+  }
+
+  private void deselectionnerTout() {
+    donnees.setPtsChoisis(new ArrayList<Integer>());
+    clearEllipse();
+  }
+
+  private void entourerSelection() {
+    ArrayList<Integer> nos = setEllipse(donnees.getPts(), donnees.getEtatsChoixtPts());
+    donnees.setPtsChoisis(nos);
+  }
+
+  private void supprimerPts() {
+    int nb = Tableaux.compterValeursVraies(donnees.getEtatsChoixtPts());
+    if (nb == 0) return;
+    if (!GMessages.confirmationAction("Supprimer " + nb
+            + " élément(s) de la représentation ?")) return;
+    donnees.supPtsChoisis();
+  }
+
+  private void setPts(Matrix Pts) {
+    nbPts = Pts.getRowDimension();
+    if (nbPts == 0) {
+      clearPts();
+      return;
+    }
+    xMin = Pts.minColumn(0);
+    yMin = Pts.minColumn(1);
+    xRange = Pts.maxColumn(0) - xMin;
+    yRange = Pts.maxColumn(1) - yMin;
+    xPts = new double[nbPts];
+    yPts = new double[nbPts];
+    rects = new Rectangle[nbPts];
+    for (int i = 0; i < nbPts; i++) {
+      xPts[i] = Pts.get(i, 0) - xMin;
+      yPts[i] = Pts.get(i, 1) - yMin;
+    }
+    ellipse = null;
+  }
+
+  private void clearPts() {
+    nbPts = 0;
+    xRange = 0;
+    yRange = 0;
+    xPts = new double[0];
+    yPts = new double[0];
+    rects = new Rectangle[0];
+    ellipse = null;
+  }
+
+  private void setEtatPts(boolean[] etats) {
+    etatPts = etats;
+  }
+
+  private void setCouleurs(Color[] couleurs) {
+    this.couleurs = couleurs;
+  }
+
+  private ArrayList<Integer> setEllipse(Matrix Pts, boolean[] aentourer) {
+    ArrayList<Integer> listenos = new ArrayList<Integer>();
+    for (int i = 0; i < aentourer.length; i++) if (aentourer[i])
+        listenos.add(i);
+    if (listenos.isEmpty()) return listenos;
+    Matrix PtsEntoures = getPtsUniqueCoord(Pts, listenos);
+    SingularValueDecomposition svd = new SingularValueDecomposition(PtsEntoures.columnCovariance());
+    Matrix C = PtsEntoures.columnMean();
+    double xcentre = C.get(0, 0);
+    double ycentre = C.get(0, 1);
+    Matrix U = svd.getU();
+    double xrotation = U.get(0, 0);
+    double yrotation = U.get(0, 1);
+    double[] s = svd.getSingularValues();
+    Matrix OPts = Pts.firstLineMinus(C).times(U);
+    double[] d2Pts = new double[nbPts];
+    double maxd2Pts = 0;
+    if (s[1] > epsilon) {  // cas général
+      for (int i = 0; i < nbPts; i++) {
+        d2Pts[i] = (OPts.get(i, 0) * OPts.get(i, 0)) / s[0]
+                + (OPts.get(i, 1) * OPts.get(i, 1)) / s[1];
+        if (aentourer[i]) maxd2Pts = Math.max(maxd2Pts, d2Pts[i]);
+      }
+      listenos.clear();
+      for (int i = 0; i < nbPts; i++) if (d2Pts[i] <= maxd2Pts) listenos.add(i);
+    } else if (s[0] > epsilon) { // tous les points sont alignés
+      for (int i = 0; i < nbPts; i++) {
+        d2Pts[i] = (OPts.get(i, 0) * OPts.get(i, 0)) / s[0];
+        if (aentourer[i]) maxd2Pts = Math.max(maxd2Pts, d2Pts[i]);
+      }
+      listenos.clear();
+      for (int i = 0; i < nbPts; i++)
+        if (Math.abs(OPts.get(i, 1)) < epsilon && d2Pts[i] <= maxd2Pts)
+          listenos.add(i);
+    }  // si tous les points sont confondus : on garde listenos et max2Pts=0
+    double r = Math.sqrt(maxd2Pts);
+    double grandaxe = r * Math.sqrt(s[0]);
+    double petitaxe = r * Math.sqrt(s[1]);
+    ellipse = new Ellipse(xcentre - xMin, ycentre - yMin,
+            grandaxe, petitaxe, xrotation, yrotation);
+    return listenos;
+  }
+
+  private void clearEllipse() {
+    ellipse = null;
+  }
+
+  private ArrayList<Integer> getPts(Point pt) {
+    ArrayList<Integer> nos = new ArrayList<Integer>();
+    for (int no = 0; no < nbPts; no++) {
+      if (rects[no].contains(pt)) {
+        nos.add(no);
+      }
+    }
+    return nos;
+  }
+
+  private static Matrix getPtsUniqueCoord(Matrix Pts, ArrayList<Integer> nos) {
+    ArrayList<Integer> noselects = new ArrayList<Integer>();
+    double dx, dy;
+    for (int i : nos) {
+      boolean unique = true;
+      for (int i1 : noselects) {
+        dx = Pts.get(i, 0) - Pts.get(i1, 0);
+        dy = Pts.get(i, 1) - Pts.get(i1, 1);
+        if (dx * dx + dy * dy < epsilon) {
+          unique = false;
+          break;
+        }
+      }
+      if (unique) noselects.add(i);
+    }
+    int[] nosels = new int[noselects.size()];
+    for (int i = 0; i < nosels.length; i++) nosels[i] = noselects.get(i);
+    return Pts.getMatrix(nosels, 0, 1);
+  }
+
+  @Override
+  public void paintComponent(Graphics g0) {
+    if (nbPts == 0) return;
+    Graphics2D g = (Graphics2D) g0;
+    double echelle;
+    int x0, y0, xrg, yrg, x, y;
+    Dimension dim = getSize();
+    if (xRange == 0 && yRange == 0) {
+      x0 = (int) Math.round((dim.width) / 2.0);
+      xrg = 0;
+      y0 = (int) Math.round((dim.height) / 2.0);
+      yrg = 0;
+      echelle = 0;
+    } else if (xRange == 0) {   // impossible en fait : xRange >= yRange
+      x0 = (int) Math.round((dim.width) / 2.0);
+      xrg = 0;
+      y0 = marge;
+      echelle = (dim.height - 2 * marge) / yRange;
+      yrg = (int) Math.round(yRange * echelle);
+    } else if (yRange == 0) {
+      echelle = (dim.width - 2 * marge) / xRange;
+      xrg = (int) Math.round(xRange * echelle);
+      x0 = marge;
+      yrg = 0;
+      y0 = (int) Math.round((dim.height) / 2.0);
+    } else {
+      double echx = (dim.width - 2 * marge) / xRange;
+      double echy = (dim.height - 2 * marge) / yRange;
+      if (echx < echy) {
+        echelle = echx;
+        xrg = (int) Math.round(xRange * echelle);
+        yrg = (int) Math.round(yRange * echelle);
+        x0 = marge;
+        y0 = (int) Math.round((dim.height - yrg) / 2.0);
+      } else {
+        echelle = echy;
+        xrg = (int) Math.round(xRange * echelle);
+        yrg = (int) Math.round(yRange * echelle);
+        x0 = (int) Math.round((dim.width - xrg) / 2.0);
+        y0 = marge;
+      }
+    }
+    g.drawRect(x0 - bord, y0 - bord, xrg + 2 * bord, yrg + 2 * bord);
+    for (int i = 0; i < nbPts; i++) {
+      x = x0 + (int) Math.round(echelle * xPts[i]);
+      y = y0 + (int) Math.round(echelle * yPts[i]);
+      g.setColor(couleurs[i]);
+      rects[i] = new Rectangle(x - rayon, y - rayon, 2 * rayon, 2 * rayon);
+      g.fillOval(x - rayon - 1, y - rayon - 1, 2 * rayon + 2, 2 * rayon + 2);
+      g.setStroke(etatPts[i] ? ligneEpaisse : ligneFine);
+      g.setColor(Color.BLACK);
+      int epais = etatPts[i] ? epaisseurSelection - 1 : 0;
+      g.drawOval(x - (rayon + epais), y - (rayon + epais), 2 * (rayon + epais), 2 * (rayon + epais));
+    }
+    if (ellipse == null) return;
+    double xc = x0 + ellipse.xcentre * echelle;
+    double yc = y0 + ellipse.ycentre * echelle;
+    double ga = ellipse.grandAxe * echelle + rayon + epaisseurSelection - 1;
+    double pa = ellipse.petitAxe * echelle + rayon + epaisseurSelection - 1;
+    Ellipse2D.Double ell = new Ellipse2D.Double(xc - ga, yc - pa, 2 * ga, 2 * pa);
+    g.setStroke(ligneFine);
+    g.draw(AffineTransform.getRotateInstance(ellipse.xrotation, ellipse.yrotation, xc, yc).
+            createTransformedShape(ell));
+  }
+
+  public Dimension initExport() {
+    if (nbPts == 0) return new Dimension(dimExport, dimExport);
+    if (xRange == 0 && yRange == 0) {
+      echelleExport = 0;
+      return new Dimension(2 * marge, 2 * marge);
+    } else if (xRange == 0) { // impossible, en fait
+      echelleExport = dimExport / yRange;
+      return new Dimension(2 * marge, dimExport + 2 * marge);
+    } else if (yRange == 0) {
+      echelleExport = dimExport / xRange;
+      return new Dimension(dimExport + 2 * marge, 2 * marge);
+    } else {
+      echelleExport = dimExport / xRange;
+      return new Dimension(dimExport + 2 * marge,
+              ((int) Math.round(yRange * echelleExport)) + 2 * marge);
+    }
+  }
+
+  public Rectangle getCadre() {
+    if (nbPts == 0) return null;
+    if (xRange == 0 && yRange == 0)
+      return new Rectangle(delta, delta, 2 * bord, 2 * bord);
+    else if (xRange == 0)
+      return new Rectangle(delta, delta, 2 * bord, dimExport + 2 * bord);
+    else if (yRange == 0)
+      return new Rectangle(delta, delta, dimExport + 2 * bord, 2 * bord);
+    else
+      return new Rectangle(delta, delta, dimExport + 2 * bord,
+              ((int) Math.round(yRange * echelleExport)) + 2 * bord);
+  }
+
+  public CercleColore[] getCerclesColores() {
+    CercleColore[] cercles = new CercleColore[nbPts];
+    for (int i = 0; i < nbPts; i++) {
+      cercles[i] = new CercleColore();
+      cercles[i].cx = marge + (int) Math.round(echelleExport * xPts[i]);
+      cercles[i].cy = marge + (int) Math.round(echelleExport * yPts[i]);
+      cercles[i].couleur = couleurs[i];
+      cercles[i].r = rayon;
+    }
+    return cercles;
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/GPlanAFC.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/GBarres.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/GBarres.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/GBarres.java	(revision 3653)
@@ -0,0 +1,101 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package visuAnalec.statistiques;
+
+import java.awt.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.plaf.*;
+import visuAnalec.util.GMessages;
+
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class GBarres extends JComponent implements TableModelListener {
+
+  ModeleStatsFrequences modele;
+  BarresPainter painter;
+
+  GBarres(ModeleStatsFrequences modele) {
+    super();
+    setUI(painter = new BarresPainter());
+    this.modele = modele;
+//    System.out.println("---\nCréation : " + getPreferredSize() + " -> " + getSize());
+
+
+  }
+
+  public void tableChanged(TableModelEvent evt) {
+    try {
+      ArrayList<Float> longueurs = new ArrayList<Float>();
+      ArrayList<String> noms = new ArrayList<String>();
+      for (int i = 0; i < modele.getRowCount() - 1; i++) {
+        if ((Integer) modele.getValueAt(i, 1) > 0) {
+          longueurs.add((Float) modele.getValueAt(i, 2));
+          noms.add((String) modele.getValueAt(i, 0));
+        }
+      }
+//    System.out.println(noms + "\n" + getPreferredSize() + " -> " + getSize());
+      painter.setLongueursBarres(longueurs.toArray(new Float[0]));
+      painter.setNomsBarres(noms.toArray(new String[0]));
+      repaint();
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+}
+class BarresPainter extends ComponentUI {
+
+  private String[] nomsBarres = new String[0];
+  private Float[] longueursBarres = new Float[0];
+  static BarresPainter barresUI = new BarresPainter();
+  private Color[] couleurs = new Color[]{Color.BLUE, Color.CYAN, Color.GREEN, Color.MAGENTA,
+    Color.RED, Color.YELLOW, Color.LIGHT_GRAY, Color.ORANGE, Color.PINK
+  };
+  private int margeX = 5;
+  private int interligneY = 5;
+
+  void setLongueursBarres(Float[] longueurs) {
+    longueursBarres = longueurs;
+  }
+
+  void setNomsBarres(String[] noms) {
+    nomsBarres = noms;
+  }
+
+  @Override
+  public void paint(Graphics g, JComponent c) {
+    Dimension dim = c.getSize();
+//    System.out.println(dim);
+    int hauteurMin = g.getFontMetrics().getHeight() + 2;
+    int nbBarres = nomsBarres.length;
+    g.setColor(Color.BLACK);
+    g.drawLine(margeX, interligneY, margeX, 2 * interligneY + (hauteurMin + interligneY) * nbBarres);
+    int largeurMaxTexte = 0;
+    for (int i = 0; i < nbBarres; i++) {
+      largeurMaxTexte = Math.max(largeurMaxTexte,
+              SwingUtilities.computeStringWidth(g.getFontMetrics(), nomsBarres[i]));
+    }
+    for (int i = 0; i < nbBarres; i++) {
+      int y = interligneY + (hauteurMin + interligneY) * i;
+      int longueur = Math.round((dim.width - largeurMaxTexte) * longueursBarres[i] / 100);
+      g.setColor(Color.LIGHT_GRAY); // couleurs[i % couleurs.length]);
+      g.fillRect(margeX, y, longueur, hauteurMin);
+      g.setColor(Color.BLACK);
+      g.drawRect(margeX, y, longueur, hauteurMin);
+      g.drawString(nomsBarres[i], 2 * margeX + longueur, y + hauteurMin);
+    }
+  }
+
+  public static ComponentUI createUI(JComponent c) {
+    return barresUI;
+  }
+}
+
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/GBarres.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/ModeleStatsFrequences.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/ModeleStatsFrequences.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/ModeleStatsFrequences.java	(revision 3653)
@@ -0,0 +1,90 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.statistiques;
+
+//import donnees.*;
+import java.util.*;
+import javax.swing.table.*;
+import visuAnalec.elements.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class ModeleStatsFrequences extends AbstractTableModel {
+  private String[] nomsValeurs;
+  private int[] nbOcc;
+  private String[] nomsColonnes;
+  private int totalOcc;
+ public ModeleStatsFrequences() {
+    super();
+    initialise();
+  }
+private void initialise() {
+    nomsValeurs = new String[0];
+    nbOcc = new int[]{0};
+    nomsColonnes = new String[]{"", "Nb d'occurrences", "Fréquence (%)"};
+    totalOcc = 0;
+  }
+  public int getRowCount() {
+    return nomsValeurs.length + 2;
+  }
+  public int getColumnCount() {
+    return 3;
+  }
+  @Override
+  public String getColumnName(int col) {
+    return nomsColonnes[col];
+  }
+  public Object getValueAt(int row, int col) {
+    switch (col) {
+      case 0:
+        return row == nomsValeurs.length + 1 ? "TOTAL" : row == nomsValeurs.length ? "<aucune valeur>" : nomsValeurs[row];
+      case 1:
+        return row == nomsValeurs.length + 1 ? totalOcc : nbOcc[row];
+      case 2:
+        return row == nomsValeurs.length + 1 ? 100.0f : Math.round(nbOcc[row] * 10000.0f / totalOcc) / 100.0f;
+      default:
+        return null;
+    }
+  }
+  Element[] getListeElementsRowsSelected(int[] rows, Vue vue, Class<? extends Element> classe, String type,
+          String champCible, String champFiltre, String[] valeursChampFiltre) {
+    if (rows.length == 0 || classe==null) return (new Unite[0]);
+    ArrayList<String> vals = new ArrayList<String>();
+    for (int row : rows) {
+      if (row == nomsValeurs.length + 1) {
+        return vue.getDoubleSelectionOccurrences(classe, type, null, vals.toArray(new String[0]), 
+                champFiltre, valeursChampFiltre);
+      }
+      vals.add(row == nomsValeurs.length ? "" : nomsValeurs[row]);
+    }
+    return vue.getDoubleSelectionOccurrences(classe, type, champCible, vals.toArray(new String[0]), 
+            champFiltre, valeursChampFiltre);
+  }
+  private void setModeleVide() {
+    initialise();
+    fireTableDataChanged();
+  }
+  void setModele(Vue vue, Class<? extends Element> classe, String type, String champCible,
+          String champFiltre, String[] valeursChampFiltre) {
+    if (classe==null || champCible == null || vue.getNbElementsAVoir(classe, type) == 0) {
+      setModeleVide();
+      return;
+    }
+    nomsValeurs = vue.getValeursChamp(classe, type, champCible);
+    nbOcc = new int[nomsValeurs.length + 1];
+    HashMap<String, Integer> compte =
+            vue.compterOccurrencesFiltrees(classe, type, champCible, champFiltre, valeursChampFiltre);
+    totalOcc = 0;
+    for (int row = 0; row < nomsValeurs.length + 1; row++) {
+      nbOcc[row] = compte.get(row == nomsValeurs.length ? "" : nomsValeurs[row]);
+      totalOcc += nbOcc[row];
+    }
+    fireTableDataChanged();
+  }
+}
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/ModeleStatsFrequences.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/ModeleStatsGeometrie.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/ModeleStatsGeometrie.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/ModeleStatsGeometrie.java	(revision 3653)
@@ -0,0 +1,188 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.statistiques;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+import JamaPlus.*;
+import java.awt.*;
+import java.util.*;
+import java.util.ArrayList;
+import visuAnalec.elements.*;
+import visuAnalec.vue.*;
+
+public class ModeleStatsGeometrie {
+  public enum TypeEventDonneesGraphe {
+    NEW_DONNEES,
+    MODIF_DONNEES,
+    CLEAR_DONNEES,
+    NEW_COORDS,
+    NEW_COULEURS,
+    NEW_SELECT_PTS
+  }
+
+  public interface DonneesGrapheListener extends EventListener {
+    void traiterEvent(DonneesGrapheEvent e);
+  }
+
+  public class DonneesGrapheEvent extends EventObject {
+    private TypeEventDonneesGraphe type;
+    DonneesGrapheEvent(Object source, TypeEventDonneesGraphe type) {
+      super(source);
+      this.type = type;
+    }
+    public TypeEventDonneesGraphe getType() {
+      return type;
+    }
+  }
+  private ArrayList<DonneesGrapheListener> listeCorrespondants = new ArrayList<DonneesGrapheListener>();
+  void addEventListener(DonneesGrapheListener correspondant) {
+    listeCorrespondants.add(correspondant);
+  }
+  void removeEventListener(DonneesGrapheListener correspondant) {
+    listeCorrespondants.remove(correspondant);
+  }
+  private void fireDonneesGrapheEvent(DonneesGrapheEvent evt) {
+    for (Object corresp : listeCorrespondants.toArray()) {
+      ((DonneesGrapheListener) corresp).traiterEvent(evt);
+    }
+  }
+  private Vue vue;
+  private Class<? extends Element> classe;
+  private String type;
+  private String[] champsPertinents;
+  private Element[] elementsRetenus;
+  private Matrix Pts;
+  private Color[] couleursPts;
+  private ArrayList<Integer> nosPtsChoisis;
+  public Class<? extends Element> getClasseElements() {
+    return classe;
+  }
+  public String getTypeElements() {
+    return type;
+  }
+  public Matrix getPts() {
+    return Pts;
+  }
+  public Color[] getCouleurs() {
+    return couleursPts;
+  }
+  public boolean[] getEtatsChoixtPts() {
+    boolean[] etats = new boolean[elementsRetenus.length];
+    for (int no : nosPtsChoisis) {
+      etats[no] = true;
+    }
+    return etats;
+  }
+  public ArrayList<ArrayList<String>> getTexteIdElements(ArrayList<Integer> nos) {
+    ArrayList<ArrayList<String>> textesIds = new ArrayList<ArrayList<String>>();
+    ArrayList<String> textes = new ArrayList<String>();
+    ArrayList<String> ids = new ArrayList<String>();
+    for (int i = 0; i<nos.size(); i++) {
+      Element elt = elementsRetenus[nos.get(i)];
+      textes.add(vue.getTexteUnite(elt.getUnite0()));
+      ids.add(vue.getIdElement(elt));
+    }
+    textesIds.add(textes);
+    textesIds.add(ids);
+    return textesIds;
+  }
+  public Element[] getListeElementsChoisis() {
+    Element[] liste = new Element[nosPtsChoisis.size()];
+    for (int i = 0; i<liste.length; i++) {
+      liste[i] = elementsRetenus[nosPtsChoisis.get(i)];
+    }
+    Arrays.sort(liste);
+    return liste;
+  }
+//  public Unite getDerniereUniteChoisie() {
+//    if (nosPtsChoisis.isEmpty()) {
+//      return null;
+//    }
+//    return unitesSelectionnees[nosPtsChoisis.get(nosPtsChoisis.size() - 1)];
+//  }
+  void initialise(Vue vue, Class<? extends Element> classe, String type) {
+    this.vue = vue;
+    this.type = type;
+    this.classe = classe;
+    if (classe==null) {
+      champsPertinents = new String[0];
+      elementsRetenus = new Element[0];
+      Pts = null;
+      fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.CLEAR_DONNEES));
+      return;
+    }
+    champsPertinents = vue.getNomsChamps(classe, type);
+    elementsRetenus = vue.getElementsAVoir(classe, type);
+    if (calculerCoord()) {
+      nosPtsChoisis = new ArrayList<Integer>();
+      fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.NEW_DONNEES));
+    } else {
+      Pts = null;
+      fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.CLEAR_DONNEES));
+    }
+  }
+  void majChampsSelect(String[] champsSelect) {
+    champsPertinents = champsSelect;
+    if (champsSelect.length>0&&calculerCoord()) {
+      fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.NEW_COORDS));
+    } else {
+      Pts = null;
+      fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.CLEAR_DONNEES));
+    }
+  }
+  void majChampAffiche(String champAffiche, HashMap<String, Color> couleurValeur) {
+    couleursPts = new Color[elementsRetenus.length];
+    for (int i = 0; i<elementsRetenus.length; i++) {
+      couleursPts[i] = couleurValeur.get(vue.getValeurChamp(elementsRetenus[i], champAffiche));
+    }
+    fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.NEW_COULEURS));
+  }
+  boolean calculerCoord() {
+//    Matrix mat = vue.getMatrice(classe, type, champsPertinents, elementsRetenus);
+    SparseMatrix mat = vue.getMatriceCreuse(classe, type, champsPertinents, elementsRetenus);
+    Matrix CP = mat.afc().getCP();
+    if (CP==null) return false;
+    if (CP.getColumnDimension()<2) {
+      Pts = new Matrix(elementsRetenus.length, 2);
+      if (CP.getColumnDimension()==1)
+        Pts.setMatrix(0, elementsRetenus.length-1, 0, 0, CP);
+    } else {
+      Pts = CP.getMatrix(0, elementsRetenus.length-1, 0, 1);
+    }
+    return true;
+  }
+  void setPtsChoisis(ArrayList<Integer> nos) {
+    nosPtsChoisis = nos;
+    fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.NEW_SELECT_PTS));
+  }
+  void majPtsChoisis(ArrayList<Integer> nos) {
+    for (Integer no : nos) {
+      if (nosPtsChoisis.contains(no)) {
+        nosPtsChoisis.remove(no);
+      } else {
+        nosPtsChoisis.add(no);
+      }
+    }
+    fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.NEW_SELECT_PTS));
+  }
+  void supPtsChoisis() {
+    ArrayList<Element> EltsSelects = new ArrayList<Element>(
+            Arrays.asList(elementsRetenus));
+    for (Integer no : nosPtsChoisis) {
+      EltsSelects.remove(elementsRetenus[no]);
+    }
+    elementsRetenus = EltsSelects.toArray(new Element[0]);
+    if (calculerCoord()) {
+      nosPtsChoisis = new ArrayList<Integer>();
+      fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.MODIF_DONNEES));
+    } else {
+      Pts = null;
+      fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.CLEAR_DONNEES));
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/ModeleStatsGeometrie.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/VisuStatsFrequences.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/VisuStatsFrequences.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/VisuStatsFrequences.java	(revision 3653)
@@ -0,0 +1,278 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.statistiques;
+
+import visuAnalec.texte.PanneauOccurrences;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import visuAnalec.*;
+import visuAnalec.Message.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.elements.*;
+import visuAnalec.fichiers.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.vue.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class VisuStatsFrequences extends JFrame
+        implements VueListener, ActionListener, ListSelectionListener {
+  private Vue vue;
+  private ModeleStatsFrequences donneesFrequences = new ModeleStatsFrequences();
+  private Class<? extends Element> classe;
+  private String type;
+  private String champEtudie;
+  private String champFiltre;
+  private String[] valeursChampFiltre;
+  private TypeComboBox saisieTypeElements;
+  private JComboBox saisieChampEtudie = new JComboBox();
+  private JComboBox saisieChampFiltre = new JComboBox();
+  private JList saisieValeursChampFiltre = new JList();
+  private JTable tableau;
+  private PanneauOccurrences panneauOccurrences;
+  public VisuStatsFrequences(Container fenetre, Vue vue, PanneauEditeur pEditeur) {
+    super("Fréquences");
+    Point pos = new Point(fenetre.getX()+20, fenetre.getY()+50);
+    Dimension dim = new Dimension(fenetre.getWidth(), fenetre.getHeight()-30);
+    setLocation(pos);
+    setSize(dim);
+    this.vue = vue;
+    vue.addEventListener(this);
+
+    // Panneau des commandes
+    Box panneauCommandes = Box.createVerticalBox();
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieType = new JPanel(new FlowLayout());
+    pSaisieType.setBorder(new TitledBorder("Eléments"));
+    saisieTypeElements = new TypeComboBox(Element.class);
+    saisieTypeElements.setModele(vue.getTypesUnitesAVoir(), vue.getTypesRelationsAVoir(),
+            vue.getTypesSchemasAVoir());
+    saisieTypeElements.setEditable(false);
+    saisieTypeElements.setMaximumRowCount(saisieTypeElements.getModel().getSize());
+    saisieTypeElements.addActionListener(this);
+    pSaisieType.add(saisieTypeElements, CENTER_ALIGNMENT);
+    panneauCommandes.add(pSaisieType);
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieChamp = new JPanel(new FlowLayout());
+    pSaisieChamp.setBorder(new TitledBorder("Champ à analyser"));
+    saisieChampEtudie.setEditable(false);
+    saisieChampEtudie.addActionListener(this);
+    pSaisieChamp.add(saisieChampEtudie, CENTER_ALIGNMENT);
+    panneauCommandes.add(pSaisieChamp);
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieFiltre = new JPanel(new BorderLayout());
+    pSaisieFiltre.setBorder(new TitledBorder("Filtre"));
+    saisieChampFiltre.setEditable(false);
+    saisieChampFiltre.addActionListener(this);
+    pSaisieFiltre.add(saisieChampFiltre, BorderLayout.NORTH);
+    saisieValeursChampFiltre.addListSelectionListener(this);
+    pSaisieFiltre.add(new JScrollPane(saisieValeursChampFiltre), BorderLayout.CENTER);
+    panneauCommandes.add(pSaisieFiltre);
+    panneauCommandes.add(Box.createVerticalGlue());
+    // Panneau du tableau de résultats
+    JPanel panneauAfficheTableau = new JPanel(new BorderLayout());
+    panneauAfficheTableau.setBorder(new TitledBorder("Résultats"));
+    tableau = new JTable(donneesFrequences);
+    tableau.getSelectionModel().addListSelectionListener(this);
+    JScrollPane scrollTableau = new JScrollPane(tableau);
+    panneauAfficheTableau.add(scrollTableau, BorderLayout.CENTER);
+    JPanel pExporterFrequences = new JPanel(new FlowLayout());
+    JButton exporterFrequences = new JButton(new GAction("Exporter le tableau") {
+      public void executer() {
+        FichiersTableur.exporterTable(donneesFrequences);
+      }
+    });
+    pExporterFrequences.add(exporterFrequences, CENTER_ALIGNMENT);
+    panneauAfficheTableau.add(pExporterFrequences, BorderLayout.SOUTH);
+//    panneauAfficheTableau.setPreferredSize(new Dimension(
+//            Math.round((dim.width - panneauCommandes.getPreferredSize().width) / 2),
+//            panneauCommandes.getPreferredSize().height));
+    // Panneau de l'affichage graphique
+    GBarres panneauAfficheBarres = new GBarres(donneesFrequences);
+    JScrollPane scrollPanneauBarres = new JScrollPane(panneauAfficheBarres);
+    scrollPanneauBarres.setBorder(new TitledBorder("Graphique"));
+    scrollPanneauBarres.setPreferredSize(scrollTableau.getPreferredSize());
+    donneesFrequences.addTableModelListener(panneauAfficheBarres);
+    // Panneau de visualisation des occurrences
+    panneauOccurrences = new PanneauOccurrences(vue, pEditeur);
+    JScrollPane scrollPanneauOccurrences = new JScrollPane(panneauOccurrences);
+    scrollPanneauOccurrences.setBorder(
+            new TitledBorder("Visualisation des occurrences"));
+    JButton exporterConcordances = new JButton(
+            new GAction("Exporter les concordances") {
+              public void executer() {
+                FichiersTableur.exporterTable(panneauOccurrences.getModeleTableur());
+              }
+            });
+    JPanel pExporterConcordances = new JPanel(new FlowLayout());
+    pExporterConcordances.add(exporterConcordances, CENTER_ALIGNMENT);
+    // cadre global de la fenêtre
+    JPanel haut = new JPanel(new BorderLayout());
+    haut.add(panneauCommandes, BorderLayout.WEST);
+    haut.add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, panneauAfficheTableau, panneauAfficheBarres),
+            BorderLayout.CENTER);
+    JPanel bas = new JPanel(new BorderLayout());
+    bas.add(scrollPanneauOccurrences, BorderLayout.CENTER);
+    bas.add(pExporterConcordances, BorderLayout.SOUTH);
+    JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, haut, bas);
+    setContentPane(split);
+    setVisible(true);
+    split.setDividerLocation(2./3);
+    // Fermeture de la fenêtre
+    setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+    addWindowListener(new WindowAdapter() {
+      @Override
+      public void windowClosing(WindowEvent evt) {
+        fermerFenetre();
+      }
+    });
+    // Initialisation
+    saisieTypeElements.effSelection();
+    afficherOccurrences();
+  }
+  private void fermerFenetre() {
+    vue.removeEventListener(this);
+    dispose();
+  }
+  private void initSaisieChampEtudie() {
+    saisieChampEtudie.removeActionListener(this);
+    saisieChampEtudie.removeAllItems();
+    if (classe!=null) for (String ch : vue.getNomsChamps(classe, type))
+        saisieChampEtudie.addItem(ch);
+    saisieChampEtudie.setSelectedIndex(-1);
+    champEtudie = null;
+    saisieChampEtudie.addActionListener(this);
+  }
+  private void initSaisieChampFiltre() {
+    saisieChampFiltre.removeActionListener(this);
+    saisieChampFiltre.removeAllItems();
+    saisieChampFiltre.addItem("<pas de filtre>");
+    if (classe!=null) for (String ch : vue.getNomsChamps(classe, type))
+        saisieChampFiltre.addItem(ch);
+    saisieChampFiltre.setSelectedIndex(0);
+    champFiltre = null;
+    saisieChampFiltre.addActionListener(this);
+  }
+  private void initSaisieValeursChampFiltre() {
+    saisieValeursChampFiltre.removeListSelectionListener(this);
+    if (champFiltre==null) {
+      saisieValeursChampFiltre.setListData(new String[0]);
+    } else {
+      saisieValeursChampFiltre.setListData(vue.getValeursChamp(classe, type, champFiltre));
+    }
+    saisieValeursChampFiltre.setSelectedIndex(-1);
+    saisieValeursChampFiltre.addListSelectionListener(this);
+  }
+  void afficherOccurrences() {
+    panneauOccurrences.init(classe, type, donneesFrequences.getListeElementsRowsSelected(tableau.getSelectedRows(), vue, classe,
+            type, champEtudie, champFiltre, valeursChampFiltre));
+  }
+  void changerDonnees() {
+    Object[] vals = saisieValeursChampFiltre.getSelectedValues();
+    valeursChampFiltre = new String[vals.length];
+    for (int i = 0; i<vals.length; i++) {
+      valeursChampFiltre[i] = (String) vals[i];
+    }
+    donneesFrequences.setModele(vue, classe, type, champEtudie, champFiltre, valeursChampFiltre);
+  }
+  public void traiterEvent(Message evt) {
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        fermerFenetre();
+        return;
+      case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+        throw new UnsupportedOperationException("Fenêtre stat présente lors d'un message NEW_CORPUS ???");
+      case MODIF_TEXTE:
+        afficherOccurrences();
+        return;
+      case MODIF_VUE:
+        fermerFenetre();
+        return;
+      case MODIF_STRUCTURE:
+        switch (((StructureEvent) evt).getModif()) {
+          case AJOUT_VALEUR:
+          case RENOM_VALEUR:
+          case FUSION_VALEUR:
+          case SUPPR_VALEUR:
+          case VALEUR_PAR_DEFAUT:
+          case AJOUT_FORME_UNITE:
+            changerDonnees();
+            return;
+          case AJOUT_TYPE:  // à affiner : trop brutal
+          case AJOUT_TYPE_ET_ELEMENTS:
+          case RENOM_TYPE:
+          case FUSION_TYPE:
+          case SUPPR_TYPE:
+          case AJOUT_PROP:
+          case RENOM_PROP:
+          case FUSION_PROP:
+          case SUPPR_PROP:
+            fermerFenetre();
+            return;
+          default:
+            throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+        }
+      case MODIF_ELEMENT:
+        ElementEvent evtE = (ElementEvent) evt;
+        if (evtE.getModif()!=TypeModifElement.BORNES_UNITE) changerDonnees();
+        else afficherOccurrences();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+  }
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource().equals(saisieTypeElements)) {
+        classe = saisieTypeElements.getClasseSelection();
+        type = saisieTypeElements.getTypeSelection();
+        initSaisieChampEtudie();
+        initSaisieChampFiltre();
+        changerDonnees();
+        return;
+      }
+      if (evt.getSource().equals(saisieChampEtudie)) {
+        champEtudie = (String) saisieChampEtudie.getSelectedItem();
+        changerDonnees();
+        return;
+      }
+      if (evt.getSource().equals(saisieChampFiltre)) {
+        int ind = saisieChampFiltre.getSelectedIndex();
+        if (ind==0) champFiltre = null;
+        else champFiltre = (String) saisieChampFiltre.getSelectedItem();
+        initSaisieValeursChampFiltre();
+        changerDonnees();
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  public void valueChanged(ListSelectionEvent evt) {
+    try {
+      if (evt.getValueIsAdjusting()) return;
+      if (evt.getSource().equals(saisieValeursChampFiltre)) {
+        changerDonnees();
+        return;
+      }
+      if (evt.getSource().equals(tableau.getSelectionModel())) {
+        afficherOccurrences();
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.toString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/VisuStatsFrequences.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/VisuStatsGeometrie.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/VisuStatsGeometrie.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/VisuStatsGeometrie.java	(revision 3653)
@@ -0,0 +1,364 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.statistiques;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.table.*;
+import visuAnalec.*;
+import visuAnalec.Message.*;
+import visuAnalec.elements.*;
+import visuAnalec.fichiers.*;
+import visuAnalec.statistiques.ModeleStatsGeometrie.*;
+import visuAnalec.texte.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.vue.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class VisuStatsGeometrie extends JFrame implements VueListener, ActionListener, DonneesGrapheListener {
+  private Vue vue;
+  private ModeleStatsGeometrie donneesGraphe = new ModeleStatsGeometrie();
+  private GPlanAFC panneauAfficheGraphe;
+  private Class<? extends Element> classe;
+  private String type;
+  private String[] listeChampsSelectionnes;
+  private String champAffiche;
+  private TypeComboBox saisieTypeElements;
+  private JList saisieChampsSelectionnes = new JList();
+  private JComboBox saisieChampAffiche = new JComboBox();
+  private JList legendeChampAffiche = new JList();
+  private PanneauOccurrences panneauOccurrences;
+  public VisuStatsGeometrie(Container fenetre, Vue vue, PanneauEditeur pEditeur) {
+    super("Représentations géométriques");
+    Point pos = new Point(fenetre.getX()+20, fenetre.getY()+20);
+    Dimension dim = new Dimension(fenetre.getWidth(), fenetre.getHeight());
+    setLocation(pos);
+    setSize(dim);
+    this.vue = vue;
+    vue.addEventListener(this);
+
+    // Panneau des commandes
+    Box panneauCommandes = Box.createVerticalBox();
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieType = new JPanel(new FlowLayout());
+    pSaisieType.setBorder(new TitledBorder("Eléments"));
+    saisieTypeElements = new TypeComboBox(Element.class);
+    saisieTypeElements.setModele(vue.getTypesUnitesAVoir(), vue.getTypesRelationsAVoir(),
+            vue.getTypesSchemasAVoir());
+    saisieTypeElements.setEditable(false);
+    saisieTypeElements.addActionListener(this);
+    pSaisieType.add(saisieTypeElements, CENTER_ALIGNMENT);
+    panneauCommandes.add(pSaisieType);
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieSelection = new JPanel(new FlowLayout());
+    pSaisieSelection.setBorder(new TitledBorder("Champs pertinents"));
+    pSaisieSelection.add(saisieChampsSelectionnes, CENTER_ALIGNMENT);
+    panneauCommandes.add(pSaisieSelection);
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pAfficherGraphe = new JPanel(new FlowLayout());
+    JButton afficherGraphe = new JButton(new GAction("Mettre à jour le graphe") {
+      public void executer() {
+        Object[] valSelect = saisieChampsSelectionnes.getSelectedValues();
+        String[] chs = new String[valSelect.length];
+        for (int i = 0; i<valSelect.length; i++) {
+          chs[i] = (String) valSelect[i];
+        }
+        donneesGraphe.majChampsSelect(chs);
+      }
+    });
+    pAfficherGraphe.add(afficherGraphe, CENTER_ALIGNMENT);
+    panneauCommandes.add(pAfficherGraphe);
+    panneauCommandes.add(Box.createVerticalGlue());
+
+    // Panneau du graphe
+    JPanel panneauAfficheGraphique = new JPanel(new BorderLayout());
+    panneauAfficheGraphique.setBorder(new TitledBorder("Graphique"));
+    panneauAfficheGraphique.setPreferredSize(new Dimension(
+            Math.round((getWidth()-panneauCommandes.getPreferredSize().width)/2),
+            panneauCommandes.getPreferredSize().height));
+    panneauAfficheGraphe = new GPlanAFC(donneesGraphe);
+    JScrollPane scroll1 = new JScrollPane(panneauAfficheGraphe);
+    panneauAfficheGraphique.add(scroll1, BorderLayout.CENTER);
+    JPanel pExporterGraphique = new JPanel(new FlowLayout());
+    JButton exporterGraphiqueSVG = new JButton(
+            new GAction("<html> Exporter le graphique<br>en format xml (.svg)") {
+              public void executer() {
+                FichiersGraphique.exporterGraphiqueSVG(panneauAfficheGraphe);
+              }
+            });
+    JButton exporterGraphiqueEMF = new JButton(
+            new GAction("<html> Exporter le graphique<br>vers MS-Office (.emf)") {
+              public void executer() {
+                FichiersGraphique.exporterGraphiqueEMF(panneauAfficheGraphe);
+              }
+            });
+    //  exporterGraphiqueEMF.setText("<htlm> Exporter le graphique<br>vers MS-Office (.emf)");
+    pExporterGraphique.add(exporterGraphiqueSVG, CENTER_ALIGNMENT);
+    pExporterGraphique.add(exporterGraphiqueEMF, CENTER_ALIGNMENT);
+    panneauAfficheGraphique.add(pExporterGraphique, BorderLayout.SOUTH);
+
+    // Panneau champ affiché 
+    Box panneauChampAffiche = Box.createVerticalBox();
+    panneauChampAffiche.add(Box.createVerticalGlue());
+    JPanel pChampAffiche = new JPanel(new BorderLayout());
+    pChampAffiche.setBorder(new TitledBorder("Champ à afficher"));
+    saisieChampAffiche.setEditable(false);
+    saisieChampAffiche.addActionListener(this);
+    pChampAffiche.add(saisieChampAffiche, BorderLayout.NORTH);
+    legendeChampAffiche.setCellRenderer(new LegendeCellRenderer());
+    pChampAffiche.add(legendeChampAffiche, BorderLayout.CENTER);
+    panneauChampAffiche.add(pChampAffiche);
+
+    // Panneau valeurs typiques 
+    JPanel panneauValTypiques = new JPanel(new BorderLayout());
+    panneauValTypiques.setBorder(new TitledBorder("Valeurs typiques"));
+    JLabel affNbElements = new JLabel("", JLabel.CENTER);
+    panneauValTypiques.add(affNbElements, BorderLayout.NORTH);
+    ModeleValTypiques donneesValTypiques =
+            new ModeleValTypiques(vue, donneesGraphe, affNbElements);
+    donneesGraphe.addEventListener(donneesValTypiques);
+    JTable tableauValTypiques = new JTable(donneesValTypiques);
+    JScrollPane scrollChampAffiche = new JScrollPane(tableauValTypiques);
+    panneauValTypiques.add(scrollChampAffiche, BorderLayout.CENTER);
+
+    // Panneau de visualisation des occurrences
+    panneauOccurrences = new PanneauOccurrences(vue, pEditeur);
+    JScrollPane scrollPanneauOccurrences = new JScrollPane(panneauOccurrences);
+    scrollPanneauOccurrences.setBorder(new TitledBorder("Visualisation des occurrences"));
+      JButton exporterConcordances = new JButton(
+            new GAction("Exporter les concordances") {
+      public void executer() {
+       FichiersTableur.exporterTable(panneauOccurrences.getModeleTableur());
+      }
+    });
+    JPanel pExporterConcordances = new JPanel(new FlowLayout());
+    pExporterConcordances.add(exporterConcordances, CENTER_ALIGNMENT); 
+
+    donneesGraphe.addEventListener(this);  // pour lancer afficheOccurrences
+
+    // cadre global de la fenêtre
+    JSplitPane split1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+            panneauChampAffiche, panneauValTypiques);
+    JSplitPane split2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+            panneauAfficheGraphique, split1);
+    JSplitPane split3 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+            panneauCommandes, split2);
+    JPanel bas = new JPanel(new BorderLayout());
+    bas.add(scrollPanneauOccurrences, BorderLayout.CENTER);
+    bas.add(pExporterConcordances, BorderLayout.SOUTH);
+    JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
+            split3, bas);
+    getContentPane().add(split);
+    setVisible(true);
+    split3.setDividerLocation(0.15);
+    split2.setDividerLocation(0.4);
+    split1.setDividerLocation(0.3);
+    split.setDividerLocation(2./3);
+
+    // Fermeture de la fenêtre
+    setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+    addWindowListener(new WindowAdapter() {
+      @Override
+      public void windowClosing(WindowEvent evt) {
+        fermerFenetre();
+      }
+    });
+
+    // Initialisation
+    saisieTypeElements.effSelection();
+  }
+  private void fermerFenetre() {
+    vue.removeEventListener(this);
+    dispose();
+  }
+  void initSaisieChampsSelectionnes() {
+    if (classe==null) {
+      listeChampsSelectionnes = new String[0];
+      saisieChampsSelectionnes.setListData(listeChampsSelectionnes);
+    } else {
+      listeChampsSelectionnes = vue.getNomsChamps(classe, type);
+      saisieChampsSelectionnes.setListData(listeChampsSelectionnes);
+      saisieChampsSelectionnes.addSelectionInterval(0, listeChampsSelectionnes.length-1);
+    }
+  }
+  void initSaisieChampAffiche() {
+    saisieChampAffiche.removeAllItems();
+    if (classe!=null) {
+      for (String ch : vue.getNomsChamps(classe, type)) {
+        saisieChampAffiche.addItem(ch);
+      }
+    }
+    saisieChampAffiche.setSelectedIndex(-1);
+    champAffiche = null;
+    initLegendeChampAffiche();
+  }
+  void initLegendeChampAffiche() {
+    legendeChampAffiche.setListData(new LegendeLabel[0]);
+    HashMap<String, Color> couleurValeur = new HashMap<String, Color>();
+    couleurValeur.put("", GVisu.getCouleurSansValeur());
+    donneesGraphe.majChampAffiche(champAffiche, couleurValeur);
+  }
+  void majCouleursChampAffiche() {
+    String[] vals = classe==null ? new String[0] : vue.getValeursChamp(classe, type, champAffiche);
+    HashMap<String, Color> couleurValeur = new HashMap<String, Color>();
+    LegendeLabel[] legende = new LegendeLabel[vals.length+1];
+    for (int i = 0; i<vals.length; i++) {
+      legende[i] = new LegendeLabel(vals[i], GVisu.getCouleur(i));
+      couleurValeur.put(vals[i], GVisu.getCouleur(i));
+    }
+    legende[vals.length] = new LegendeLabel("<aucune valeur>", GVisu.getCouleurSansValeur());
+    couleurValeur.put("", GVisu.getCouleurSansValeur());
+    legendeChampAffiche.setListData(legende);
+    donneesGraphe.majChampAffiche(champAffiche, couleurValeur);
+  }
+  public void traiterEvent(Message evt) {
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        fermerFenetre();
+        return;
+      case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+        throw new UnsupportedOperationException("Fenêtre stat présente lors d'un message NEW_CORPUS ???");
+      case MODIF_TEXTE:
+        return;
+      case MODIF_VUE:
+        fermerFenetre();
+        return;
+      case MODIF_STRUCTURE:
+        fermerFenetre();
+        return;
+      case MODIF_ELEMENT:
+        ElementEvent evtE = (ElementEvent) evt;
+        if (evtE.getModif()!=TypeModifElement.BORNES_UNITE) {
+          fermerFenetre();
+        }
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+  }
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource().equals(saisieTypeElements)) {
+        classe = saisieTypeElements.getClasseSelection();
+        type = saisieTypeElements.getTypeSelection();
+        donneesGraphe.initialise(vue, classe, type);
+        initSaisieChampsSelectionnes();
+        initSaisieChampAffiche();
+        return;
+      }
+      if (evt.getSource().equals(saisieChampAffiche)) {
+        champAffiche = (String) saisieChampAffiche.getSelectedItem();
+        majCouleursChampAffiche();
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "
+              +evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  public void traiterEvent(DonneesGrapheEvent evt) {
+    switch (evt.getType()) {
+      case NEW_DONNEES:
+      case CLEAR_DONNEES:
+        panneauOccurrences.initVide();
+        return;
+      case MODIF_DONNEES:
+        panneauOccurrences.initVide();
+        majCouleursChampAffiche();
+        return;
+      case NEW_SELECT_PTS:
+        panneauOccurrences.init(classe, type,
+                donneesGraphe.getListeElementsChoisis());
+        return;
+      case NEW_COORDS:
+      case NEW_COULEURS:
+        return;
+      default:
+        throw new UnsupportedOperationException("cas "+evt.getType()
+                +" non traité dans un switch");
+    }
+  }
+
+  static class ModeleValTypiques extends AbstractTableModel
+          implements DonneesGrapheListener {
+    String[] nomsColonnes;
+    Vue.TripletValTypique[] triplets;
+    ModeleStatsGeometrie donnees;
+    Vue vue;
+    JLabel affNbElts;
+    public ModeleValTypiques(Vue vue, ModeleStatsGeometrie donnees, JLabel affNbElts) {
+      super();
+      this.donnees = donnees;
+      this.vue = vue;
+      this.affNbElts = affNbElts;
+      initialise();
+    }
+    private void initialise() {
+      nomsColonnes = new String[]{"Champ", "Valeur", "Pourcentage"};
+      setModeleVide();
+    }
+    private void setModeleVide() {
+      triplets = new Vue.TripletValTypique[0];
+      affNbElts.setText("Pas d'élément sélectionné");
+      fireTableDataChanged();
+    }
+    private void setModele(Class<? extends Element> classe, String type, Element[] elts) {
+      triplets = vue.getValTypiques(classe, type, elts);
+      affNbElts.setText(elts.length==1 ? "Un seul élément sélectionné"
+              : elts.length+" éléments sélectionnés");
+      fireTableDataChanged();
+    }
+    public int getRowCount() {
+      return triplets.length;
+    }
+    public int getColumnCount() {
+      return 3;
+    }
+    @Override
+    public String getColumnName(int col) {
+      return nomsColonnes[col];
+    }
+    public Object getValueAt(int row, int col) {
+      switch (col) {
+        case 0:
+          return triplets[row].champ;
+        case 1:
+          return triplets[row].valeur;
+        case 2:
+          return Math.round(triplets[row].pourcentage*10000)/100.0f;
+        default:
+          return null;
+      }
+    }
+    public void traiterEvent(DonneesGrapheEvent evt) {
+      switch (evt.getType()) {
+        case NEW_DONNEES:
+        case CLEAR_DONNEES:
+        case MODIF_DONNEES:
+          setModeleVide();
+          return;
+        case NEW_SELECT_PTS:
+          setModele(donnees.getClasseElements(), donnees.getTypeElements(),
+                  donnees.getListeElementsChoisis());
+          return;
+        case NEW_COORDS:
+        case NEW_COULEURS:
+          return;
+        default:
+          throw new UnsupportedOperationException("cas "+evt.getType()+" non traité dans un switch");
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/VisuStatsGeometrie.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/ModeleStatsCorrelations.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/ModeleStatsCorrelations.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/ModeleStatsCorrelations.java	(revision 3653)
@@ -0,0 +1,146 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.statistiques;
+
+import java.awt.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.table.*;
+import visuAnalec.elements.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class ModeleStatsCorrelations extends AbstractTableModel {
+  private String[] valeursChamp2;
+  private String[] valeursChamp1;
+  private int[][] nbOcc;
+  private int[] totauxChamp1;
+  private int[] totauxChamp2;
+  private int totalTotaux;
+  public ModeleStatsCorrelations() {
+    super();
+    initialise();
+  }
+  private void initialise() {
+    valeursChamp2 = new String[0];
+    valeursChamp1 = new String[0];
+    nbOcc = new int[1][1];
+    totauxChamp1 = new int[1];
+    totauxChamp2 = new int[1];
+    totalTotaux = 0;
+  }
+  public int getRowCount() {
+    return valeursChamp2.length + 2;
+  }
+  public int getColumnCount() {
+    return valeursChamp1.length + 3;
+  }
+  @Override
+  public String getColumnName(int col) {
+    return col == 0 ? "" : col == valeursChamp1.length + 2 ? "TOTAL" : col == valeursChamp1.length + 1 ? "<aucune valeur>" : valeursChamp1[col - 1];
+  }
+  public Object getValueAt(int row, int col) {
+    if (col == 0) {
+      return row == valeursChamp2.length + 1 ? "TOTAL" : row == valeursChamp2.length ? "<aucune valeur>" : valeursChamp2[row];
+    } else if (col == valeursChamp1.length + 2) {
+      return row == valeursChamp2.length + 1 ? totalTotaux : totauxChamp1[row];
+    } else {
+      return row == valeursChamp2.length + 1 ? totauxChamp2[col - 1] : nbOcc[row][col - 1];
+    }
+  }
+  Element[] getListeElementsSelected(Integer[] rows, Integer[] cols, Vue vue, Class<? extends Element> classe, 
+          String type, String champ1, String champ2) {
+    HashSet<Element> liste = new HashSet<Element>();
+    for (int i = 0; i < rows.length; i++) {
+      if(cols[i]==0) continue;
+      if (rows[i] == valeursChamp2.length + 1) {
+        if (cols[i] == valeursChamp1.length + 2) {
+          return vue.getElementsAVoir(classe, type);
+        } else {
+          String[] val1 = cols[i] == valeursChamp1.length + 1 ? new String[]{""} : new String[]{valeursChamp1[cols[i] - 1]};
+          liste.addAll(Arrays.asList(vue.getDoubleSelectionOccurrences(classe, type,champ1, val1, null, null)));
+        }
+      } else {
+        String[] val2 = rows[i] == valeursChamp2.length ? new String[]{""} : new String[]{valeursChamp2[rows[i]]};
+        if (cols[i] == valeursChamp1.length + 2) {
+          liste.addAll(Arrays.asList(vue.getDoubleSelectionOccurrences(classe, type, champ2, val2, null, null)));
+        } else {
+          String[] val1 = cols[i] == valeursChamp1.length + 1 ? new String[]{""} : new String[]{valeursChamp1[cols[i] - 1]};
+          liste.addAll(Arrays.asList(vue.getDoubleSelectionOccurrences(classe, type, champ2, val2, champ1, val1)));
+
+        }
+      }
+    }
+    Element[] tab = liste.toArray(new Element[0]);
+    Arrays.sort(tab);
+    return tab;
+  }
+  void setModele(Vue vue, Class<? extends Element> classe, String type, String champ1, String champ2) {
+    if (classe == null) {
+      setModeleVide();
+      return;
+    }
+    valeursChamp1 = champ1 == null ? new String[0] : vue.getValeursChamp(classe, type, champ1);
+    valeursChamp2 = champ2 == null ? new String[0] : vue.getValeursChamp(classe, type, champ2);
+    nbOcc = new int[valeursChamp2.length + 1][valeursChamp1.length + 1];
+    totauxChamp1 = new int[valeursChamp2.length + 1];
+    totauxChamp2 = new int[valeursChamp1.length + 1];
+    HashMap<String, HashMap<String, Integer>> compte =
+            vue.compterOccurrencesCorrelees(classe, type, champ1, champ2);
+    totalTotaux = 0;
+    for (int col = 0; col < valeursChamp1.length + 1; col++) {
+      HashMap<String, Integer> hm = compte.get(col == valeursChamp1.length ? "" : valeursChamp1[col]);
+      for (int row = 0; row < valeursChamp2.length + 1; row++) {
+        nbOcc[row][col] = hm.get(row == valeursChamp2.length ? "" : valeursChamp2[row]);
+        totauxChamp2[col] += nbOcc[row][col];
+        totauxChamp1[row] += nbOcc[row][col];
+        totalTotaux += nbOcc[row][col];
+      }
+    }
+    fireTableStructureChanged();
+  }
+  private void setModeleVide() {
+    initialise();
+    fireTableDataChanged();
+  }
+}
+
+class CorrelationsRenderer extends DefaultTableCellRenderer {
+  ModeleStatsCorrelations donnees;
+  static Color GRIS_CLAIR = new Color(0.95f, 0.95f, 0.95f);
+  static Color BLEU_CLAIR = new Color(0.9f, 0.9f, 1.0f);
+  public CorrelationsRenderer(ModeleStatsCorrelations donnees) {
+    this.donnees = donnees;
+  }
+  @Override
+  public Component getTableCellRendererComponent(JTable table, Object value,
+          boolean isSelected, boolean hasFocus, int row, int col) {
+    int colTotal = donnees.getColumnCount() - 1;
+    int rowTotal = donnees.getRowCount() - 1;
+    int totalTotaux = (Integer) donnees.getValueAt(rowTotal, colTotal);
+    setBackground(Color.WHITE);
+    setHorizontalTextPosition(JLabel.CENTER);
+    if (col == colTotal || row == rowTotal) {
+      setBackground(BLEU_CLAIR);
+    } else if (col == 0) {
+      setBackground(GRIS_CLAIR);
+      setHorizontalTextPosition(JLabel.LEFT);
+    } else if (totalTotaux > 0) {
+      int c = (Integer) donnees.getValueAt(row, col);
+      float m = ((Integer) donnees.getValueAt(row, colTotal)) * ((Integer) donnees.getValueAt(rowTotal, col)) /
+              totalTotaux * 1.0f;
+      if (c / m > 1.0f) {
+        float corr = Math.min(c / m - 1.0f, 2.0f) * 0.4f;
+        setBackground(new Color(1.0f, 1.0f - corr, 1.0f - corr));
+      }
+    }
+    return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
+  }
+}
+
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/statistiques/ModeleStatsCorrelations.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauChamps.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauChamps.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauChamps.java	(revision 3653)
@@ -0,0 +1,138 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec;
+
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class PanneauChamps extends JPanel {
+  ArrayList<GChamp> champs = new ArrayList<GChamp>();
+  private Vue vue;
+  private Element element = null;
+  private Class<? extends Element> classe = null;
+  private String type = null;
+  private JPanel cadre;
+  public PanneauChamps(PanneauEditeur pEdit, Vue vue) {
+    super(new BorderLayout());
+    setBorder(new TitledBorder("Champs"));
+    cadre = new JPanel(new GridLayout(0, 1));
+    JScrollPane scroll = new JScrollPane(cadre);
+    add(scroll, BorderLayout.CENTER);
+    this.vue = vue;
+  }
+  void reafficher() {
+    if (element == null) return;
+    type = null;
+    afficher(element);
+  }
+  void afficher(Element elt) {
+    this.element = elt;
+    if (elt.getClass() != classe || !elt.getType().equals(type)) {
+      type = elt.getType();
+      classe = elt.getClass();
+      afficherTouslesChamps();
+    }
+    ((TitledBorder) getBorder()).setTitle("Champs " + GVisu.getNomDeLaClasse(elt) + " :  \"" +
+            vue.getIdElement(elt) + "\"");
+    for (GChamp gc : champs) {
+      gc.afficher(elt);
+    }
+    revalidate();
+    repaint();
+  }
+  void effacer() {
+    cadre.removeAll();
+    type = null;
+    element = null;
+    ((TitledBorder) getBorder()).setTitle("Champs");
+    revalidate();
+    repaint();
+  }
+  private void afficherTouslesChamps() {
+    cadre.removeAll();
+    champs.clear();
+
+    int niveau = 0;
+    for (String[] champsniveau : vue.getChamps(classe, type)) {
+      JPanel panneauniveau = new JPanel();
+ //     panneauniveau.setBorder(new TitledBorder("Niveau " + ++niveau));
+      for (String champ : champsniveau) {
+        GChamp gc = new GChamp(vue, classe, type, champ);
+        champs.add(gc);
+        panneauniveau.add(gc);
+      }
+      cadre.add(panneauniveau);
+    }
+  }
+
+  private static class GChamp extends JPanel implements ActionListener {
+    JComboBox afficheValeurChamp;
+    Vue vue;
+    Class<? extends Element> classe;
+    String type;
+    String champ;
+    Element element = null;
+    GChamp(Vue vue, Class<? extends Element> classe, String type, String champ) {
+      super();
+      this.vue = vue;
+      this.classe = classe;
+      this.type = type;
+      this.champ = champ;
+      Box groupe = Box.createVerticalBox();
+      Box titre = Box.createHorizontalBox();
+      titre.add(Box.createHorizontalGlue());
+      JLabel label = new JLabel(champ, JLabel.CENTER);
+ //     label.setPreferredSize(new Dimension(50, 10));
+      titre.add(label);
+      titre.add(Box.createHorizontalGlue());
+      groupe.add(titre);
+      groupe.add(Box.createVerticalStrut(2));
+      afficheValeurChamp = new JComboBox(vue.getValeursChamp(classe, type, champ));
+      afficheValeurChamp.setEditable(vue.isChampModifiable(classe, type, champ));
+      afficheValeurChamp.addActionListener(this);
+      groupe.add(afficheValeurChamp);
+      add(groupe);
+    }
+    void afficher(Element elt) {
+      this.element = elt;
+      afficheValeurChamp.removeActionListener(this);
+      String val = vue.getValeurChamp(elt, champ);
+      if (val.isEmpty()) afficheValeurChamp.setSelectedIndex(-1);
+      else afficheValeurChamp.setSelectedItem(val);
+      afficheValeurChamp.addActionListener(this);
+    }
+    public void actionPerformed(ActionEvent evt) {
+      try {
+        if (!afficheValeurChamp.isEditable()) {
+          JOptionPane.showMessageDialog(getTopLevelAncestor(), "Champ non modifiable pour ce type d'éléments",
+                  "Modification impossible", JOptionPane.ERROR_MESSAGE);
+          afficher(element);
+          return;
+        }
+        String newval = ((String) afficheValeurChamp.getSelectedItem());
+        if (newval == null) newval = "";
+        else newval = newval.trim();
+        if (!vue.setValeurChamp(element, champ, newval)) {
+          JOptionPane.showMessageDialog(getTopLevelAncestor(), "Champ non défini pour cet élément",
+                  "Saisie de valeur de champ impossible", JOptionPane.ERROR_MESSAGE);
+          afficher(element);
+        }
+      } catch (Throwable ex) {
+        GMessages.erreurFatale(ex);
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/PanneauChamps.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/Message.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/Message.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/Message.java	(revision 3653)
@@ -0,0 +1,148 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec;
+
+import java.util.*;
+import visuAnalec.elements.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class Message extends EventObject {
+  public enum TypeMessage {
+    CLEAR_CORPUS,
+    NEW_CORPUS,
+    MODIF_TEXTE,
+    MODIF_ELEMENT,
+    MODIF_STRUCTURE,
+    MODIF_VUE
+  }
+
+  public enum TypeModifElement {
+    AJOUT_UNITE,
+    SUP_UNITE,
+    BORNES_UNITE,
+    AJOUT_RELATION,
+    SUP_RELATION,
+    AJOUT_SCHEMA,
+    MODIF_SCHEMA,
+    SUP_SCHEMA,
+    MODIF_VALEUR,
+  }
+
+  public enum TypeModifStructure {
+    AJOUT_TYPE_ET_ELEMENTS,
+    AJOUT_TYPE,
+    AJOUT_PROP,
+    AJOUT_FORME_UNITE,
+    AJOUT_VALEUR,
+    RENOM_TYPE,
+    RENOM_PROP,
+    RENOM_VALEUR,
+    FUSION_TYPE,
+    FUSION_PROP,
+    FUSION_VALEUR,
+    SUPPR_TYPE,
+    SUPPR_PROP,
+    SUPPR_VALEUR,
+    VALEUR_PAR_DEFAUT,
+  }
+
+  public enum TypeModifVue {
+    EXTRACTION,
+    NEW_VUE,
+    VUE_DEFAUT,
+  }
+  TypeMessage type;
+  public Message(Object source, TypeMessage type) {
+    super(source);
+    this.type = type;
+  }
+  public TypeMessage getType() {
+    return type;
+  }
+
+  public static class VueEvent extends Message {
+    private TypeModifVue modif;
+    private Unite unite;
+    private String[] args;
+    public VueEvent(Object source, TypeModifVue modif, String... args) {
+      super(source, TypeMessage.MODIF_VUE);
+      this.modif = modif;
+      this.args = args;
+    }
+    public VueEvent(Object source, TypeModifVue modif, Unite unite, String... args) {
+      super(source, TypeMessage.MODIF_VUE);
+      this.unite = unite;
+      this.modif = modif;
+      this.args = args;
+    }
+    public TypeModifVue getModif() {
+      return modif;
+    }
+    public Unite getUnite() {
+      return unite;
+    }
+    public String getArg() {
+      return args[0];
+    }
+    public String getArg(int i) {
+      return args[i];
+    }
+  }
+
+  public static class ElementEvent extends Message {
+    private TypeModifElement modif;
+    private Element element;
+    private String[] args;
+    public ElementEvent(Object source, TypeModifElement modif, Element element, String... args) {
+      super(source, TypeMessage.MODIF_ELEMENT);
+      this.modif = modif;
+      this.element = element;
+      this.args = args;
+    }
+    public TypeModifElement getModif() {
+      return modif;
+    }
+    public Element getElement() {
+      return element;
+    }
+    public String getArg() {
+      return args[0];
+    }
+    public String getArg(int i) {
+      return args[i];
+    }
+  }
+
+  public static class StructureEvent extends Message {
+    private TypeModifStructure modif;
+    private Class<? extends Element> classe;
+    private String[] args;
+    public StructureEvent(Object source, TypeModifStructure modif, Class<? extends Element> classe, String... args) {
+      super(source, TypeMessage.MODIF_STRUCTURE);
+      this.modif = modif;
+      this.classe = classe;
+      this.args = args;
+    }
+    public TypeModifStructure getModif() {
+      return modif;
+    }
+    public Class<? extends Element> getClasse() {
+      return classe;
+    }
+    public String getArg() {
+      return args[0];
+    }
+    public String getArg(int i) {
+      return args[i];
+    }
+  }
+}
+
+
+
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/visuAnalec/Message.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/AFC.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/AFC.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/AFC.java	(revision 3653)
@@ -0,0 +1,70 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package JamaPlus;
+
+/**
+ *
+ * AFC analyse factorielle des correspondances (optimisé mémoire)
+ * mat :  matrice binaire (0. ou 1.) profil des lignes (un individu par ligne, un caractère par colonne)
+ * CP: composantes principales,
+ * VP: valeurs d'inertie, 
+ * CG: centres de gravité des CP contenant un même caractère (non calculé dans cette version)
+ * [p,q] = size(mat); p:nb de lignes, q:nb de col
+ * 
+ * @author Bernard Victorri
+ */
+public class AFC {
+
+  private double[][] CP;
+  private double[] VP;
+  private int p, q, n;
+
+  AFC(Matrix Arg) {
+    Matrix mat = Arg.copy();
+    mat = mat.nulColumnSuppression();
+    p = mat.getRowDimension();
+    q = mat.getColumnDimension();
+    n = Math.min(Math.min(p, q), 5); // n : nombre de composantes principales calculées
+    if (n == 0) return;
+    if (n == 1) {
+      CP = new double[p][1];
+      VP = new double[1];
+      return;
+    }
+    double f = mat.elementSum();
+    if (f == 0) return;
+    mat = mat.timesEquals(1 / f);
+    Matrix r = mat.lineSum();
+    Matrix r1 = r.arrayInverse();
+    Matrix r2 = r.arraySqrt();
+    Matrix r3 = r2.arrayInverse();
+    Matrix c = mat.columnSum();
+    Matrix c1 = c.arrayInverse();
+    Matrix c2 = c.arraySqrt();
+    Matrix c3 = c2.arrayInverse();
+    mat = mat.firstColumnTimesEqual(r3);
+    mat = mat.firstLineTimesEqual(c3);
+    SingularValueDecomposition svd = mat.svd();
+    Matrix cp = svd.getU();
+    Matrix vp = new Matrix(svd.getSingularValues(), 1);
+    cp = cp.getMatrix(0, p - 1, 1, n - 1);
+    cp = cp.firstColumnTimesEqual(r2);
+    vp = vp.getMatrix(0, 0, 1, n - 1);
+    cp = cp.firstLineTimesEqual(vp);
+    cp.fixColumnSigns();
+    cp = cp.firstColumnTimesEqual(r1);
+    CP = cp.getArray();
+    VP = vp.getColumnPackedCopy();
+  }
+
+  public Matrix getCP() {
+    if (CP == null) return null;
+    return new Matrix(CP, p, n - 1);
+  }
+
+  public double[] getVP() {
+    return VP;
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/AFC.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SparseSVD.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SparseSVD.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SparseSVD.java	(revision 3653)
@@ -0,0 +1,920 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package JamaPlus;
+
+import JamaPlus.util.*;
+import java.util.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class SparseSVD {  // based on code adapted from SVDLIBC - svdLAS2 (adapted from SVDPACKC)
+  private boolean transpose; // si transposition de la matrice en entrée
+  private int rows, cols, dim; // nb rows, nb cols, nb de val sing. désirées
+  // (après transposition éventuelle)
+  private double[][] Ut; // (d x m) transpose of left singular vectors (rows of Ut)
+  private double[][] Vt; // (d x n) transpose of right singular vectors (rows of Vt)
+  private double[] S; // d singular values
+  /* Constantes */
+  private final static int MAXLL = 2; // ??
+  private final static double[] END = {-1e-30, 1e-30};
+  private final static double EPS = Machine.eps(); // precision de la machine
+  private final static double RAD_EPS = Math.sqrt(EPS);
+  private final static double RAD34_EPS = RAD_EPS*Math.sqrt(RAD_EPS);
+  private final static double KAPPA = Math.max(RAD34_EPS, 1e-6);
+  private double EPS1;  // = precision * sqrt(nbcols)
+  /* Variables de travail : mémoire à libérer en fin de calcul */
+  private double[] alph;  // diagonale de la matrice tridiagonale T
+  private double[] bet; // éléments hors-diagonale de T
+  private double[] ritz; // valeurs propres de la  projection de A'A sur l'espace de Krylov
+  private double[] bnd; // a vérifier : initialisation (127) nécessaire ?? 
+  private double[] rj ;
+  private  double[] qj;
+  private  double[] qj1;
+  private  double[] pj ;
+  private  double[] pj1;
+  private  double[] wk;
+   private   double[] eta; 
+  private  double[] oldeta; 
+
+
+//    private static int irandom = 0;  // deboguage : à supprimer
+
+  private static class Storage {  // store Lanczos vectors q(j) 
+    private double[][] P, Q;  // P supplementary storage for j < MAXLL (j= 0 or 1)
+
+    private Storage(int nb, int maxll) {
+      P = new double[maxll][];
+      Q = new double[nb][];
+    }
+
+    private void storeP(int n, int j, double[] p) {
+      if (P[j]==null) P[j] = new double[n];
+      System.arraycopy(p, 0, P[j], 0, n);
+    }
+
+    private void storeQ(int n, int j, double[] q) {
+      if (Q[j]==null) Q[j] = new double[n];
+      System.arraycopy(q, 0, Q[j], 0, n);
+    }
+
+    private void retrieveP(int n, int j, double[] p) {
+      System.arraycopy(P[j], 0, p, 0, n);
+    }
+
+    private void retrieveQ(int n, int j, double[] q) {
+      System.arraycopy(Q[j], 0, q, 0, n);
+    }
+  }
+  private Storage storage;
+
+ public enum CodeSVDException {
+   DIM_OUT_OF_BOUNDS ("Nombre de valeurs singulières désirées invalide"),
+   FIRST_STEP_FAILURE("Impossible d'initialiser le premier pas de calcul"),
+   CONVERGENCE_FAILURE("Echec de convergence ");
+   String message;
+  CodeSVDException(String message) {
+   this.message = message;
+ }
+ }
+  public static class SparseSVDException extends Exception { // Erreurs
+    private CodeSVDException code;
+    private int k;
+
+    private SparseSVDException(CodeSVDException code, int k) {
+      super();
+      this.code = code;
+      this.k = k;
+    }
+
+    public CodeSVDException getCode() {
+      return code;
+    }
+
+    public int getK() {
+      return k;
+    }
+
+    @Override
+    public String getMessage() {
+      return super.getMessage()+"\ncode = "+getCode().message +", n = "+getK();
+    }
+  }
+
+  public SparseSVD(SparseMatrix spm, int d) throws SparseSVDException {
+    int iter = Math.min(spm.getRowDimension(), spm.getColumnDimension()); // nb d'itérations 
+    if (d<=0 || d>iter)
+      throw new SparseSVDException(CodeSVDException.DIM_OUT_OF_BOUNDS, d);
+    dim = d;
+    transpose = spm.getColumnDimension()>=spm.getRowDimension()*1.2;
+    SparseMatrix A = transpose ? spm.transpose() : spm.copy();
+    rows = A.getRowDimension();
+    cols = A.getColumnDimension();
+    EPS1 = EPS*Math.sqrt(cols);
+    alph = new double[iter];  // diagonale de la matrice tridiagonale T
+    bet = new double[iter+1]; // éléments hors-diagonale de T
+    ritz = new double[iter+1];
+    bnd = new double[iter+1]; // a vérifier : initialisation (127) nécessaire ?? 
+    storage = new Storage(iter, MAXLL);
+    // Calcul de la matrice tridiagonale 
+    int[] steps_neig_ = lanso(A, iter);
+    Ut = new double[dim][rows];
+    Vt = new double[dim][cols];
+    S = new double[dim];
+    // Calcul des  vecteurs propres
+    //  nsig  : nb de val. propres "kappa-acceptables"
+    int nsig = ritvec(A, steps_neig_);
+    if (nsig<dim) dim = nsig;  // moins de valeurs obtenues que demandées
+    // libère la mémoire
+    storage = null;
+    alph =  bet = ritz = bnd = null;
+
+  }
+
+  private int[] lanso(SparseMatrix A, int iter) throws SparseSVDException {
+    // Calcul de la matrice tridiagonale
+    int neig = 0;
+    // espace de travail
+    rj = new double[cols];
+    qj = new double[cols];
+     qj1 = new double[cols];
+     pj = new double[cols];
+     pj1 = new double[cols];
+     wk = new double[cols];
+    // step one 
+    double[] rnm_tol_ = stpone(A, cols); // initialise rmn et tol
+     eta = new double[iter]; // orthogonality estimate of Lanczos vectors
+    oldeta = new double[iter];
+    if (rnm_tol_[0]==0) {
+      ritz[0] = alph[0];
+      storage.storeQ(cols, 0, qj);
+      return new int[]{0, 1}; // steps = 0 et neig = 1
+    }
+    eta[0] = oldeta[0] = EPS1;
+    boolean[] enough_ = {false}; // flag de sortie de boucle
+    int steps = 0; // j = steps
+    int[] ll_ = {0};  // 0, 1 or 2 initial Lanczos vectors in local orthog.
+    int first = 1;
+    int last = Math.min(dim+Math.max(8, dim), iter);  // = iter dans notre version
+    int i, l;
+    int intro = 0;
+    while (!enough_[0]) {
+      steps = lanczos_step(A, first, last, 
+              ll_, enough_, rnm_tol_, cols);
+      steps = enough_[0] ? steps-1 : last-1;
+      first = steps+1;
+      bet[first] = rnm_tol_[0];
+      // analyse T
+      l = 0;
+      for (int id2 = 0; id2<steps; id2++) {
+        if (l>steps) break;
+        for (i = l; i<=steps; i++) if (bet[i+1]==0) break;
+        if (i>steps) i = steps;
+        // now i is at the end of an unreduced submatrix
+        DoubleArraysPlus.copyReverse(i-l+1, alph, l, ritz, l);
+        DoubleArraysPlus.copyReverse(i-l, bet, l+1, wk, l+1);
+        imtqlb(i-l+1, l, ritz, wk, bnd);
+        for (int id3 = l; id3<=i; id3++)
+          bnd[id3] = rnm_tol_[0]*Math.abs(bnd[id3]);
+        l = i+1;
+      }
+      // sort eigenvalues into increasing order
+      DoubleArraysPlus.sort2(ritz, bnd, steps+1, 0);
+      // massage error bounds for very close ritz values 
+      neig = error_bound(enough_, END[0], END[1], steps, rnm_tol_[1]);
+      // should we stop? 
+      if (neig<dim) {
+        if (neig==0) {
+          last = first+9;
+          intro = first;
+        } else {
+          last = first+Math.max(3, 1+((steps-intro)*(dim-neig))/neig);
+        }
+        last = Math.min(last, iter);
+      } else {
+        enough_[0] = true;
+      }
+      enough_[0] = enough_[0]||first>=iter;
+    }
+    storage.storeQ(cols, steps, qj);
+    // libère la mémoire
+     rj = qj =  qj1 = pj =  pj1 =  wk = null;
+     eta = oldeta = null;
+    return new int[]{steps, neig};
+  }
+
+  private double[] stpone(SparseMatrix A,  int n)
+          throws SparseSVDException {
+    /*  stp-one performs the first step of the Lanczos algorithm.  It also
+    does a step of extended local re-orthogonalization.
+    Arguments 
+    (input)
+    n      dimension of the eigenproblem for matrix B
+    (output)
+    wptr   array of pointers that point to work space that contains
+    wptr[0]             r[j]
+    wptr[1]             q[j]
+    wptr[2]             q[j-1]
+    wptr[3]             p
+    wptr[4]             p[j-1]
+    alph             diagonal elements of matrix T 
+    throw a SparseSVDException(-1) if the choice of initial vector (startv) failed
+     */
+    // get initial normalized vector; default is random 
+    startv0(A, n);
+    System.arraycopy(pj, 0, qj, 0, n);
+    // take the first step   
+    A.opb(pj, rj);
+    alph[0] = DoubleArraysPlus.dot(rj, pj);
+    for (int i = 0; i<n; i++) rj[i] -= alph[0]*qj[i];
+    /* extended local reorthogonalization */
+    double t = DoubleArraysPlus.dot(rj, pj);
+    for (int i = 0; i<n; i++) rj[i] -= t*qj[i];
+    alph[0] += t;
+    System.arraycopy(rj, 0, pj1, 0, n);
+    double rnm = Math.sqrt(DoubleArraysPlus.dot(pj1, pj1));
+    double tol = RAD_EPS*(rnm+Math.abs(alph[0]));
+    return new double[]{rnm, tol};
+  }
+
+//  private static double random2() {
+//    double x = 0.11*(++irandom);
+//    return x-Math.floor(x);
+//  }
+//
+private void startv0(SparseMatrix A, int n)
+          throws SparseSVDException {
+    /* startv delivers a starting normalized vector in r, 
+     * and throws a SparseSVDException(-1) if no starting vector can be found.
+    Parameters 
+    (input)
+    n      dimension of the eigenproblem matrix B
+    wptr   array of pointers that point to work space
+    step      starting index for a Lanczos run
+    (output)
+    wptr   array of pointers that point to work space that contains
+    r[j], q[j], q[j-1], p[j], p[j-1]
+     */
+// get initial vector; default is random
+    double rnm2 = 0;
+    Random random = new Random(918273);
+    for (int id = 0; id<3; id++) {
+      for (int i = 0; i<n; i++) wk[i]  = random.nextDouble(); 
+      // apply operator to put r in range (essential if m singular)
+      A.opb(wk, pj);
+      rnm2 = DoubleArraysPlus.dot(pj, pj);
+      if (rnm2>0) break;
+    }
+    // normalize
+    if (rnm2<=0) throw new SparseSVDException(CodeSVDException.FIRST_STEP_FAILURE, 0);
+    rnm2 = 1/Math.sqrt(rnm2);
+    for (int i = 0; i<n; i++) pj[i] *= rnm2;
+  }
+
+  private int lanczos_step(SparseMatrix A, int first, int last,int[] ll_,   
+          boolean[] enough_, double[] rnm_tol_, int n) throws SparseSVDException {
+    /*   embodies a single Lanczos step
+    Arguments 
+    (input)
+    n        dimension of the eigenproblem for matrix B
+    first    start of index through loop				      
+    last     end of index through loop				     
+    wptr	    array of pointers pointing to work space		    
+    alf	    array to hold diagonal of the tridiagonal matrix T
+    eta      orthogonality estimate of Lanczos vectors at step j   
+    oldeta   orthogonality estimate of Lanczos vectors at step j-1
+    bet      array to hold off-diagonal of T                     
+    ll       number of intitial Lanczos vectors in local orthog. 
+    (has value of 0, 1 or 2)			
+    enough   stop flag			
+     */
+    int j;
+    double t;
+    double mid[];
+    for (j = first; j<last; j++) {
+      mid = qj1;
+      qj1 = qj;
+      qj = mid;
+      mid = pj;
+      pj = pj1;
+      pj1 = mid;
+      storage.storeQ(n, j-1, qj1);
+      if (j-1<MAXLL) storage.storeP(n, j-1, pj1);
+      bet[j] = rnm_tol_[0];
+
+      // restart if invariant subspace is found 
+      if (bet[j]==0) {
+        rnm_tol_[0] = startv(A, j, n);
+        if (rnm_tol_[0]==0) enough_[0] = true;
+      }
+      if (enough_[0]) {
+        /* added by Doug... */
+        /* These lines fix a bug that occurs with low-rank matrices */
+        mid = qj1;
+        qj1 = qj;
+        qj = mid;
+        /* ...added by Doug */
+        break;
+      }
+      /* take a lanczos step */
+      t = 1.0/rnm_tol_[0];
+      for (int i = 0; i<n; i++) qj[i] = t*rj[i];
+      for (int i = 0; i<n; i++) pj[i] *= t;
+      A.opb(pj, rj);
+      for (int i = 0; i<n; i++) rj[i] -= rnm_tol_[0]*qj1[i];
+      alph[j] = DoubleArraysPlus.dot(rj, pj);
+      for (int i = 0; i<n; i++) rj[i] -= alph[j]*qj[i];
+      /* orthogonalize against initial lanczos vectors */
+      if (j<=MAXLL&&(Math.abs(alph[j-1])>4.0*Math.abs(alph[j])))
+        ll_[0] = j;
+      for (int i = 0; i<Math.min(ll_[0], j-1); i++) {
+        storage.retrieveP(n, i, wk);
+        t = DoubleArraysPlus.dot(wk, rj);
+        storage.retrieveQ(n, i, wk);
+        for (int ii = 0; ii<n; ii++) rj[ii] -= t*wk[ii];
+        oldeta[i] = eta[i] = EPS1;
+      }
+      /* extended local reorthogonalization */
+      t = DoubleArraysPlus.dot(rj, pj1);
+      for (int i = 0; i<n; i++) rj[i] -= t*qj1[i];
+      if (bet[j]>0) bet[j] += t;
+      t = DoubleArraysPlus.dot(rj, pj);
+      for (int i = 0; i<n; i++) rj[i] -= t*qj[i];
+      alph[j] += t;
+      System.arraycopy(rj, 0, pj1, 0, n);
+      rnm_tol_[0] = Math.sqrt(DoubleArraysPlus.dot(rj, pj1));
+      rnm_tol_[1] = RAD_EPS*(bet[j]+Math.abs(alph[j])+rnm_tol_[0]);
+      /* update the orthogonality bounds */
+      ortbnd(j, rnm_tol_[0]);
+      /* restore the orthogonality state when needed */
+      purge(n, ll_[0], j, rnm_tol_);
+      if (rnm_tol_[0]<=rnm_tol_[1]) rnm_tol_[0] = 0;
+    }
+    return j;
+  }
+
+  private double startv(SparseMatrix A, int step, int n)
+          throws SparseSVDException {
+    /* startv delivers a starting vector in r and returns |r|; it returns 
+    zero if the range is spanned, and throws a SparseSVDException(-1) if no starting 
+    vector within range of operator can be found.
+    Parameters 
+    (input)
+    n      dimension of the eigenproblem matrix B
+    wptr   array of pointers that point to work space
+    step      starting index for a Lanczos run
+    (output)
+    wptr   array of pointers that point to work space that contains
+    r[j], q[j], q[j-1], p[j], p[j-1]
+     */
+// get initial vector; default is random
+    double rnm2 = DoubleArraysPlus.dot(rj, rj);
+    Random random = new Random(918273+step);
+    for (int id = 0; id<3; id++) {
+      for (int i = 0; i<n; i++) rj[i] = random.nextDouble();
+      System.arraycopy(rj, 0, pj, 0, n);
+      // apply operator to put r in range (essential if m singular)
+      A.opb(pj, rj);
+      System.arraycopy(rj, 0, pj, 0, n);
+      rnm2 = DoubleArraysPlus.dot(rj, pj);
+      if (rnm2>0) break;
+    }
+    if (rnm2<=0) throw new SparseSVDException(CodeSVDException.FIRST_STEP_FAILURE, 0);
+    double t;
+    for (int j = 0; j<step; j++) {
+      storage.retrieveQ(n, j, wk);
+      t = -DoubleArraysPlus.dot(pj, wk);
+      for (int i = 0; i<n; i++) rj[i] += t*wk[i];
+    }
+    // make sure q[step] is orthogonal to q[step-1] 
+    t = DoubleArraysPlus.dot(pj1, rj);
+    for (int i = 0; i<n; i++) rj[i] -= t*qj1[i];
+    System.arraycopy(rj, 0, pj, 0, n);
+    t = DoubleArraysPlus.dot(pj, rj);
+    if (t<=EPS*rnm2) rnm2 = 0;
+    else rnm2 = t;
+    return Math.sqrt(rnm2);
+  }
+
+  private void ortbnd(int step, double rnm) {
+    /*  updates the eta recurrence
+    Arguments 
+    (input)
+    alf      array to hold diagonal of the tridiagonal matrix T         
+    eta      orthogonality estimate of Lanczos vectors at step j        
+    oldeta   orthogonality estimate of Lanczos vectors at step j-1     
+    bet      array to hold off-diagonal of T                          
+    n        dimension of the eigenproblem for matrix B		    
+    j        dimension of T					  
+    rnm	    norm of the next residual vector			 
+    eps1	    roundoff estimate for dot product of two unit vectors
+    (output)
+    eta      orthogonality estimate of Lanczos vectors at step j+1     
+    oldeta   orthogonality estimate of Lanczos vectors at step j        
+     */
+    if (step<1) return;
+    if (rnm!=0) {
+      if (step>1)
+        oldeta[0] = (bet[1]*eta[1]+(alph[0]-alph[step])*eta[0]
+                -bet[step]*oldeta[0])/rnm+EPS1;
+      for (int i = 1; i<=step-2; i++)
+        oldeta[i] = (bet[i+1]*eta[i+1]+(alph[i]-alph[step])*eta[i]
+                +bet[i]*eta[i-1]-bet[step]*oldeta[i])/rnm+EPS1;
+    }
+    oldeta[step-1] = EPS1;
+    double t;
+    for (int i = 0; i<step; i++) {
+      t = oldeta[i];
+      oldeta[i] = eta[i];
+      eta[i] = t;
+    }
+    eta[step] = EPS1;
+  }
+
+  private void purge(int n, int ll, int step, double[] rnm_tol_) {
+    /*
+    purge examines the state of orthogonality between the new Lanczos
+    vector and the previous ones to decide whether re-orthogonalization 
+    should be performed
+    Arguments 
+    (input)
+    n        dimension of the eigenproblem for matrix B		       
+    ll       number of intitial Lanczos vectors in local orthog.       
+    r        residual vector to become next Lanczos vector            
+    q        current Lanczos vector			           
+    ra       previous Lanczos vector
+    qa       previous Lanczos vector
+    wrk      temporary vector to hold the previous Lanczos vector
+    eta      state of orthogonality between r and prev. Lanczos vectors 
+    oldeta   state of orthogonality between q and prev. Lanczos vectors
+    j        current Lanczos step				     
+    (output)
+    r	    residual vector orthogonalized against previous Lanczos 
+    vectors
+    q        current Lanczos vector orthogonalized against previous ones    
+     */
+    if (step<ll+2) return;
+    int k = DoubleArraysPlus.indAbsMax(step-(ll+1), eta, ll);
+    if (Math.abs(eta[k])<=RAD_EPS) return;
+    double REPS1 = EPS1/RAD_EPS;
+    double t;
+    for (int iteration = 0; iteration<2; iteration++) {
+      if (rnm_tol_[0]<=rnm_tol_[1]) break;
+      /* bring in a lanczos vector t and orthogonalize both 
+       * r and q against it */
+      double tq = 0;
+      double tr = 0;
+      for (int i = ll; i<step; i++) {
+        storage.retrieveQ(n, i, wk);
+        t = -DoubleArraysPlus.dot(pj, wk);
+        tq += Math.abs(t);
+        for (int ii = 0; ii<n; ii++) qj[ii] += t*wk[ii];
+        t = -DoubleArraysPlus.dot(pj1, wk);
+        tr += Math.abs(t);
+        for (int ii = 0; ii<n; ii++) rj[ii] += t*wk[ii];
+      }
+      System.arraycopy(qj, 0, pj, 0, n);
+      t = -DoubleArraysPlus.dot(rj, pj);
+      tr += Math.abs(t);
+      for (int i = 0; i<n; i++) rj[i] += t*qj[i];
+      System.arraycopy(rj, 0, pj1, 0, n);
+      rnm_tol_[0] = Math.sqrt(DoubleArraysPlus.dot(pj1, rj));
+      if (tq<=REPS1&&tr<=REPS1*rnm_tol_[0]) break;
+    }
+    for (int i = ll; i<=step; i++) {
+      eta[i] = EPS1;
+      oldeta[i] = EPS1;
+    }
+  }
+
+  private static void imtqlb(int n, int i0, double[] d, double[] e, double[] bnd)
+          throws SparseSVDException {
+    /*   imtqlb() finds the eigenvalues of a symmetric tridiagonal
+    matrix by the implicit QL method.
+    Arguments 
+    (input)
+    n      order of the symmetric tridiagonal matrix   
+    d      contains the diagonal elements of the input matrix           
+    e      contains the subdiagonal elements of the input matrix in its
+    last n-1 positions.  e[0] is arbitrary
+    i0   starting index for the 3 vectors
+    (elements with index < i0 or >= i0+n are preserved)
+    (output)
+    d      contains the eigenvalues in ascending order.  if an error
+    exit is made, the eigenvalues are correct and ordered for
+    indices 0,1,...ierr, but may not be the smallest eigenvalues.
+    e      has been destroyed.					    
+    throws a SparseSVDException(j) if the j-th eigenvalue has
+    not been determined after 30 iterations.		    
+     */
+    if (n==1) return;
+    bnd[i0] = 1;
+    for (int i = i0+1; i<i0+n; i++) {
+      bnd[i] = 0;
+      e[i-1] = e[i];
+    }
+    e[i0+n-1] = 0;
+    for (int l = i0; l<i0+n; l++) {
+      for (int iteration = 0; iteration<=30; iteration++) {
+        double p = d[l];
+        double f = bnd[l];
+        int m;
+        for (m = l; m<i0+n-1; m++) { // test de convergence
+          double test = Math.abs(d[m])+Math.abs(d[m+1]);
+          if (test+Math.abs(e[m])==test) break;
+        }
+        if (m==l) {
+          d[l] = p;
+          bnd[l] = f;
+          /* order the eigenvalues */
+          DoubleArraysPlus.sort2(d, bnd, l-i0+1, i0);
+          break;
+        } else {
+          if (iteration==30) throw new SparseSVDException(CodeSVDException.CONVERGENCE_FAILURE, l);
+          /*........ form shift ........*/
+          double g = (d[l+1]-p)/(2.0*e[l]);
+          double r = Math.hypot(g, 1);
+          g = d[m]-p+e[l]/(g+Math.copySign(r, g));
+          double s = 1;
+          double c = 1;
+          p = 0;
+          boolean underflow = false;
+          for (int i = m-1; i>=l; i--) {
+            f = s*e[i];
+            double b = c*e[i];
+            r = Math.hypot(f, g);
+            e[i+1] = r;
+            if (r==0) {
+              /*........ recover from underflow .........*/
+              underflow = true;
+              d[i+1] -= p;
+              e[m] = 0.0;
+              break;
+            }
+            s = f/r;
+            c = g/r;
+            g = d[i+1]-p;
+            r = (d[i]-g)*s+2*c*b;
+            p = s*r;
+            d[i+1] = g+p;
+            g = c*r-b;
+            f = bnd[i+1];
+            bnd[i+1] = s*bnd[i]+c*f;
+            bnd[i] = c*bnd[i]-s*f;
+          }
+
+          if (!underflow) {
+            d[l] -= p;
+            e[l] = g;
+            e[m] = 0.0;
+          }
+        }
+      }
+    }
+  }
+
+  private int error_bound(boolean[] enough_, double endl, double endr,
+          int step, double tol) {
+    /*
+    massages error bounds for very close ritz values by placing 
+    a gap between them.  The error bounds are then refined to reflect this.
+    Arguments 
+    (input)
+    endl     left end of interval containing unwanted eigenvalues
+    endr     right end of interval containing unwanted eigenvalues
+    ritz     array to store the ritz values
+    bnd      array to store the error bounds
+    enough   stop flag
+     */
+    int mid = DoubleArraysPlus.indAbsMax(step+1, bnd, 1);
+
+    for (int i = step; i>mid; i--)
+      if (Math.abs(ritz[i-1]-ritz[i])<RAD34_EPS*Math.abs(ritz[i]))
+        if (bnd[i]>tol&&bnd[i-1]>tol) {
+          bnd[i-1] = Math.hypot(bnd[i], bnd[i-1]);
+          bnd[i] = 0;
+        }
+    for (int i = 1; i<mid; i++)
+      if (Math.abs(ritz[i+1]-ritz[i])<RAD34_EPS*Math.abs(ritz[i]))
+        if (bnd[i]>tol&&bnd[i+1]>tol) {
+          bnd[i+1] = Math.hypot(bnd[i], bnd[i+1]);
+          bnd[i] = 0.0;
+        }
+    /* refine the error bounds */
+    int neig = 0;
+    double gapl = ritz[step]-ritz[0];
+    for (int i = 0; i<=step; i++) {
+      double gap = gapl;
+      if (i<step) gapl = ritz[i+1]-ritz[i];
+      gap = Math.min(gap, gapl);
+      if (gap>bnd[i]) bnd[i] *= (bnd[i]/gap);
+      if (bnd[i]<=16.0*EPS*Math.abs(ritz[i])) {
+        neig++;
+        if (!enough_[0]) enough_[0] = endl<ritz[i]&&ritz[i]<endr;
+      }
+    }
+    return neig;
+  }
+
+  private int ritvec0(SparseMatrix A, int[] steps_neig_) throws SparseSVDException {
+
+    int js, jsq, i, k, /*size,*/ id2, tmp, nsig, x;
+    double[] s, xv2;
+    double tmp0, tmp1, xnorm;
+    double[] w1 = Vt[0];
+    double[] w2 = new double[cols];
+
+    js = steps_neig_[0]+1;
+    jsq = js*js;
+    /*size = sizeof(double) * n;*/
+
+    s = new double[jsq];
+    xv2 = new double[cols];
+
+    /* initialize s to an identity matrix */
+    for (i = 0; i<jsq; i += (js+1)) s[i] = 1.0;
+    DoubleArraysPlus.copyReverse(js, alph, 0, w1, 0);
+    DoubleArraysPlus.copyReverse(steps_neig_[0], bet, 1, w2, 1);
+
+    /* on return from imtql2(), w1 contains eigenvalues in ascending 
+     * order and s contains the corresponding eigenvectors */
+    double[][] z = new double[js][js];
+    for (int r = 0; r<js; r++) for (int c = 0; c<js; c++) z[r][c] = s[r*js+c];
+    imtql2(js, js, w1, w2, z);
+    for (int r = 0; r<js; r++) for (int c = 0; c<js; c++) s[r*js+c] = z[r][c];
+
+
+    /*fwrite((char *)&n, sizeof(n), 1, fp_out2);
+    fwrite((char *)&js, sizeof(js), 1, fp_out2);
+    fwrite((char *)&kappa, sizeof(kappa), 1, fp_out2);*/
+    /*id = 0;*/
+    nsig = 0;
+    x = 0;
+    id2 = jsq-js;
+    for (k = 0; k<js; k++) {
+      tmp = id2;
+      if (bnd[k]<=KAPPA*Math.abs(ritz[k])&&k>js-steps_neig_[1]-1) {
+        if (--x<0) x = dim-1;
+        w1 = Vt[x];
+        for (i = 0; i<cols; i++) w1[i] = 0.0;
+        for (i = 0; i<js; i++) {
+          storage.retrieveQ(cols, i, w2);
+          for (int ii = 0; ii<cols; ii++) w1[ii] += s[tmp]*w2[ii];
+          tmp -= js;
+        }
+        /*fwrite((char *)w1, size, 1, fp_out2);*/
+
+        /* store the w1 vector row-wise in array xv1;   
+         * size of xv1 is (steps+1) * (nrow+ncol) elements 
+         * and each vector, even though only ncol long,
+         * will have (nrow+ncol) elements in xv1.      
+         * It is as if xv1 is a 2-d array (steps+1) by     
+         * (nrow+ncol) and each vector occupies a row  */
+
+        /* j is the index in the R arrays, which are sorted by high to low 
+        singular values. */
+
+        /*for (i = 0; i < n; i++) R->Vt->value[x]xv1[id++] = w1[i];*/
+        /*id += nrow;*/
+        nsig++;
+      }
+      id2++;
+    }
+    s = null;
+
+    /* Rotate the singular vectors and values. */
+    /* x is now the location of the highest singular value. */
+    DoubleArraysPlus.rotateArray(Vt, x);
+    dim = Math.min(dim, nsig);
+    for (x = 0; x<dim; x++) {
+      /* multiply by matrix B first */
+      A.opb(Vt[x], xv2);
+      tmp0 = DoubleArraysPlus.dot(Vt[x], xv2);
+      for (int ii = 0; ii<cols; ii++) xv2[ii] -= tmp0*Vt[x][ii];
+      tmp0 = Math.sqrt(tmp0);
+      xnorm = Math.sqrt(DoubleArraysPlus.dot(xv2, xv2));
+
+      /* multiply by matrix A to get (scaled) left s-vector */
+      A.opa(Vt[x], Ut[x]);
+      tmp1 = 1.0/tmp0;
+      for (int ii = 0; ii<rows; ii++) Ut[x][ii] *= tmp1;
+      xnorm *= tmp1;
+      bnd[i] = xnorm;
+      S[x] = tmp0;
+    }
+
+    xv2 = w2 = null;
+    return nsig;
+    /* multiply by matrix A to get (scaled) left s-vector */
+
+  }
+
+  private int ritvec(SparseMatrix A, int[] steps_neig_) throws SparseSVDException {
+    //  computes the singular vectors of matrix A	       *
+/*  Parameters
+    (input)
+    nrow       number of rows of A
+    steps      number of Lanczos iterations performed
+    fp_out2    pointer to unformatted output file
+    n	      dimension of matrix A
+    kappa      relative accuracy of ritz values acceptable as 
+    eigenvalues of A'A
+    ritz       array of ritz values
+    bnd        array of error bounds
+    alf        array of diagonal elements of the tridiagonal matrix T
+    bet        array of off-diagonal elements of T
+    w1, w2     work space
+    (output)
+    xv1        array of eigenvectors of A'A (right singular vectors of A)
+    ierr	      error code
+    0 for normal return from imtql2()
+    k if convergence did not occur for k-th eigenvalue in
+    imtql2()
+    nsig       number of accepted ritz values based on kappa
+    (local)
+    s	      work array which is initialized to the identity matrix
+    of order (j + 1) upon calling imtql2().  After the call,
+    s contains the orthonormal eigenvectors of the symmetric 
+    tridiagonal matrix T
+     */
+    // int n = cols;
+
+    double[] w1 = Vt[0];
+    double[] w2 = new double[cols];
+    int js = steps_neig_[0]+1;
+    double[][] s = new double[js][js];
+    double[] xv2 = new double[cols];
+    /* initialize s to an identity matrix */
+    for (int i = 0; i<js; i++) s[i][i] = 1;
+    DoubleArraysPlus.copyReverse(js, alph, 0, w1, 0);
+    DoubleArraysPlus.copyReverse(steps_neig_[0], bet, 1, w2, 1);
+    /* on return from imtql2(), w1 contains eigenvalues in ascending 
+     * order and s contains the corresponding eigenvectors */
+    imtql2(js, js, w1, w2, s);
+    int nsig = 0;
+    int x = 0;
+    for (int k = 0; k<js; k++) {
+      if (bnd[k]<=KAPPA*Math.abs(ritz[k])&&k>js-steps_neig_[1]-1) {
+        if (--x<0) x = dim-1;
+        w1 = Vt[x];
+        for (int i = 0; i<cols; i++) w1[i] = 0;
+        for (int i = 0; i<js; i++) {
+          storage.retrieveQ(cols, i, w2);
+          for (int ii = 0; ii<cols; ii++) w1[ii] += s[k][js-1-i]*w2[ii];
+        }
+        /*fwrite((char *)w1, size, 1, fp_out2);*/
+
+        /* store the w1 vector row-wise in array xv1;   
+         * size of xv1 is (steps+1) * (nrow+ncol) elements 
+         * and each vector, even though only ncol long,
+         * will have (nrow+ncol) elements in xv1.      
+         * It is as if xv1 is a 2-d array (steps+1) by     
+         * (nrow+ncol) and each vector occupies a row  */
+
+        /* j is the index in the R arrays, which are sorted by high to low 
+        singular values. */
+
+        /*for (i = 0; i < n; i++) R->Vt->value[x]xv1[id++] = w1[i];*/
+        /*id += nrow;*/
+        nsig++;
+      }
+    }
+    s = null;  // libère la mémoire
+  /* Rotate the singular vectors and values. */
+    /* x is now the location of the highest singular value. */
+    DoubleArraysPlus.rotateArray(Vt, x);
+    int d = Math.min(dim, nsig);
+    for (x = 0; x<d; x++) {
+      /* multiply by matrix B first */
+      A.opb(Vt[x], xv2);
+      double tmp0 = DoubleArraysPlus.dot(Vt[x], xv2);
+      for (int i = 0; i<cols; i++) xv2[i] -= tmp0*Vt[x][i];
+      tmp0 = Math.sqrt(tmp0);
+      double xnorm = Math.sqrt(DoubleArraysPlus.dot(xv2, xv2));
+      /* multiply by matrix A to get (scaled) left s-vector */
+      A.opa(Vt[x], Ut[x]);
+      double tmp1 = 1/tmp0;
+      for (int i = 0; i<rows; i++) Ut[x][i] *= tmp1;
+      xnorm *= tmp1;
+      //   bnd[i] = xnorm; bizarre ??
+      S[x] = tmp0;
+    }
+    xv2 = w2 = null;
+    return nsig;
+  }
+
+  private static void imtql2(int nm, int n, double d[], double[] e, double[][] z)
+          throws SparseSVDException {
+    /*   imtqlb() finds the eigenvalues  and eigenvectors of a symmetric tridiagonal
+    matrix by the implicit QL method.
+    Arguments 
+    (input)
+    nm     row dimension of the symmetric tridiagonal matrix   
+    n      order of the symmetric tridiagonal matrix   
+    d      contains the diagonal elements of the input matrix           
+    e      contains the subdiagonal elements of the input matrix in its
+    last n-1 positions.  e[0] is arbitrary
+    z      contains the identity matrix
+    (output)
+    d      contains the eigenvalues in ascending order.  if an error
+    exit is made, the eigenvalues are correct but unordered for
+    indices 0,1,...ierr.
+    e      has been destroyed.					    
+    z      contains orthonormal eigenvectors of the symmetric   
+    tridiagonal (or full) matrix.  if an error exit is made,
+    z contains the eigenvectors associated with the stored 
+    eigenvalues.					
+    throws a SparseSVDException(j) if the j-th eigenvalue has
+    not been determined after 30 iterations.		    
+     */
+    if (n==1) return;
+    for (int i = 1; i<n; i++) e[i-1] = e[i];
+    e[n-1] = 0.0;
+    int nnm = n*nm;
+    for (int l = 0; l<n; l++) {
+      /* look for small sub-diagonal element */
+      for (int iteration = 0; iteration<=30; iteration++) {
+        double p = d[l];
+        int m;
+        for (m = l; m<n-1; m++) {// test de convergence
+          double test = Math.abs(d[m])+Math.abs(d[m+1]);
+          if (test+Math.abs(e[m])==test) break;
+        }
+        if (m==l) break;
+        /* set error -- no convergence to an eigenvalue after
+         * 30 iterations. */
+        if (iteration==30) throw new SparseSVDException(CodeSVDException.CONVERGENCE_FAILURE, l);
+        /* form shift */
+        double g = (d[l+1]-p)/(2*e[l]);
+        double r = Math.hypot(g, 1);
+        g = d[m]-p+e[l]/(g+Math.copySign(r, g));
+        double s = 1;
+        double c = 1;
+        p = 0;
+        boolean underflow = false;
+        for (int i = m-1; i>=l; i--) {
+          double f = s*e[i];
+          double b = c*e[i];
+          r = Math.hypot(f, g);
+          e[i+1] = r;
+          if (r==0) {
+            /*........ recover from underflow .........*/
+            underflow = true;
+            d[i+1] -= p;
+            e[m] = 0.0;
+            break;
+          }
+          s = f/r;
+          c = g/r;
+          g = d[i+1]-p;
+          r = (d[i]-g)*s+2*c*b;
+          p = s*r;
+          d[i+1] = g+p;
+          g = c*r-b;
+          /* form vector */
+          for (int k = 0; k<nm; k++) {
+            f = z[i+1][k];
+            z[i+1][k] = s*z[i][k]+c*f;
+            z[i][k] = c*z[i][k]-s*f;
+          }
+        }
+        if (!underflow) {
+          d[l] -= p;
+          e[l] = g;
+          e[m] = 0.0;
+        }
+      }
+    }
+    /* order the eigenvalues and corresponding eigenvectors */
+    DoubleArraysPlus.sort2(d, z, n, 0);
+  }
+
+  /* ------------------------
+  Public Methods
+   * ------------------------ */
+  /** Return the left singular vectors
+  @return     U
+   */
+  public Matrix getU() {
+    return transpose ? (new Matrix(Vt, dim, cols)).transpose()
+            : (new Matrix(Ut, dim, rows)).transpose();
+  }
+
+  /** Return the right singular vectors
+  @return     V
+   */
+  public Matrix getV() {
+    return transpose ? (new Matrix(Ut, dim, rows)).transpose()
+            : (new Matrix(Vt, dim, cols)).transpose();
+  }
+
+  /** Return the one-dimensional array of singular values
+  @return     diagonal of S.
+   */
+  public double[] getSingularValues() {
+    return Arrays.copyOfRange(S, 0, dim);
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SparseSVD.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/LUDecomposition.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/LUDecomposition.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/LUDecomposition.java	(revision 3653)
@@ -0,0 +1,311 @@
+package JamaPlus;
+
+   /** LU Decomposition.
+   <P>
+   For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n
+   unit lower triangular matrix L, an n-by-n upper triangular matrix U,
+   and a permutation vector piv of length m so that A(piv,:) = L*U.
+   If m < n, then L is m-by-m and U is m-by-n.
+   <P>
+   The LU decompostion with pivoting always exists, even if the matrix is
+   singular, so the constructor will never fail.  The primary use of the
+   LU decomposition is in the solution of square systems of simultaneous
+   linear equations.  This will fail if isNonsingular() returns false.
+   */
+
+public class LUDecomposition implements java.io.Serializable {
+
+/* ------------------------
+   Class variables
+ * ------------------------ */
+
+   /** Array for internal storage of decomposition.
+   @serial internal array storage.
+   */
+   private double[][] LU;
+
+   /** Row and column dimensions, and pivot sign.
+   @serial column dimension.
+   @serial row dimension.
+   @serial pivot sign.
+   */
+   private int m, n, pivsign; 
+
+   /** Internal storage of pivot vector.
+   @serial pivot vector.
+   */
+   private int[] piv;
+
+/* ------------------------
+   Constructor
+ * ------------------------ */
+
+   /** LU Decomposition
+   @param  A   Rectangular matrix
+   @return     Structure to access L, U and piv.
+   */
+
+   public LUDecomposition (Matrix A) {
+
+   // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
+
+      LU = A.getArrayCopy();
+      m = A.getRowDimension();
+      n = A.getColumnDimension();
+      piv = new int[m];
+      for (int i = 0; i < m; i++) {
+         piv[i] = i;
+      }
+      pivsign = 1;
+      double[] LUrowi;
+      double[] LUcolj = new double[m];
+
+      // Outer loop.
+
+      for (int j = 0; j < n; j++) {
+
+         // Make a copy of the j-th column to localize references.
+
+         for (int i = 0; i < m; i++) {
+            LUcolj[i] = LU[i][j];
+         }
+
+         // Apply previous transformations.
+
+         for (int i = 0; i < m; i++) {
+            LUrowi = LU[i];
+
+            // Most of the time is spent in the following dot product.
+
+            int kmax = Math.min(i,j);
+            double s = 0.0;
+            for (int k = 0; k < kmax; k++) {
+               s += LUrowi[k]*LUcolj[k];
+            }
+
+            LUrowi[j] = LUcolj[i] -= s;
+         }
+   
+         // Find pivot and exchange if necessary.
+
+         int p = j;
+         for (int i = j+1; i < m; i++) {
+            if (Math.abs(LUcolj[i]) > Math.abs(LUcolj[p])) {
+               p = i;
+            }
+         }
+         if (p != j) {
+            for (int k = 0; k < n; k++) {
+               double t = LU[p][k]; LU[p][k] = LU[j][k]; LU[j][k] = t;
+            }
+            int k = piv[p]; piv[p] = piv[j]; piv[j] = k;
+            pivsign = -pivsign;
+         }
+
+         // Compute multipliers.
+         
+         if (j < m & LU[j][j] != 0.0) {
+            for (int i = j+1; i < m; i++) {
+               LU[i][j] /= LU[j][j];
+            }
+         }
+      }
+   }
+
+/* ------------------------
+   Temporary, experimental code.
+   ------------------------ *\
+
+   \** LU Decomposition, computed by Gaussian elimination.
+   <P>
+   This constructor computes L and U with the "daxpy"-based elimination
+   algorithm used in LINPACK and MATLAB.  In Java, we suspect the dot-product,
+   Crout algorithm will be faster.  We have temporarily included this
+   constructor until timing experiments confirm this suspicion.
+   <P>
+   @param  A             Rectangular matrix
+   @param  linpackflag   Use Gaussian elimination.  Actual value ignored.
+   @return               Structure to access L, U and piv.
+   *\
+
+   public LUDecomposition (Matrix A, int linpackflag) {
+      // Initialize.
+      LU = A.getArrayCopy();
+      m = A.getRowDimension();
+      n = A.getColumnDimension();
+      piv = new int[m];
+      for (int i = 0; i < m; i++) {
+         piv[i] = i;
+      }
+      pivsign = 1;
+      // Main loop.
+      for (int k = 0; k < n; k++) {
+         // Find pivot.
+         int p = k;
+         for (int i = k+1; i < m; i++) {
+            if (Math.abs(LU[i][k]) > Math.abs(LU[p][k])) {
+               p = i;
+            }
+         }
+         // Exchange if necessary.
+         if (p != k) {
+            for (int j = 0; j < n; j++) {
+               double t = LU[p][j]; LU[p][j] = LU[k][j]; LU[k][j] = t;
+            }
+            int t = piv[p]; piv[p] = piv[k]; piv[k] = t;
+            pivsign = -pivsign;
+         }
+         // Compute multipliers and eliminate k-th column.
+         if (LU[k][k] != 0.0) {
+            for (int i = k+1; i < m; i++) {
+               LU[i][k] /= LU[k][k];
+               for (int j = k+1; j < n; j++) {
+                  LU[i][j] -= LU[i][k]*LU[k][j];
+               }
+            }
+         }
+      }
+   }
+
+\* ------------------------
+   End of temporary code.
+ * ------------------------ */
+
+/* ------------------------
+   Public Methods
+ * ------------------------ */
+
+   /** Is the matrix nonsingular?
+   @return     true if U, and hence A, is nonsingular.
+   */
+
+   public boolean isNonsingular () {
+      for (int j = 0; j < n; j++) {
+         if (LU[j][j] == 0)
+            return false;
+      }
+      return true;
+   }
+
+   /** Return lower triangular factor
+   @return     L
+   */
+
+   public Matrix getL () {
+      Matrix X = new Matrix(m,n);
+      double[][] L = X.getArray();
+      for (int i = 0; i < m; i++) {
+         for (int j = 0; j < n; j++) {
+            if (i > j) {
+               L[i][j] = LU[i][j];
+            } else if (i == j) {
+               L[i][j] = 1.0;
+            } else {
+               L[i][j] = 0.0;
+            }
+         }
+      }
+      return X;
+   }
+
+   /** Return upper triangular factor
+   @return     U
+   */
+
+   public Matrix getU () {
+      Matrix X = new Matrix(n,n);
+      double[][] U = X.getArray();
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            if (i <= j) {
+               U[i][j] = LU[i][j];
+            } else {
+               U[i][j] = 0.0;
+            }
+         }
+      }
+      return X;
+   }
+
+   /** Return pivot permutation vector
+   @return     piv
+   */
+
+   public int[] getPivot () {
+      int[] p = new int[m];
+      for (int i = 0; i < m; i++) {
+         p[i] = piv[i];
+      }
+      return p;
+   }
+
+   /** Return pivot permutation vector as a one-dimensional double array
+   @return     (double) piv
+   */
+
+   public double[] getDoublePivot () {
+      double[] vals = new double[m];
+      for (int i = 0; i < m; i++) {
+         vals[i] = (double) piv[i];
+      }
+      return vals;
+   }
+
+   /** Determinant
+   @return     det(A)
+   @exception  IllegalArgumentException  Matrix must be square
+   */
+
+   public double det () {
+      if (m != n) {
+         throw new IllegalArgumentException("Matrix must be square.");
+      }
+      double d = (double) pivsign;
+      for (int j = 0; j < n; j++) {
+         d *= LU[j][j];
+      }
+      return d;
+   }
+
+   /** Solve A*X = B
+   @param  B   A Matrix with as many rows as A and any number of columns.
+   @return     X so that L*U*X = B(piv,:)
+   @exception  IllegalArgumentException Matrix row dimensions must agree.
+   @exception  RuntimeException  Matrix is singular.
+   */
+
+   public Matrix solve (Matrix B) {
+      if (B.getRowDimension() != m) {
+         throw new IllegalArgumentException("Matrix row dimensions must agree.");
+      }
+      if (!this.isNonsingular()) {
+         throw new RuntimeException("Matrix is singular.");
+      }
+
+      // Copy right hand side with pivoting
+      int nx = B.getColumnDimension();
+      Matrix Xmat = B.getMatrix(piv,0,nx-1);
+      double[][] X = Xmat.getArray();
+
+      // Solve L*Y = B(piv,:)
+      for (int k = 0; k < n; k++) {
+         for (int i = k+1; i < n; i++) {
+            for (int j = 0; j < nx; j++) {
+               X[i][j] -= X[k][j]*LU[i][k];
+            }
+         }
+      }
+      // Solve U*X = Y;
+      for (int k = n-1; k >= 0; k--) {
+         for (int j = 0; j < nx; j++) {
+            X[k][j] /= LU[k][k];
+         }
+         for (int i = 0; i < k; i++) {
+            for (int j = 0; j < nx; j++) {
+               X[i][j] -= X[k][j]*LU[i][k];
+            }
+         }
+      }
+      return Xmat;
+   }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/LUDecomposition.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/util/DoubleArraysPlus.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/util/DoubleArraysPlus.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/util/DoubleArraysPlus.java	(revision 3653)
@@ -0,0 +1,97 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package JamaPlus.util;
+
+import java.util.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class DoubleArraysPlus {
+  public static void copyReverse(int length, double[] src, int srcStart,
+          double[] dest, int destStart) {
+    destStart += length-1;
+    for (int i = 0; i<length; i++) dest[destStart-i] = src[srcStart+i];
+  }
+
+   private static class Couple implements Comparable<Couple> {
+    double x1;
+    Object x2;
+
+    public int compareTo(Couple c) {
+      return Double.compare(x1, c.x1);
+    }
+  }
+
+  public static void sort2(double[] a1, double[] a2, int n, int istart) {
+    // sort the first n elements of a1 and a2, starting at index istart,
+    // in increasing order for a1 
+    // (elements with indexes < istart or > istart + n preserved) 
+    Couple[] cs = new Couple[n];
+    for (int i = 0; i<n; i++) {
+      cs[i] = new Couple();
+      cs[i].x1 = a1[i+istart];
+      cs[i].x2 = a2[i+istart];
+    }
+    Arrays.sort(cs);
+    for (int i = 0; i<n; i++) {
+      a1[i+istart] = cs[i].x1;
+      a2[i+istart] = (Double) cs[i].x2;
+    }
+  }
+ public static void sort2(double[] a1, double[][] a2, int n, int istart) {
+    // sort the first n elements of a1 and a2[] (lines of array a2)
+//    starting at index istart, in increasing order for a1
+    // (elements with index < istart or > istart + n preserved) 
+    Couple[] cs = new Couple[n];
+    for (int i = 0; i<n; i++) {
+      cs[i] = new Couple();
+      cs[i].x1 = a1[i+istart];
+      cs[i].x2 = a2[i+istart];
+    }
+    Arrays.sort(cs);
+    for (int i = 0; i<n; i++) {
+      a1[i+istart] = cs[i].x1;
+      a2[i+istart] = (double[]) cs[i].x2;
+    }
+  }
+
+  public static int indAbsMax(int n, double x[], int istart) {
+    // finds the index of element having maximum absolute value 
+    // among the first n elements of x starting at index istart
+    if (n<1||istart<0||istart+n>x.length)
+      throw new ArrayIndexOutOfBoundsException();
+    if (n==1) return (istart);
+    double max = Math.abs(x[istart]);
+    int imax = istart;
+    for (int i = istart+1; i<istart+n; i++) {
+      double ax = Math.abs(x[i]);
+      if (ax>max) {
+        max = ax;
+        imax = i;
+      }
+    }
+    return imax;
+  }
+
+  public static double dot(double[] x, double[] y) {
+    // dot product of vectors x and y
+    int n = x.length;
+    if (n!=y.length) throw new IllegalArgumentException();
+    double res = 0;
+    for (int i = 0; i<n; i++) res += x[i]*y[i];
+    return res;
+  }
+  public static void rotateArray(double[][] a, int x) {
+    // permutation circulaire des lignes de la matrice a
+    // plaçant la ligne x en tête
+  double[][] b =new double[a.length-x][];
+ System.arraycopy(a, x, b, 0, b.length);
+ System.arraycopy(a, 0, a, b.length, a.length-b.length);
+ System.arraycopy(b, 0, a, 0, b.length);
+     }
+
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/util/DoubleArraysPlus.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/util/Machine.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/util/Machine.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/util/Machine.java	(revision 3653)
@@ -0,0 +1,143 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package JamaPlus.util;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class Machine {
+
+    /***********************************************************************
+     *                                                                     *
+     *				machar()			       *
+     *                                                                     *
+     ***********************************************************************/
+    /***********************************************************************
+    
+    Description
+    -----------
+    
+    This function is a partial translation of a Fortran-77 subroutine 
+    written by W. J. Cody of Argonne National Laboratory.
+    It dynamically determines the listed machine parameters of the
+    floating-point arithmetic.  According to the documentation of
+    the Fortran code, "the determination of the first three uses an
+    extension of an algorithm due to M. Malcolm, ACM 15 (1972), 
+    pp. 949-951, incorporating some, but not all, of the improvements
+    suggested by M. Gentleman and S. Marovich, CACM 17 (1974), 
+    pp. 276-277."  The complete Fortran version of this translation is
+    documented in W. J. Cody, "Machar: a Subroutine to Dynamically 
+    Determine Determine Machine Parameters," TOMS 14, December, 1988.
+    
+    
+    Parameters reported 
+    -------------------
+    
+    ibeta     the radix for the floating-point representation       
+    it        the number of base ibeta digits in the floating-point
+    significand					 
+    irnd      0 if floating-point addition chops		      
+    1 if floating-point addition rounds, but not in the 
+    ieee style					
+    2 if floating-point addition rounds in the ieee style
+    3 if floating-point addition chops, and there is    
+    partial underflow				
+    4 if floating-point addition rounds, but not in the
+    ieee style, and there is partial underflow    
+    5 if floating-point addition rounds in the ieee style,
+    and there is partial underflow                   
+    machep    the largest negative integer such that              
+    1.0+float(ibeta)**machep .ne. 1.0, except that 
+    machep is bounded below by  -(it+3)          
+    negeps    the largest negative integer such that          
+    1.0-float(ibeta)**negeps .ne. 1.0, except that 
+    negeps is bounded below by  -(it+3)	       
+    
+     ***********************************************************************/
+    public static double eps(/*int res[]*/) {
+        int ibeta, it, irnd, machep, negep;
+        double beta, betain, betah, a, b = 0, ZERO, ONE, TWO, temp, tempa, temp1;
+        int i, itemp;
+
+        ONE = (double) 1;
+        TWO = ONE + ONE;
+        ZERO = ONE - ONE;
+
+        a = ONE;
+        temp1 = ONE;
+        while (temp1 - ONE == ZERO) {
+            a += a;
+            temp = a + ONE;
+            temp1 = temp - a;
+            b += a; /* to prevent icc compiler error */
+        }
+        b = ONE;
+        itemp = 0;
+        while (itemp == 0) {
+            b += b;
+            temp = a + b;
+            itemp = (int) (temp - a);
+        }
+        ibeta = itemp;
+        beta = (double) ibeta;
+
+        it = 0;
+        b = ONE;
+        temp1 = ONE;
+        while (temp1 - ONE == ZERO) {
+            it++;
+            b *= beta;
+            temp = b + ONE;
+            temp1 = temp - b;
+        }
+        irnd = 0;
+        betah = beta / TWO;
+        temp = a + betah;
+        if (temp - a != ZERO) irnd = 1;
+        tempa = a + beta;
+        temp = tempa + betah;
+        if ((irnd == 0) && (temp - tempa != ZERO)) irnd = 2;
+
+        negep = it + 3;
+        betain = ONE / beta;
+        a = ONE;
+        for (i = 0; i < negep; i++) a *= betain;
+        b = a;
+        temp = ONE - a;
+        while (temp - ONE == ZERO) {
+            a *= beta;
+            negep--;
+            temp = ONE - a;
+        }
+        negep = -(negep);
+
+        machep = -(it) - 3;
+        a = b;
+        temp = ONE + a;
+        while (temp - ONE == ZERO) {
+            a *= beta;
+            machep += 1;
+            temp = ONE + a;
+        }
+//        res[0] = ibeta;
+//        res[1] = it;
+//        res[2] = irnd;
+//        res[3] = machep;
+//        res[4] = negep;
+        return a;
+    }
+
+    static public void main(String[] args) {
+        int[] res = new int[5];
+//        double precision = eps(res);
+//        System.out.println("eps = " + precision);
+        System.out.println("ibeta = " + res[0]);
+        System.out.println("it = " + res[1]);
+        System.out.println("irnd = " + res[2]);
+        System.out.println("machep = " + res[3]);
+        System.out.println("negep = " + res[4]);
+    }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/util/Machine.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/CholeskyDecomposition.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/CholeskyDecomposition.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/CholeskyDecomposition.java	(revision 3653)
@@ -0,0 +1,199 @@
+package JamaPlus;
+
+   /** Cholesky Decomposition.
+   <P>
+   For a symmetric, positive definite matrix A, the Cholesky decomposition
+   is an lower triangular matrix L so that A = L*L'.
+   <P>
+   If the matrix is not symmetric or positive definite, the constructor
+   returns a partial decomposition and sets an internal flag that may
+   be queried by the isSPD() method.
+   */
+
+public class CholeskyDecomposition implements java.io.Serializable {
+
+/* ------------------------
+   Class variables
+ * ------------------------ */
+
+   /** Array for internal storage of decomposition.
+   @serial internal array storage.
+   */
+   private double[][] L;
+
+   /** Row and column dimension (square matrix).
+   @serial matrix dimension.
+   */
+   private int n;
+
+   /** Symmetric and positive definite flag.
+   @serial is symmetric and positive definite flag.
+   */
+   private boolean isspd;
+
+/* ------------------------
+   Constructor
+ * ------------------------ */
+
+   /** Cholesky algorithm for symmetric and positive definite matrix.
+   @param  A   Square, symmetric matrix.
+   @return     Structure to access L and isspd flag.
+   */
+
+   public CholeskyDecomposition (Matrix Arg) {
+
+
+     // Initialize.
+      double[][] A = Arg.getArray();
+      n = Arg.getRowDimension();
+      L = new double[n][n];
+      isspd = (Arg.getColumnDimension() == n);
+      // Main loop.
+      for (int j = 0; j < n; j++) {
+         double[] Lrowj = L[j];
+         double d = 0.0;
+         for (int k = 0; k < j; k++) {
+            double[] Lrowk = L[k];
+            double s = 0.0;
+            for (int i = 0; i < k; i++) {
+               s += Lrowk[i]*Lrowj[i];
+            }
+            Lrowj[k] = s = (A[j][k] - s)/L[k][k];
+            d = d + s*s;
+            isspd = isspd & (A[k][j] == A[j][k]); 
+         }
+         d = A[j][j] - d;
+         isspd = isspd & (d > 0.0);
+         L[j][j] = Math.sqrt(Math.max(d,0.0));
+         for (int k = j+1; k < n; k++) {
+            L[j][k] = 0.0;
+         }
+      }
+   }
+
+/* ------------------------
+   Temporary, experimental code.
+ * ------------------------ *\
+
+   \** Right Triangular Cholesky Decomposition.
+   <P>
+   For a symmetric, positive definite matrix A, the Right Cholesky
+   decomposition is an upper triangular matrix R so that A = R'*R.
+   This constructor computes R with the Fortran inspired column oriented
+   algorithm used in LINPACK and MATLAB.  In Java, we suspect a row oriented,
+   lower triangular decomposition is faster.  We have temporarily included
+   this constructor here until timing experiments confirm this suspicion.
+   *\
+
+   \** Array for internal storage of right triangular decomposition. **\
+   private transient double[][] R;
+
+   \** Cholesky algorithm for symmetric and positive definite matrix.
+   @param  A           Square, symmetric matrix.
+   @param  rightflag   Actual value ignored.
+   @return             Structure to access R and isspd flag.
+   *\
+
+   public CholeskyDecomposition (Matrix Arg, int rightflag) {
+      // Initialize.
+      double[][] A = Arg.getArray();
+      n = Arg.getColumnDimension();
+      R = new double[n][n];
+      isspd = (Arg.getColumnDimension() == n);
+      // Main loop.
+      for (int j = 0; j < n; j++) {
+         double d = 0.0;
+         for (int k = 0; k < j; k++) {
+            double s = A[k][j];
+            for (int i = 0; i < k; i++) {
+               s = s - R[i][k]*R[i][j];
+            }
+            R[k][j] = s = s/R[k][k];
+            d = d + s*s;
+            isspd = isspd & (A[k][j] == A[j][k]); 
+         }
+         d = A[j][j] - d;
+         isspd = isspd & (d > 0.0);
+         R[j][j] = Math.sqrt(Math.max(d,0.0));
+         for (int k = j+1; k < n; k++) {
+            R[k][j] = 0.0;
+         }
+      }
+   }
+
+   \** Return upper triangular factor.
+   @return     R
+   *\
+
+   public Matrix getR () {
+      return new Matrix(R,n,n);
+   }
+
+\* ------------------------
+   End of temporary code.
+ * ------------------------ */
+
+/* ------------------------
+   Public Methods
+ * ------------------------ */
+
+   /** Is the matrix symmetric and positive definite?
+   @return     true if A is symmetric and positive definite.
+   */
+
+   public boolean isSPD () {
+      return isspd;
+   }
+
+   /** Return triangular factor.
+   @return     L
+   */
+
+   public Matrix getL () {
+      return new Matrix(L,n,n);
+   }
+
+   /** Solve A*X = B
+   @param  B   A Matrix with as many rows as A and any number of columns.
+   @return     X so that L*L'*X = B
+   @exception  IllegalArgumentException  Matrix row dimensions must agree.
+   @exception  RuntimeException  Matrix is not symmetric positive definite.
+   */
+
+   public Matrix solve (Matrix B) {
+      if (B.getRowDimension() != n) {
+         throw new IllegalArgumentException("Matrix row dimensions must agree.");
+      }
+      if (!isspd) {
+         throw new RuntimeException("Matrix is not symmetric positive definite.");
+      }
+
+      // Copy right hand side.
+      double[][] X = B.getArrayCopy();
+      int nx = B.getColumnDimension();
+
+	      // Solve L*Y = B;
+	      for (int k = 0; k < n; k++) {
+	        for (int j = 0; j < nx; j++) {
+	           for (int i = 0; i < k ; i++) {
+	               X[k][j] -= X[i][j]*L[k][i];
+	           }
+	           X[k][j] /= L[k][k];
+	        }
+	      }
+	
+	      // Solve L'*X = Y;
+	      for (int k = n-1; k >= 0; k--) {
+	        for (int j = 0; j < nx; j++) {
+	           for (int i = k+1; i < n ; i++) {
+	               X[k][j] -= X[i][j]*L[i][k];
+	           }
+	           X[k][j] /= L[k][k];
+	        }
+	      }
+      
+      
+      return new Matrix(X,n,nx);
+   }
+}
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/CholeskyDecomposition.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SingularValueDecomposition.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SingularValueDecomposition.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SingularValueDecomposition.java	(revision 3653)
@@ -0,0 +1,556 @@
+package JamaPlus;
+import JamaPlus.util.*;
+
+   /** Singular Value Decomposition.
+   <P>
+   For an m-by-n matrix A with m >= n, the singular value decomposition is
+   an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and
+   an n-by-n orthogonal matrix V so that A = U*S*V'.
+   <P>
+   The singular values, sigma[k] = S[k][k], are ordered so that
+   sigma[0] >= sigma[1] >= ... >= sigma[n-1].
+   <P>
+   The singular value decompostion always exists, so the constructor will
+   never fail.  The matrix condition number and the effective numerical
+   rank can be computed from this decomposition.
+   */
+
+public class SingularValueDecomposition implements java.io.Serializable {
+
+/* ------------------------
+   Class variables
+ * ------------------------ */
+
+   /** Arrays for internal storage of U and V.
+   @serial internal storage of U.
+   @serial internal storage of V.
+   */
+   private double[][] U, V;
+
+   /** Array for internal storage of singular values.
+   @serial internal storage of singular values.
+   */
+   private double[] s;
+
+   /** Row and column dimensions.
+   @serial row dimension.
+   @serial column dimension.
+   */
+   private int m, n;
+   
+   private boolean transpose; // pour éviter les bugs quand m<n (cf.ci-dessous) 
+
+/* ------------------------
+   Constructor
+ * ------------------------ */
+
+   /** Construct the singular value decomposition
+   @param A    Rectangular matrix
+   @return     Structure to access U, S and V.
+   */
+
+   public SingularValueDecomposition (Matrix Arg) {
+
+      // Derived from LINPACK code.
+      // Initialize.
+      /* Apparently the failing cases are only a proper subset of (m<n), 
+	 so let's not throw error.  Correct fix to come later?
+      if (m<n) {
+	  throw new IllegalArgumentException("Jama SVD only works for m >= n"); }
+      */
+      /* 
+       * Une façon très simple de contourner le problème ci-dessus :
+       * si m < n on transpose A
+       * (ce qui revient à échanger U et V, S restant inchangé)
+       */
+   transpose = Arg.getColumnDimension()>Arg.getRowDimension();
+    Matrix M = transpose ? Arg.transpose() : Arg.copy();
+  
+     double[][] A = M.getArray();
+      m = M.getRowDimension();
+      n = M.getColumnDimension();
+
+      s = new double [n];
+      U = new double [m][n];
+      V = new double [n][n];
+      double[] e = new double [n];
+      double[] work = new double [m];
+      boolean wantu = true;
+      boolean wantv = true;
+
+      // Reduce A to bidiagonal form, storing the diagonal elements
+      // in s and the super-diagonal elements in e.
+
+      int nct = Math.min(m-1,n);
+      int nrt = Math.max(0,Math.min(n-2,m));
+      for (int k = 0; k < Math.max(nct,nrt); k++) {
+         if (k < nct) {
+
+            // Compute the transformation for the k-th column and
+            // place the k-th diagonal in s[k].
+            // Compute 2-norm of k-th column without under/overflow.
+            s[k] = 0;
+            for (int i = k; i < m; i++) {
+               s[k] = Math.hypot(s[k],A[i][k]);
+            }
+            if (s[k] != 0.0) {
+               if (A[k][k] < 0.0) {
+                  s[k] = -s[k];
+               }
+               for (int i = k; i < m; i++) {
+                  A[i][k] /= s[k];
+               }
+               A[k][k] += 1.0;
+            }
+            s[k] = -s[k];
+         }
+         for (int j = k+1; j < n; j++) {
+            if ((k < nct) & (s[k] != 0.0))  {
+
+            // Apply the transformation.
+
+               double t = 0;
+               for (int i = k; i < m; i++) {
+                  t += A[i][k]*A[i][j];
+               }
+               t = -t/A[k][k];
+               for (int i = k; i < m; i++) {
+                  A[i][j] += t*A[i][k];
+               }
+            }
+
+            // Place the k-th row of A into e for the
+            // subsequent calculation of the row transformation.
+
+            e[j] = A[k][j];
+         }
+         if (wantu & (k < nct)) {
+
+            // Place the transformation in U for subsequent back
+            // multiplication.
+
+            for (int i = k; i < m; i++) {
+               U[i][k] = A[i][k];
+            }
+         }
+         if (k < nrt) {
+
+            // Compute the k-th row transformation and place the
+            // k-th super-diagonal in e[k].
+            // Compute 2-norm without under/overflow.
+            e[k] = 0;
+            for (int i = k+1; i < n; i++) {
+               e[k] = Math.hypot(e[k],e[i]);
+            }
+            if (e[k] != 0.0) {
+               if (e[k+1] < 0.0) {
+                  e[k] = -e[k];
+               }
+               for (int i = k+1; i < n; i++) {
+                  e[i] /= e[k];
+               }
+               e[k+1] += 1.0;
+            }
+            e[k] = -e[k];
+            if ((k+1 < m) & (e[k] != 0.0)) {
+
+            // Apply the transformation.
+
+               for (int i = k+1; i < m; i++) {
+                  work[i] = 0.0;
+               }
+               for (int j = k+1; j < n; j++) {
+                  for (int i = k+1; i < m; i++) {
+                     work[i] += e[j]*A[i][j];
+                  }
+               }
+               for (int j = k+1; j < n; j++) {
+                  double t = -e[j]/e[k+1];
+                  for (int i = k+1; i < m; i++) {
+                     A[i][j] += t*work[i];
+                  }
+               }
+            }
+            if (wantv) {
+
+            // Place the transformation in V for subsequent
+            // back multiplication.
+
+               for (int i = k+1; i < n; i++) {
+                  V[i][k] = e[i];
+               }
+            }
+         }
+      }
+
+      // Set up the final bidiagonal matrix or order p.
+
+      int p = Math.min(n,m+1);
+      if (nct < n) {
+         s[nct] = A[nct][nct];
+      }
+      if (m < p) {
+         s[p-1] = 0.0;
+      }
+      if (nrt+1 < p) {
+         e[nrt] = A[nrt][p-1];
+      }
+      e[p-1] = 0.0;
+
+      // If required, generate U.
+
+      if (wantu) {
+         for (int j = nct; j < n; j++) {
+            for (int i = 0; i < m; i++) {
+               U[i][j] = 0.0;
+            }
+            U[j][j] = 1.0;
+         }
+         for (int k = nct-1; k >= 0; k--) {
+            if (s[k] != 0.0) {
+               for (int j = k+1; j < n; j++) {
+                  double t = 0;
+                  for (int i = k; i < m; i++) {
+                     t += U[i][k]*U[i][j];
+                  }
+                  t = -t/U[k][k];
+                  for (int i = k; i < m; i++) {
+                     U[i][j] += t*U[i][k];
+                  }
+               }
+               for (int i = k; i < m; i++ ) {
+                  U[i][k] = -U[i][k];
+               }
+               U[k][k] = 1.0 + U[k][k];
+               for (int i = 0; i < k-1; i++) {
+                  U[i][k] = 0.0;
+               }
+            } else {
+               for (int i = 0; i < m; i++) {
+                  U[i][k] = 0.0;
+               }
+               U[k][k] = 1.0;
+            }
+         }
+      }
+
+      // If required, generate V.
+
+      if (wantv) {
+         for (int k = n-1; k >= 0; k--) {
+            if ((k < nrt) & (e[k] != 0.0)) {
+               for (int j = k+1; j < n; j++) {
+                  double t = 0;
+                  for (int i = k+1; i < n; i++) {
+                     t += V[i][k]*V[i][j];
+                  }
+                  t = -t/V[k+1][k];
+                  for (int i = k+1; i < n; i++) {
+                     V[i][j] += t*V[i][k];
+                  }
+               }
+            }
+            for (int i = 0; i < n; i++) {
+               V[i][k] = 0.0;
+            }
+            V[k][k] = 1.0;
+         }
+      }
+
+      // Main iteration loop for the singular values.
+
+      int pp = p-1;
+      int iter = 0;
+      double eps = Math.pow(2.0,-52.0);
+      double tiny = Math.pow(2.0,-966.0);
+      while (p > 0) {
+         int k,kase;
+
+         // Here is where a test for too many iterations would go.
+
+         // This section of the program inspects for
+         // negligible elements in the s and e arrays.  On
+         // completion the variables kase and k are set as follows.
+
+         // kase = 1     if s(p) and e[k-1] are negligible and k<p
+         // kase = 2     if s(k) is negligible and k<p
+         // kase = 3     if e[k-1] is negligible, k<p, and
+         //              s(k), ..., s(p) are not negligible (qr step).
+         // kase = 4     if e(p-1) is negligible (convergence).
+
+         for (k = p-2; k >= -1; k--) {
+            if (k == -1) {
+               break;
+            }
+            if (Math.abs(e[k]) <=
+                  tiny + eps*(Math.abs(s[k]) + Math.abs(s[k+1]))) {
+               e[k] = 0.0;
+               break;
+            }
+         }
+         if (k == p-2) {
+            kase = 4;
+         } else {
+            int ks;
+            for (ks = p-1; ks >= k; ks--) {
+               if (ks == k) {
+                  break;
+               }
+               double t = (ks != p ? Math.abs(e[ks]) : 0.) + 
+                          (ks != k+1 ? Math.abs(e[ks-1]) : 0.);
+               if (Math.abs(s[ks]) <= tiny + eps*t)  {
+                  s[ks] = 0.0;
+                  break;
+               }
+            }
+            if (ks == k) {
+               kase = 3;
+            } else if (ks == p-1) {
+               kase = 1;
+            } else {
+               kase = 2;
+               k = ks;
+            }
+         }
+         k++;
+
+         // Perform the task indicated by kase.
+
+         switch (kase) {
+
+            // Deflate negligible s(p).
+
+            case 1: {
+               double f = e[p-2];
+               e[p-2] = 0.0;
+               for (int j = p-2; j >= k; j--) {
+                  double t = Math.hypot(s[j],f);
+                  double cs = s[j]/t;
+                  double sn = f/t;
+                  s[j] = t;
+                  if (j != k) {
+                     f = -sn*e[j-1];
+                     e[j-1] = cs*e[j-1];
+                  }
+                  if (wantv) {
+                     for (int i = 0; i < n; i++) {
+                        t = cs*V[i][j] + sn*V[i][p-1];
+                        V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1];
+                        V[i][j] = t;
+                     }
+                  }
+               }
+            }
+            break;
+
+            // Split at negligible s(k).
+
+            case 2: {
+               double f = e[k-1];
+               e[k-1] = 0.0;
+               for (int j = k; j < p; j++) {
+                  double t = Math.hypot(s[j],f);
+                  double cs = s[j]/t;
+                  double sn = f/t;
+                  s[j] = t;
+                  f = -sn*e[j];
+                  e[j] = cs*e[j];
+                  if (wantu) {
+                     for (int i = 0; i < m; i++) {
+                        t = cs*U[i][j] + sn*U[i][k-1];
+                        U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1];
+                        U[i][j] = t;
+                     }
+                  }
+               }
+            }
+            break;
+
+            // Perform one qr step.
+
+            case 3: {
+
+               // Calculate the shift.
+   
+               double scale = Math.max(Math.max(Math.max(Math.max(
+                       Math.abs(s[p-1]),Math.abs(s[p-2])),Math.abs(e[p-2])), 
+                       Math.abs(s[k])),Math.abs(e[k]));
+               double sp = s[p-1]/scale;
+               double spm1 = s[p-2]/scale;
+               double epm1 = e[p-2]/scale;
+               double sk = s[k]/scale;
+               double ek = e[k]/scale;
+               double b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
+               double c = (sp*epm1)*(sp*epm1);
+               double shift = 0.0;
+               if ((b != 0.0) | (c != 0.0)) {
+                  shift = Math.sqrt(b*b + c);
+                  if (b < 0.0) {
+                     shift = -shift;
+                  }
+                  shift = c/(b + shift);
+               }
+               double f = (sk + sp)*(sk - sp) + shift;
+               double g = sk*ek;
+   
+               // Chase zeros.
+   
+               for (int j = k; j < p-1; j++) {
+                  double t = Math.hypot(f,g);
+                  double cs = f/t;
+                  double sn = g/t;
+                  if (j != k) {
+                     e[j-1] = t;
+                  }
+                  f = cs*s[j] + sn*e[j];
+                  e[j] = cs*e[j] - sn*s[j];
+                  g = sn*s[j+1];
+                  s[j+1] = cs*s[j+1];
+                  if (wantv) {
+                     for (int i = 0; i < n; i++) {
+                        t = cs*V[i][j] + sn*V[i][j+1];
+                        V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1];
+                        V[i][j] = t;
+                     }
+                  }
+                  t = Math.hypot(f,g);
+                  cs = f/t;
+                  sn = g/t;
+                  s[j] = t;
+                  f = cs*e[j] + sn*s[j+1];
+                  s[j+1] = -sn*e[j] + cs*s[j+1];
+                  g = sn*e[j+1];
+                  e[j+1] = cs*e[j+1];
+                  if (wantu && (j < m-1)) {
+                     for (int i = 0; i < m; i++) {
+                        t = cs*U[i][j] + sn*U[i][j+1];
+                        U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1];
+                        U[i][j] = t;
+                     }
+                  }
+               }
+               e[p-2] = f;
+               iter = iter + 1;
+            }
+            break;
+
+            // Convergence.
+
+            case 4: {
+
+               // Make the singular values positive.
+   
+               if (s[k] <= 0.0) {
+                  s[k] = (s[k] < 0.0 ? -s[k] : 0.0);
+                  if (wantv) {
+                     for (int i = 0; i <= pp; i++) {
+                        V[i][k] = -V[i][k];
+                     }
+                  }
+               }
+   
+               // Order the singular values.
+   
+               while (k < pp) {
+                  if (s[k] >= s[k+1]) {
+                     break;
+                  }
+                  double t = s[k];
+                  s[k] = s[k+1];
+                  s[k+1] = t;
+                  if (wantv && (k < n-1)) {
+                     for (int i = 0; i < n; i++) {
+                        t = V[i][k+1]; V[i][k+1] = V[i][k]; V[i][k] = t;
+                     }
+                  }
+                  if (wantu && (k < m-1)) {
+                     for (int i = 0; i < m; i++) {
+                        t = U[i][k+1]; U[i][k+1] = U[i][k]; U[i][k] = t;
+                     }
+                  }
+                  k++;
+               }
+               iter = 0;
+               p--;
+            }
+            break;
+         }
+      }
+   }
+
+/* ------------------------
+   Public Methods
+ * ------------------------ */
+
+   /** Return the left singular vectors
+   @return     U
+   */
+
+   public Matrix getU () {
+      return transpose ? new Matrix(V,n,n) : new Matrix(U,m,n);
+   }
+
+   /** Return the right singular vectors
+   @return     V
+   */
+
+   public Matrix getV () {
+      return transpose ? new Matrix(U,m,n) : new Matrix(V,n,n);
+   }
+
+   /** Return the one-dimensional array of singular values
+   @return     diagonal of S.
+   */
+
+   public double[] getSingularValues () {
+      return s;
+   }
+
+   /** Return the diagonal matrix of singular values
+   @return     S
+   */
+
+   public Matrix getS () {
+      Matrix X = new Matrix(n,n);
+      double[][] S = X.getArray();
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            S[i][j] = 0.0;
+         }
+         S[i][i] = this.s[i];
+      }
+      return X;
+   }
+
+   /** Two norm
+   @return     max(S)
+   */
+
+   public double norm2 () {
+      return s[0];
+   }
+
+   /** Two norm condition number
+   @return     max(S)/min(S)
+   */
+
+   public double cond () {
+      return s[0]/s[Math.min(m,n)-1];
+   }
+
+   /** Effective numerical matrix rank
+   @return     Number of nonnegligible singular values.
+   */
+
+   public int rank () {
+      double eps = Math.pow(2.0,-52.0);
+      double tol = Math.max(m,n)*s[0]*eps;
+      int r = 0;
+      for (int i = 0; i < s.length; i++) {
+         if (s[i] > tol) {
+            r++;
+         }
+      }
+      return r;
+   }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SingularValueDecomposition.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SingularValueDecomposition.java0
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SingularValueDecomposition.java0	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SingularValueDecomposition.java0	(revision 3653)
@@ -0,0 +1,547 @@
+package JamaPlus;
+import JamaPlus.util.*;
+
+   /** Singular Value Decomposition.
+   <P>
+   For an m-by-n matrix A with m >= n, the singular value decomposition is
+   an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and
+   an n-by-n orthogonal matrix V so that A = U*S*V'.
+   <P>
+   The singular values, sigma[k] = S[k][k], are ordered so that
+   sigma[0] >= sigma[1] >= ... >= sigma[n-1].
+   <P>
+   The singular value decompostion always exists, so the constructor will
+   never fail.  The matrix condition number and the effective numerical
+   rank can be computed from this decomposition.
+   */
+
+public class SingularValueDecomposition implements java.io.Serializable {
+
+/* ------------------------
+   Class variables
+ * ------------------------ */
+
+   /** Arrays for internal storage of U and V.
+   @serial internal storage of U.
+   @serial internal storage of V.
+   */
+   private double[][] U, V;
+
+   /** Array for internal storage of singular values.
+   @serial internal storage of singular values.
+   */
+   private double[] s;
+
+   /** Row and column dimensions.
+   @serial row dimension.
+   @serial column dimension.
+   */
+   private int m, n;
+
+/* ------------------------
+   Constructor
+ * ------------------------ */
+
+   /** Construct the singular value decomposition
+   @param A    Rectangular matrix
+   @return     Structure to access U, S and V.
+   */
+
+   public SingularValueDecomposition (Matrix Arg) {
+
+      // Derived from LINPACK code.
+      // Initialize.
+      double[][] A = Arg.getArrayCopy();
+      m = Arg.getRowDimension();
+      n = Arg.getColumnDimension();
+
+      /* Apparently the failing cases are only a proper subset of (m<n), 
+	 so let's not throw error.  Correct fix to come later?
+      if (m<n) {
+	  throw new IllegalArgumentException("Jama SVD only works for m >= n"); }
+      */
+      int nu = Math.min(m,n);
+      s = new double [Math.min(m+1,n)];
+      U = new double [m][nu];
+      V = new double [n][n];
+      double[] e = new double [n];
+      double[] work = new double [m];
+      boolean wantu = true;
+      boolean wantv = true;
+
+      // Reduce A to bidiagonal form, storing the diagonal elements
+      // in s and the super-diagonal elements in e.
+
+      int nct = Math.min(m-1,n);
+      int nrt = Math.max(0,Math.min(n-2,m));
+      for (int k = 0; k < Math.max(nct,nrt); k++) {
+         if (k < nct) {
+
+            // Compute the transformation for the k-th column and
+            // place the k-th diagonal in s[k].
+            // Compute 2-norm of k-th column without under/overflow.
+            s[k] = 0;
+            for (int i = k; i < m; i++) {
+               s[k] = Math.hypot(s[k],A[i][k]);
+            }
+            if (s[k] != 0.0) {
+               if (A[k][k] < 0.0) {
+                  s[k] = -s[k];
+               }
+               for (int i = k; i < m; i++) {
+                  A[i][k] /= s[k];
+               }
+               A[k][k] += 1.0;
+            }
+            s[k] = -s[k];
+         }
+         for (int j = k+1; j < n; j++) {
+            if ((k < nct) & (s[k] != 0.0))  {
+
+            // Apply the transformation.
+
+               double t = 0;
+               for (int i = k; i < m; i++) {
+                  t += A[i][k]*A[i][j];
+               }
+               t = -t/A[k][k];
+               for (int i = k; i < m; i++) {
+                  A[i][j] += t*A[i][k];
+               }
+            }
+
+            // Place the k-th row of A into e for the
+            // subsequent calculation of the row transformation.
+
+            e[j] = A[k][j];
+         }
+         if (wantu & (k < nct)) {
+
+            // Place the transformation in U for subsequent back
+            // multiplication.
+
+            for (int i = k; i < m; i++) {
+               U[i][k] = A[i][k];
+            }
+         }
+         if (k < nrt) {
+
+            // Compute the k-th row transformation and place the
+            // k-th super-diagonal in e[k].
+            // Compute 2-norm without under/overflow.
+            e[k] = 0;
+            for (int i = k+1; i < n; i++) {
+               e[k] = Math.hypot(e[k],e[i]);
+            }
+            if (e[k] != 0.0) {
+               if (e[k+1] < 0.0) {
+                  e[k] = -e[k];
+               }
+               for (int i = k+1; i < n; i++) {
+                  e[i] /= e[k];
+               }
+               e[k+1] += 1.0;
+            }
+            e[k] = -e[k];
+            if ((k+1 < m) & (e[k] != 0.0)) {
+
+            // Apply the transformation.
+
+               for (int i = k+1; i < m; i++) {
+                  work[i] = 0.0;
+               }
+               for (int j = k+1; j < n; j++) {
+                  for (int i = k+1; i < m; i++) {
+                     work[i] += e[j]*A[i][j];
+                  }
+               }
+               for (int j = k+1; j < n; j++) {
+                  double t = -e[j]/e[k+1];
+                  for (int i = k+1; i < m; i++) {
+                     A[i][j] += t*work[i];
+                  }
+               }
+            }
+            if (wantv) {
+
+            // Place the transformation in V for subsequent
+            // back multiplication.
+
+               for (int i = k+1; i < n; i++) {
+                  V[i][k] = e[i];
+               }
+            }
+         }
+      }
+
+      // Set up the final bidiagonal matrix or order p.
+
+      int p = Math.min(n,m+1);
+      if (nct < n) {
+         s[nct] = A[nct][nct];
+      }
+      if (m < p) {
+         s[p-1] = 0.0;
+      }
+      if (nrt+1 < p) {
+         e[nrt] = A[nrt][p-1];
+      }
+      e[p-1] = 0.0;
+
+      // If required, generate U.
+
+      if (wantu) {
+         for (int j = nct; j < nu; j++) {
+            for (int i = 0; i < m; i++) {
+               U[i][j] = 0.0;
+            }
+            U[j][j] = 1.0;
+         }
+         for (int k = nct-1; k >= 0; k--) {
+            if (s[k] != 0.0) {
+               for (int j = k+1; j < nu; j++) {
+                  double t = 0;
+                  for (int i = k; i < m; i++) {
+                     t += U[i][k]*U[i][j];
+                  }
+                  t = -t/U[k][k];
+                  for (int i = k; i < m; i++) {
+                     U[i][j] += t*U[i][k];
+                  }
+               }
+               for (int i = k; i < m; i++ ) {
+                  U[i][k] = -U[i][k];
+               }
+               U[k][k] = 1.0 + U[k][k];
+               for (int i = 0; i < k-1; i++) {
+                  U[i][k] = 0.0;
+               }
+            } else {
+               for (int i = 0; i < m; i++) {
+                  U[i][k] = 0.0;
+               }
+               U[k][k] = 1.0;
+            }
+         }
+      }
+
+      // If required, generate V.
+
+      if (wantv) {
+         for (int k = n-1; k >= 0; k--) {
+            if ((k < nrt) & (e[k] != 0.0)) {
+               for (int j = k+1; j < nu; j++) {
+                  double t = 0;
+                  for (int i = k+1; i < n; i++) {
+                     t += V[i][k]*V[i][j];
+                  }
+                  t = -t/V[k+1][k];
+                  for (int i = k+1; i < n; i++) {
+                     V[i][j] += t*V[i][k];
+                  }
+               }
+            }
+            for (int i = 0; i < n; i++) {
+               V[i][k] = 0.0;
+            }
+            V[k][k] = 1.0;
+         }
+      }
+
+      // Main iteration loop for the singular values.
+
+      int pp = p-1;
+      int iter = 0;
+      double eps = Math.pow(2.0,-52.0);
+      double tiny = Math.pow(2.0,-966.0);
+      while (p > 0) {
+         int k,kase;
+
+         // Here is where a test for too many iterations would go.
+
+         // This section of the program inspects for
+         // negligible elements in the s and e arrays.  On
+         // completion the variables kase and k are set as follows.
+
+         // kase = 1     if s(p) and e[k-1] are negligible and k<p
+         // kase = 2     if s(k) is negligible and k<p
+         // kase = 3     if e[k-1] is negligible, k<p, and
+         //              s(k), ..., s(p) are not negligible (qr step).
+         // kase = 4     if e(p-1) is negligible (convergence).
+
+         for (k = p-2; k >= -1; k--) {
+            if (k == -1) {
+               break;
+            }
+            if (Math.abs(e[k]) <=
+                  tiny + eps*(Math.abs(s[k]) + Math.abs(s[k+1]))) {
+               e[k] = 0.0;
+               break;
+            }
+         }
+         if (k == p-2) {
+            kase = 4;
+         } else {
+            int ks;
+            for (ks = p-1; ks >= k; ks--) {
+               if (ks == k) {
+                  break;
+               }
+               double t = (ks != p ? Math.abs(e[ks]) : 0.) + 
+                          (ks != k+1 ? Math.abs(e[ks-1]) : 0.);
+               if (Math.abs(s[ks]) <= tiny + eps*t)  {
+                  s[ks] = 0.0;
+                  break;
+               }
+            }
+            if (ks == k) {
+               kase = 3;
+            } else if (ks == p-1) {
+               kase = 1;
+            } else {
+               kase = 2;
+               k = ks;
+            }
+         }
+         k++;
+
+         // Perform the task indicated by kase.
+
+         switch (kase) {
+
+            // Deflate negligible s(p).
+
+            case 1: {
+               double f = e[p-2];
+               e[p-2] = 0.0;
+               for (int j = p-2; j >= k; j--) {
+                  double t = Math.hypot(s[j],f);
+                  double cs = s[j]/t;
+                  double sn = f/t;
+                  s[j] = t;
+                  if (j != k) {
+                     f = -sn*e[j-1];
+                     e[j-1] = cs*e[j-1];
+                  }
+                  if (wantv) {
+                     for (int i = 0; i < n; i++) {
+                        t = cs*V[i][j] + sn*V[i][p-1];
+                        V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1];
+                        V[i][j] = t;
+                     }
+                  }
+               }
+            }
+            break;
+
+            // Split at negligible s(k).
+
+            case 2: {
+               double f = e[k-1];
+               e[k-1] = 0.0;
+               for (int j = k; j < p; j++) {
+                  double t = Math.hypot(s[j],f);
+                  double cs = s[j]/t;
+                  double sn = f/t;
+                  s[j] = t;
+                  f = -sn*e[j];
+                  e[j] = cs*e[j];
+                  if (wantu) {
+                     for (int i = 0; i < m; i++) {
+                        t = cs*U[i][j] + sn*U[i][k-1];
+                        U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1];
+                        U[i][j] = t;
+                     }
+                  }
+               }
+            }
+            break;
+
+            // Perform one qr step.
+
+            case 3: {
+
+               // Calculate the shift.
+   
+               double scale = Math.max(Math.max(Math.max(Math.max(
+                       Math.abs(s[p-1]),Math.abs(s[p-2])),Math.abs(e[p-2])), 
+                       Math.abs(s[k])),Math.abs(e[k]));
+               double sp = s[p-1]/scale;
+               double spm1 = s[p-2]/scale;
+               double epm1 = e[p-2]/scale;
+               double sk = s[k]/scale;
+               double ek = e[k]/scale;
+               double b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
+               double c = (sp*epm1)*(sp*epm1);
+               double shift = 0.0;
+               if ((b != 0.0) | (c != 0.0)) {
+                  shift = Math.sqrt(b*b + c);
+                  if (b < 0.0) {
+                     shift = -shift;
+                  }
+                  shift = c/(b + shift);
+               }
+               double f = (sk + sp)*(sk - sp) + shift;
+               double g = sk*ek;
+   
+               // Chase zeros.
+   
+               for (int j = k; j < p-1; j++) {
+                  double t = Math.hypot(f,g);
+                  double cs = f/t;
+                  double sn = g/t;
+                  if (j != k) {
+                     e[j-1] = t;
+                  }
+                  f = cs*s[j] + sn*e[j];
+                  e[j] = cs*e[j] - sn*s[j];
+                  g = sn*s[j+1];
+                  s[j+1] = cs*s[j+1];
+                  if (wantv) {
+                     for (int i = 0; i < n; i++) {
+                        t = cs*V[i][j] + sn*V[i][j+1];
+                        V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1];
+                        V[i][j] = t;
+                     }
+                  }
+                  t = Math.hypot(f,g);
+                  cs = f/t;
+                  sn = g/t;
+                  s[j] = t;
+                  f = cs*e[j] + sn*s[j+1];
+                  s[j+1] = -sn*e[j] + cs*s[j+1];
+                  g = sn*e[j+1];
+                  e[j+1] = cs*e[j+1];
+                  if (wantu && (j < m-1)) {
+                     for (int i = 0; i < m; i++) {
+                        t = cs*U[i][j] + sn*U[i][j+1];
+                        U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1];
+                        U[i][j] = t;
+                     }
+                  }
+               }
+               e[p-2] = f;
+               iter = iter + 1;
+            }
+            break;
+
+            // Convergence.
+
+            case 4: {
+
+               // Make the singular values positive.
+   
+               if (s[k] <= 0.0) {
+                  s[k] = (s[k] < 0.0 ? -s[k] : 0.0);
+                  if (wantv) {
+                     for (int i = 0; i <= pp; i++) {
+                        V[i][k] = -V[i][k];
+                     }
+                  }
+               }
+   
+               // Order the singular values.
+   
+               while (k < pp) {
+                  if (s[k] >= s[k+1]) {
+                     break;
+                  }
+                  double t = s[k];
+                  s[k] = s[k+1];
+                  s[k+1] = t;
+                  if (wantv && (k < n-1)) {
+                     for (int i = 0; i < n; i++) {
+                        t = V[i][k+1]; V[i][k+1] = V[i][k]; V[i][k] = t;
+                     }
+                  }
+                  if (wantu && (k < m-1)) {
+                     for (int i = 0; i < m; i++) {
+                        t = U[i][k+1]; U[i][k+1] = U[i][k]; U[i][k] = t;
+                     }
+                  }
+                  k++;
+               }
+               iter = 0;
+               p--;
+            }
+            break;
+         }
+      }
+   }
+
+/* ------------------------
+   Public Methods
+ * ------------------------ */
+
+   /** Return the left singular vectors
+   @return     U
+   */
+
+   public Matrix getU () {
+      return new Matrix(U,m,Math.min(m+1,n));
+   }
+
+   /** Return the right singular vectors
+   @return     V
+   */
+
+   public Matrix getV () {
+      return new Matrix(V,n,n);
+   }
+
+   /** Return the one-dimensional array of singular values
+   @return     diagonal of S.
+   */
+
+   public double[] getSingularValues () {
+      return s;
+   }
+
+   /** Return the diagonal matrix of singular values
+   @return     S
+   */
+
+   public Matrix getS () {
+      Matrix X = new Matrix(n,n);
+      double[][] S = X.getArray();
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            S[i][j] = 0.0;
+         }
+         S[i][i] = this.s[i];
+      }
+      return X;
+   }
+
+   /** Two norm
+   @return     max(S)
+   */
+
+   public double norm2 () {
+      return s[0];
+   }
+
+   /** Two norm condition number
+   @return     max(S)/min(S)
+   */
+
+   public double cond () {
+      return s[0]/s[Math.min(m,n)-1];
+   }
+
+   /** Effective numerical matrix rank
+   @return     Number of nonnegligible singular values.
+   */
+
+   public int rank () {
+      double eps = Math.pow(2.0,-52.0);
+      double tol = Math.max(m,n)*s[0]*eps;
+      int r = 0;
+      for (int i = 0; i < s.length; i++) {
+         if (s[i] > tol) {
+            r++;
+         }
+      }
+      return r;
+   }
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/QRDecomposition.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/QRDecomposition.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/QRDecomposition.java	(revision 3653)
@@ -0,0 +1,218 @@
+package JamaPlus;
+import JamaPlus.util.*;
+
+/** QR Decomposition.
+<P>
+   For an m-by-n matrix A with m >= n, the QR decomposition is an m-by-n
+   orthogonal matrix Q and an n-by-n upper triangular matrix R so that
+   A = Q*R.
+<P>
+   The QR decompostion always exists, even if the matrix does not have
+   full rank, so the constructor will never fail.  The primary use of the
+   QR decomposition is in the least squares solution of nonsquare systems
+   of simultaneous linear equations.  This will fail if isFullRank()
+   returns false.
+*/
+
+public class QRDecomposition implements java.io.Serializable {
+
+/* ------------------------
+   Class variables
+ * ------------------------ */
+
+   /** Array for internal storage of decomposition.
+   @serial internal array storage.
+   */
+   private double[][] QR;
+
+   /** Row and column dimensions.
+   @serial column dimension.
+   @serial row dimension.
+   */
+   private int m, n;
+
+   /** Array for internal storage of diagonal of R.
+   @serial diagonal of R.
+   */
+   private double[] Rdiag;
+
+/* ------------------------
+   Constructor
+ * ------------------------ */
+
+   /** QR Decomposition, computed by Householder reflections.
+   @param A    Rectangular matrix
+   @return     Structure to access R and the Householder vectors and compute Q.
+   */
+
+   public QRDecomposition (Matrix A) {
+      // Initialize.
+      QR = A.getArrayCopy();
+      m = A.getRowDimension();
+      n = A.getColumnDimension();
+      Rdiag = new double[n];
+
+      // Main loop.
+      for (int k = 0; k < n; k++) {
+         // Compute 2-norm of k-th column without under/overflow.
+         double nrm = 0;
+         for (int i = k; i < m; i++) {
+            nrm = Math.hypot(nrm,QR[i][k]);
+         }
+
+         if (nrm != 0.0) {
+            // Form k-th Householder vector.
+            if (QR[k][k] < 0) {
+               nrm = -nrm;
+            }
+            for (int i = k; i < m; i++) {
+               QR[i][k] /= nrm;
+            }
+            QR[k][k] += 1.0;
+
+            // Apply transformation to remaining columns.
+            for (int j = k+1; j < n; j++) {
+               double s = 0.0; 
+               for (int i = k; i < m; i++) {
+                  s += QR[i][k]*QR[i][j];
+               }
+               s = -s/QR[k][k];
+               for (int i = k; i < m; i++) {
+                  QR[i][j] += s*QR[i][k];
+               }
+            }
+         }
+         Rdiag[k] = -nrm;
+      }
+   }
+
+/* ------------------------
+   Public Methods
+ * ------------------------ */
+
+   /** Is the matrix full rank?
+   @return     true if R, and hence A, has full rank.
+   */
+
+   public boolean isFullRank () {
+      for (int j = 0; j < n; j++) {
+         if (Rdiag[j] == 0)
+            return false;
+      }
+      return true;
+   }
+
+   /** Return the Householder vectors
+   @return     Lower trapezoidal matrix whose columns define the reflections
+   */
+
+   public Matrix getH () {
+      Matrix X = new Matrix(m,n);
+      double[][] H = X.getArray();
+      for (int i = 0; i < m; i++) {
+         for (int j = 0; j < n; j++) {
+            if (i >= j) {
+               H[i][j] = QR[i][j];
+            } else {
+               H[i][j] = 0.0;
+            }
+         }
+      }
+      return X;
+   }
+
+   /** Return the upper triangular factor
+   @return     R
+   */
+
+   public Matrix getR () {
+      Matrix X = new Matrix(n,n);
+      double[][] R = X.getArray();
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            if (i < j) {
+               R[i][j] = QR[i][j];
+            } else if (i == j) {
+               R[i][j] = Rdiag[i];
+            } else {
+               R[i][j] = 0.0;
+            }
+         }
+      }
+      return X;
+   }
+
+   /** Generate and return the (economy-sized) orthogonal factor
+   @return     Q
+   */
+
+   public Matrix getQ () {
+      Matrix X = new Matrix(m,n);
+      double[][] Q = X.getArray();
+      for (int k = n-1; k >= 0; k--) {
+         for (int i = 0; i < m; i++) {
+            Q[i][k] = 0.0;
+         }
+         Q[k][k] = 1.0;
+         for (int j = k; j < n; j++) {
+            if (QR[k][k] != 0) {
+               double s = 0.0;
+               for (int i = k; i < m; i++) {
+                  s += QR[i][k]*Q[i][j];
+               }
+               s = -s/QR[k][k];
+               for (int i = k; i < m; i++) {
+                  Q[i][j] += s*QR[i][k];
+               }
+            }
+         }
+      }
+      return X;
+   }
+
+   /** Least squares solution of A*X = B
+   @param B    A Matrix with as many rows as A and any number of columns.
+   @return     X that minimizes the two norm of Q*R*X-B.
+   @exception  IllegalArgumentException  Matrix row dimensions must agree.
+   @exception  RuntimeException  Matrix is rank deficient.
+   */
+
+   public Matrix solve (Matrix B) {
+      if (B.getRowDimension() != m) {
+         throw new IllegalArgumentException("Matrix row dimensions must agree.");
+      }
+      if (!this.isFullRank()) {
+         throw new RuntimeException("Matrix is rank deficient.");
+      }
+      
+      // Copy right hand side
+      int nx = B.getColumnDimension();
+      double[][] X = B.getArrayCopy();
+
+      // Compute Y = transpose(Q)*B
+      for (int k = 0; k < n; k++) {
+         for (int j = 0; j < nx; j++) {
+            double s = 0.0; 
+            for (int i = k; i < m; i++) {
+               s += QR[i][k]*X[i][j];
+            }
+            s = -s/QR[k][k];
+            for (int i = k; i < m; i++) {
+               X[i][j] += s*QR[i][k];
+            }
+         }
+      }
+      // Solve R*X = Y;
+      for (int k = n-1; k >= 0; k--) {
+         for (int j = 0; j < nx; j++) {
+            X[k][j] /= Rdiag[k];
+         }
+         for (int i = 0; i < k; i++) {
+            for (int j = 0; j < nx; j++) {
+               X[i][j] -= X[k][j]*QR[i][k];
+            }
+         }
+      }
+      return (new Matrix(X,n,nx).getMatrix(0,n-1,0,nx-1));
+   }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/QRDecomposition.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/EigenvalueDecomposition.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/EigenvalueDecomposition.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/EigenvalueDecomposition.java	(revision 3653)
@@ -0,0 +1,955 @@
+package JamaPlus;
+import JamaPlus.util.*;
+
+/** Eigenvalues and eigenvectors of a real matrix. 
+<P>
+    If A is symmetric, then A = V*D*V' where the eigenvalue matrix D is
+    diagonal and the eigenvector matrix V is orthogonal.
+    I.e. A = V.times(D.times(V.transpose())) and 
+    V.times(V.transpose()) equals the identity matrix.
+<P>
+    If A is not symmetric, then the eigenvalue matrix D is block diagonal
+    with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,
+    lambda + i*mu, in 2-by-2 blocks, [lambda, mu; -mu, lambda].  The
+    columns of V represent the eigenvectors in the sense that A*V = V*D,
+    i.e. A.times(V) equals V.times(D).  The matrix V may be badly
+    conditioned, or even singular, so the validity of the equation
+    A = V*D*inverse(V) depends upon V.cond().
+**/
+
+public class EigenvalueDecomposition implements java.io.Serializable {
+
+/* ------------------------
+   Class variables
+ * ------------------------ */
+
+   /** Row and column dimension (square matrix).
+   @serial matrix dimension.
+   */
+   private int n;
+
+   /** Symmetry flag.
+   @serial internal symmetry flag.
+   */
+   private boolean issymmetric;
+
+   /** Arrays for internal storage of eigenvalues.
+   @serial internal storage of eigenvalues.
+   */
+   private double[] d, e;
+
+   /** Array for internal storage of eigenvectors.
+   @serial internal storage of eigenvectors.
+   */
+   private double[][] V;
+
+   /** Array for internal storage of nonsymmetric Hessenberg form.
+   @serial internal storage of nonsymmetric Hessenberg form.
+   */
+   private double[][] H;
+
+   /** Working storage for nonsymmetric algorithm.
+   @serial working storage for nonsymmetric algorithm.
+   */
+   private double[] ort;
+
+/* ------------------------
+   Private Methods
+ * ------------------------ */
+
+   // Symmetric Householder reduction to tridiagonal form.
+
+   private void tred2 () {
+
+   //  This is derived from the Algol procedures tred2 by
+   //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
+   //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
+   //  Fortran subroutine in EISPACK.
+
+      for (int j = 0; j < n; j++) {
+         d[j] = V[n-1][j];
+      }
+
+      // Householder reduction to tridiagonal form.
+   
+      for (int i = n-1; i > 0; i--) {
+   
+         // Scale to avoid under/overflow.
+   
+         double scale = 0.0;
+         double h = 0.0;
+         for (int k = 0; k < i; k++) {
+            scale = scale + Math.abs(d[k]);
+         }
+         if (scale == 0.0) {
+            e[i] = d[i-1];
+            for (int j = 0; j < i; j++) {
+               d[j] = V[i-1][j];
+               V[i][j] = 0.0;
+               V[j][i] = 0.0;
+            }
+         } else {
+   
+            // Generate Householder vector.
+   
+            for (int k = 0; k < i; k++) {
+               d[k] /= scale;
+               h += d[k] * d[k];
+            }
+            double f = d[i-1];
+            double g = Math.sqrt(h);
+            if (f > 0) {
+               g = -g;
+            }
+            e[i] = scale * g;
+            h = h - f * g;
+            d[i-1] = f - g;
+            for (int j = 0; j < i; j++) {
+               e[j] = 0.0;
+            }
+   
+            // Apply similarity transformation to remaining columns.
+   
+            for (int j = 0; j < i; j++) {
+               f = d[j];
+               V[j][i] = f;
+               g = e[j] + V[j][j] * f;
+               for (int k = j+1; k <= i-1; k++) {
+                  g += V[k][j] * d[k];
+                  e[k] += V[k][j] * f;
+               }
+               e[j] = g;
+            }
+            f = 0.0;
+            for (int j = 0; j < i; j++) {
+               e[j] /= h;
+               f += e[j] * d[j];
+            }
+            double hh = f / (h + h);
+            for (int j = 0; j < i; j++) {
+               e[j] -= hh * d[j];
+            }
+            for (int j = 0; j < i; j++) {
+               f = d[j];
+               g = e[j];
+               for (int k = j; k <= i-1; k++) {
+                  V[k][j] -= (f * e[k] + g * d[k]);
+               }
+               d[j] = V[i-1][j];
+               V[i][j] = 0.0;
+            }
+         }
+         d[i] = h;
+      }
+   
+      // Accumulate transformations.
+   
+      for (int i = 0; i < n-1; i++) {
+         V[n-1][i] = V[i][i];
+         V[i][i] = 1.0;
+         double h = d[i+1];
+         if (h != 0.0) {
+            for (int k = 0; k <= i; k++) {
+               d[k] = V[k][i+1] / h;
+            }
+            for (int j = 0; j <= i; j++) {
+               double g = 0.0;
+               for (int k = 0; k <= i; k++) {
+                  g += V[k][i+1] * V[k][j];
+               }
+               for (int k = 0; k <= i; k++) {
+                  V[k][j] -= g * d[k];
+               }
+            }
+         }
+         for (int k = 0; k <= i; k++) {
+            V[k][i+1] = 0.0;
+         }
+      }
+      for (int j = 0; j < n; j++) {
+         d[j] = V[n-1][j];
+         V[n-1][j] = 0.0;
+      }
+      V[n-1][n-1] = 1.0;
+      e[0] = 0.0;
+   } 
+
+   // Symmetric tridiagonal QL algorithm.
+   
+   private void tql2 () {
+
+   //  This is derived from the Algol procedures tql2, by
+   //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
+   //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
+   //  Fortran subroutine in EISPACK.
+   
+      for (int i = 1; i < n; i++) {
+         e[i-1] = e[i];
+      }
+      e[n-1] = 0.0;
+   
+      double f = 0.0;
+      double tst1 = 0.0;
+      double eps = Math.pow(2.0,-52.0);
+      for (int l = 0; l < n; l++) {
+
+         // Find small subdiagonal element
+   
+         tst1 = Math.max(tst1,Math.abs(d[l]) + Math.abs(e[l]));
+         int m = l;
+         while (m < n) {
+            if (Math.abs(e[m]) <= eps*tst1) {
+               break;
+            }
+            m++;
+         }
+   
+         // If m == l, d[l] is an eigenvalue,
+         // otherwise, iterate.
+   
+         if (m > l) {
+            int iter = 0;
+            do {
+               iter = iter + 1;  // (Could check iteration count here.)
+   
+               // Compute implicit shift
+   
+               double g = d[l];
+               double p = (d[l+1] - g) / (2.0 * e[l]);
+               double r = Math.hypot(p,1.0);
+               if (p < 0) {
+                  r = -r;
+               }
+               d[l] = e[l] / (p + r);
+               d[l+1] = e[l] * (p + r);
+               double dl1 = d[l+1];
+               double h = g - d[l];
+               for (int i = l+2; i < n; i++) {
+                  d[i] -= h;
+               }
+               f = f + h;
+   
+               // Implicit QL transformation.
+   
+               p = d[m];
+               double c = 1.0;
+               double c2 = c;
+               double c3 = c;
+               double el1 = e[l+1];
+               double s = 0.0;
+               double s2 = 0.0;
+               for (int i = m-1; i >= l; i--) {
+                  c3 = c2;
+                  c2 = c;
+                  s2 = s;
+                  g = c * e[i];
+                  h = c * p;
+                  r = Math.hypot(p,e[i]);
+                  e[i+1] = s * r;
+                  s = e[i] / r;
+                  c = p / r;
+                  p = c * d[i] - s * g;
+                  d[i+1] = h + s * (c * g + s * d[i]);
+   
+                  // Accumulate transformation.
+   
+                  for (int k = 0; k < n; k++) {
+                     h = V[k][i+1];
+                     V[k][i+1] = s * V[k][i] + c * h;
+                     V[k][i] = c * V[k][i] - s * h;
+                  }
+               }
+               p = -s * s2 * c3 * el1 * e[l] / dl1;
+               e[l] = s * p;
+               d[l] = c * p;
+   
+               // Check for convergence.
+   
+            } while (Math.abs(e[l]) > eps*tst1);
+         }
+         d[l] = d[l] + f;
+         e[l] = 0.0;
+      }
+     
+      // Sort eigenvalues and corresponding vectors.
+   
+      for (int i = 0; i < n-1; i++) {
+         int k = i;
+         double p = d[i];
+         for (int j = i+1; j < n; j++) {
+            if (d[j] < p) {
+               k = j;
+               p = d[j];
+            }
+         }
+         if (k != i) {
+            d[k] = d[i];
+            d[i] = p;
+            for (int j = 0; j < n; j++) {
+               p = V[j][i];
+               V[j][i] = V[j][k];
+               V[j][k] = p;
+            }
+         }
+      }
+   }
+
+   // Nonsymmetric reduction to Hessenberg form.
+
+   private void orthes () {
+   
+      //  This is derived from the Algol procedures orthes and ortran,
+      //  by Martin and Wilkinson, Handbook for Auto. Comp.,
+      //  Vol.ii-Linear Algebra, and the corresponding
+      //  Fortran subroutines in EISPACK.
+   
+      int low = 0;
+      int high = n-1;
+   
+      for (int m = low+1; m <= high-1; m++) {
+   
+         // Scale column.
+   
+         double scale = 0.0;
+         for (int i = m; i <= high; i++) {
+            scale = scale + Math.abs(H[i][m-1]);
+         }
+         if (scale != 0.0) {
+   
+            // Compute Householder transformation.
+   
+            double h = 0.0;
+            for (int i = high; i >= m; i--) {
+               ort[i] = H[i][m-1]/scale;
+               h += ort[i] * ort[i];
+            }
+            double g = Math.sqrt(h);
+            if (ort[m] > 0) {
+               g = -g;
+            }
+            h = h - ort[m] * g;
+            ort[m] = ort[m] - g;
+   
+            // Apply Householder similarity transformation
+            // H = (I-u*u'/h)*H*(I-u*u')/h)
+   
+            for (int j = m; j < n; j++) {
+               double f = 0.0;
+               for (int i = high; i >= m; i--) {
+                  f += ort[i]*H[i][j];
+               }
+               f = f/h;
+               for (int i = m; i <= high; i++) {
+                  H[i][j] -= f*ort[i];
+               }
+           }
+   
+           for (int i = 0; i <= high; i++) {
+               double f = 0.0;
+               for (int j = high; j >= m; j--) {
+                  f += ort[j]*H[i][j];
+               }
+               f = f/h;
+               for (int j = m; j <= high; j++) {
+                  H[i][j] -= f*ort[j];
+               }
+            }
+            ort[m] = scale*ort[m];
+            H[m][m-1] = scale*g;
+         }
+      }
+   
+      // Accumulate transformations (Algol's ortran).
+
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            V[i][j] = (i == j ? 1.0 : 0.0);
+         }
+      }
+
+      for (int m = high-1; m >= low+1; m--) {
+         if (H[m][m-1] != 0.0) {
+            for (int i = m+1; i <= high; i++) {
+               ort[i] = H[i][m-1];
+            }
+            for (int j = m; j <= high; j++) {
+               double g = 0.0;
+               for (int i = m; i <= high; i++) {
+                  g += ort[i] * V[i][j];
+               }
+               // Double division avoids possible underflow
+               g = (g / ort[m]) / H[m][m-1];
+               for (int i = m; i <= high; i++) {
+                  V[i][j] += g * ort[i];
+               }
+            }
+         }
+      }
+   }
+
+
+   // Complex scalar division.
+
+   private transient double cdivr, cdivi;
+   private void cdiv(double xr, double xi, double yr, double yi) {
+      double r,d;
+      if (Math.abs(yr) > Math.abs(yi)) {
+         r = yi/yr;
+         d = yr + r*yi;
+         cdivr = (xr + r*xi)/d;
+         cdivi = (xi - r*xr)/d;
+      } else {
+         r = yr/yi;
+         d = yi + r*yr;
+         cdivr = (r*xr + xi)/d;
+         cdivi = (r*xi - xr)/d;
+      }
+   }
+
+
+   // Nonsymmetric reduction from Hessenberg to real Schur form.
+
+   private void hqr2 () {
+   
+      //  This is derived from the Algol procedure hqr2,
+      //  by Martin and Wilkinson, Handbook for Auto. Comp.,
+      //  Vol.ii-Linear Algebra, and the corresponding
+      //  Fortran subroutine in EISPACK.
+   
+      // Initialize
+   
+      int nn = this.n;
+      int n = nn-1;
+      int low = 0;
+      int high = nn-1;
+      double eps = Math.pow(2.0,-52.0);
+      double exshift = 0.0;
+      double p=0,q=0,r=0,s=0,z=0,t,w,x,y;
+   
+      // Store roots isolated by balanc and compute matrix norm
+   
+      double norm = 0.0;
+      for (int i = 0; i < nn; i++) {
+         if (i < low | i > high) {
+            d[i] = H[i][i];
+            e[i] = 0.0;
+         }
+         for (int j = Math.max(i-1,0); j < nn; j++) {
+            norm = norm + Math.abs(H[i][j]);
+         }
+      }
+   
+      // Outer loop over eigenvalue index
+   
+      int iter = 0;
+      while (n >= low) {
+   
+         // Look for single small sub-diagonal element
+   
+         int l = n;
+         while (l > low) {
+            s = Math.abs(H[l-1][l-1]) + Math.abs(H[l][l]);
+            if (s == 0.0) {
+               s = norm;
+            }
+            if (Math.abs(H[l][l-1]) < eps * s) {
+               break;
+            }
+            l--;
+         }
+       
+         // Check for convergence
+         // One root found
+   
+         if (l == n) {
+            H[n][n] = H[n][n] + exshift;
+            d[n] = H[n][n];
+            e[n] = 0.0;
+            n--;
+            iter = 0;
+   
+         // Two roots found
+   
+         } else if (l == n-1) {
+            w = H[n][n-1] * H[n-1][n];
+            p = (H[n-1][n-1] - H[n][n]) / 2.0;
+            q = p * p + w;
+            z = Math.sqrt(Math.abs(q));
+            H[n][n] = H[n][n] + exshift;
+            H[n-1][n-1] = H[n-1][n-1] + exshift;
+            x = H[n][n];
+   
+            // Real pair
+   
+            if (q >= 0) {
+               if (p >= 0) {
+                  z = p + z;
+               } else {
+                  z = p - z;
+               }
+               d[n-1] = x + z;
+               d[n] = d[n-1];
+               if (z != 0.0) {
+                  d[n] = x - w / z;
+               }
+               e[n-1] = 0.0;
+               e[n] = 0.0;
+               x = H[n][n-1];
+               s = Math.abs(x) + Math.abs(z);
+               p = x / s;
+               q = z / s;
+               r = Math.sqrt(p * p+q * q);
+               p = p / r;
+               q = q / r;
+   
+               // Row modification
+   
+               for (int j = n-1; j < nn; j++) {
+                  z = H[n-1][j];
+                  H[n-1][j] = q * z + p * H[n][j];
+                  H[n][j] = q * H[n][j] - p * z;
+               }
+   
+               // Column modification
+   
+               for (int i = 0; i <= n; i++) {
+                  z = H[i][n-1];
+                  H[i][n-1] = q * z + p * H[i][n];
+                  H[i][n] = q * H[i][n] - p * z;
+               }
+   
+               // Accumulate transformations
+   
+               for (int i = low; i <= high; i++) {
+                  z = V[i][n-1];
+                  V[i][n-1] = q * z + p * V[i][n];
+                  V[i][n] = q * V[i][n] - p * z;
+               }
+   
+            // Complex pair
+   
+            } else {
+               d[n-1] = x + p;
+               d[n] = x + p;
+               e[n-1] = z;
+               e[n] = -z;
+            }
+            n = n - 2;
+            iter = 0;
+   
+         // No convergence yet
+   
+         } else {
+   
+            // Form shift
+   
+            x = H[n][n];
+            y = 0.0;
+            w = 0.0;
+            if (l < n) {
+               y = H[n-1][n-1];
+               w = H[n][n-1] * H[n-1][n];
+            }
+   
+            // Wilkinson's original ad hoc shift
+   
+            if (iter == 10) {
+               exshift += x;
+               for (int i = low; i <= n; i++) {
+                  H[i][i] -= x;
+               }
+               s = Math.abs(H[n][n-1]) + Math.abs(H[n-1][n-2]);
+               x = y = 0.75 * s;
+               w = -0.4375 * s * s;
+            }
+
+            // MATLAB's new ad hoc shift
+
+            if (iter == 30) {
+                s = (y - x) / 2.0;
+                s = s * s + w;
+                if (s > 0) {
+                    s = Math.sqrt(s);
+                    if (y < x) {
+                       s = -s;
+                    }
+                    s = x - w / ((y - x) / 2.0 + s);
+                    for (int i = low; i <= n; i++) {
+                       H[i][i] -= s;
+                    }
+                    exshift += s;
+                    x = y = w = 0.964;
+                }
+            }
+   
+            iter = iter + 1;   // (Could check iteration count here.)
+   
+            // Look for two consecutive small sub-diagonal elements
+   
+            int m = n-2;
+            while (m >= l) {
+               z = H[m][m];
+               r = x - z;
+               s = y - z;
+               p = (r * s - w) / H[m+1][m] + H[m][m+1];
+               q = H[m+1][m+1] - z - r - s;
+               r = H[m+2][m+1];
+               s = Math.abs(p) + Math.abs(q) + Math.abs(r);
+               p = p / s;
+               q = q / s;
+               r = r / s;
+               if (m == l) {
+                  break;
+               }
+               if (Math.abs(H[m][m-1]) * (Math.abs(q) + Math.abs(r)) <
+                  eps * (Math.abs(p) * (Math.abs(H[m-1][m-1]) + Math.abs(z) +
+                  Math.abs(H[m+1][m+1])))) {
+                     break;
+               }
+               m--;
+            }
+   
+            for (int i = m+2; i <= n; i++) {
+               H[i][i-2] = 0.0;
+               if (i > m+2) {
+                  H[i][i-3] = 0.0;
+               }
+            }
+   
+            // Double QR step involving rows l:n and columns m:n
+   
+            for (int k = m; k <= n-1; k++) {
+               boolean notlast = (k != n-1);
+               if (k != m) {
+                  p = H[k][k-1];
+                  q = H[k+1][k-1];
+                  r = (notlast ? H[k+2][k-1] : 0.0);
+                  x = Math.abs(p) + Math.abs(q) + Math.abs(r);
+                  if (x != 0.0) {
+                     p = p / x;
+                     q = q / x;
+                     r = r / x;
+                  }
+               }
+               if (x == 0.0) {
+                  break;
+               }
+               s = Math.sqrt(p * p + q * q + r * r);
+               if (p < 0) {
+                  s = -s;
+               }
+               if (s != 0) {
+                  if (k != m) {
+                     H[k][k-1] = -s * x;
+                  } else if (l != m) {
+                     H[k][k-1] = -H[k][k-1];
+                  }
+                  p = p + s;
+                  x = p / s;
+                  y = q / s;
+                  z = r / s;
+                  q = q / p;
+                  r = r / p;
+   
+                  // Row modification
+   
+                  for (int j = k; j < nn; j++) {
+                     p = H[k][j] + q * H[k+1][j];
+                     if (notlast) {
+                        p = p + r * H[k+2][j];
+                        H[k+2][j] = H[k+2][j] - p * z;
+                     }
+                     H[k][j] = H[k][j] - p * x;
+                     H[k+1][j] = H[k+1][j] - p * y;
+                  }
+   
+                  // Column modification
+   
+                  for (int i = 0; i <= Math.min(n,k+3); i++) {
+                     p = x * H[i][k] + y * H[i][k+1];
+                     if (notlast) {
+                        p = p + z * H[i][k+2];
+                        H[i][k+2] = H[i][k+2] - p * r;
+                     }
+                     H[i][k] = H[i][k] - p;
+                     H[i][k+1] = H[i][k+1] - p * q;
+                  }
+   
+                  // Accumulate transformations
+   
+                  for (int i = low; i <= high; i++) {
+                     p = x * V[i][k] + y * V[i][k+1];
+                     if (notlast) {
+                        p = p + z * V[i][k+2];
+                        V[i][k+2] = V[i][k+2] - p * r;
+                     }
+                     V[i][k] = V[i][k] - p;
+                     V[i][k+1] = V[i][k+1] - p * q;
+                  }
+               }  // (s != 0)
+            }  // k loop
+         }  // check convergence
+      }  // while (n >= low)
+      
+      // Backsubstitute to find vectors of upper triangular form
+
+      if (norm == 0.0) {
+         return;
+      }
+   
+      for (n = nn-1; n >= 0; n--) {
+         p = d[n];
+         q = e[n];
+   
+         // Real vector
+   
+         if (q == 0) {
+            int l = n;
+            H[n][n] = 1.0;
+            for (int i = n-1; i >= 0; i--) {
+               w = H[i][i] - p;
+               r = 0.0;
+               for (int j = l; j <= n; j++) {
+                  r = r + H[i][j] * H[j][n];
+               }
+               if (e[i] < 0.0) {
+                  z = w;
+                  s = r;
+               } else {
+                  l = i;
+                  if (e[i] == 0.0) {
+                     if (w != 0.0) {
+                        H[i][n] = -r / w;
+                     } else {
+                        H[i][n] = -r / (eps * norm);
+                     }
+   
+                  // Solve real equations
+   
+                  } else {
+                     x = H[i][i+1];
+                     y = H[i+1][i];
+                     q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
+                     t = (x * s - z * r) / q;
+                     H[i][n] = t;
+                     if (Math.abs(x) > Math.abs(z)) {
+                        H[i+1][n] = (-r - w * t) / x;
+                     } else {
+                        H[i+1][n] = (-s - y * t) / z;
+                     }
+                  }
+   
+                  // Overflow control
+   
+                  t = Math.abs(H[i][n]);
+                  if ((eps * t) * t > 1) {
+                     for (int j = i; j <= n; j++) {
+                        H[j][n] = H[j][n] / t;
+                     }
+                  }
+               }
+            }
+   
+         // Complex vector
+   
+         } else if (q < 0) {
+            int l = n-1;
+
+            // Last vector component imaginary so matrix is triangular
+   
+            if (Math.abs(H[n][n-1]) > Math.abs(H[n-1][n])) {
+               H[n-1][n-1] = q / H[n][n-1];
+               H[n-1][n] = -(H[n][n] - p) / H[n][n-1];
+            } else {
+               cdiv(0.0,-H[n-1][n],H[n-1][n-1]-p,q);
+               H[n-1][n-1] = cdivr;
+               H[n-1][n] = cdivi;
+            }
+            H[n][n-1] = 0.0;
+            H[n][n] = 1.0;
+            for (int i = n-2; i >= 0; i--) {
+               double ra,sa,vr,vi;
+               ra = 0.0;
+               sa = 0.0;
+               for (int j = l; j <= n; j++) {
+                  ra = ra + H[i][j] * H[j][n-1];
+                  sa = sa + H[i][j] * H[j][n];
+               }
+               w = H[i][i] - p;
+   
+               if (e[i] < 0.0) {
+                  z = w;
+                  r = ra;
+                  s = sa;
+               } else {
+                  l = i;
+                  if (e[i] == 0) {
+                     cdiv(-ra,-sa,w,q);
+                     H[i][n-1] = cdivr;
+                     H[i][n] = cdivi;
+                  } else {
+   
+                     // Solve complex equations
+   
+                     x = H[i][i+1];
+                     y = H[i+1][i];
+                     vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
+                     vi = (d[i] - p) * 2.0 * q;
+                     if (vr == 0.0 & vi == 0.0) {
+                        vr = eps * norm * (Math.abs(w) + Math.abs(q) +
+                        Math.abs(x) + Math.abs(y) + Math.abs(z));
+                     }
+                     cdiv(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);
+                     H[i][n-1] = cdivr;
+                     H[i][n] = cdivi;
+                     if (Math.abs(x) > (Math.abs(z) + Math.abs(q))) {
+                        H[i+1][n-1] = (-ra - w * H[i][n-1] + q * H[i][n]) / x;
+                        H[i+1][n] = (-sa - w * H[i][n] - q * H[i][n-1]) / x;
+                     } else {
+                        cdiv(-r-y*H[i][n-1],-s-y*H[i][n],z,q);
+                        H[i+1][n-1] = cdivr;
+                        H[i+1][n] = cdivi;
+                     }
+                  }
+   
+                  // Overflow control
+
+                  t = Math.max(Math.abs(H[i][n-1]),Math.abs(H[i][n]));
+                  if ((eps * t) * t > 1) {
+                     for (int j = i; j <= n; j++) {
+                        H[j][n-1] = H[j][n-1] / t;
+                        H[j][n] = H[j][n] / t;
+                     }
+                  }
+               }
+            }
+         }
+      }
+   
+      // Vectors of isolated roots
+   
+      for (int i = 0; i < nn; i++) {
+         if (i < low | i > high) {
+            for (int j = i; j < nn; j++) {
+               V[i][j] = H[i][j];
+            }
+         }
+      }
+   
+      // Back transformation to get eigenvectors of original matrix
+   
+      for (int j = nn-1; j >= low; j--) {
+         for (int i = low; i <= high; i++) {
+            z = 0.0;
+            for (int k = low; k <= Math.min(j,high); k++) {
+               z = z + V[i][k] * H[k][j];
+            }
+            V[i][j] = z;
+         }
+      }
+   }
+
+
+/* ------------------------
+   Constructor
+ * ------------------------ */
+
+   /** Check for symmetry, then construct the eigenvalue decomposition
+   @param A    Square matrix
+   @return     Structure to access D and V.
+   */
+
+   public EigenvalueDecomposition (Matrix Arg) {
+      double[][] A = Arg.getArray();
+      n = Arg.getColumnDimension();
+      V = new double[n][n];
+      d = new double[n];
+      e = new double[n];
+
+      issymmetric = true;
+      for (int j = 0; (j < n) & issymmetric; j++) {
+         for (int i = 0; (i < n) & issymmetric; i++) {
+            issymmetric = (A[i][j] == A[j][i]);
+         }
+      }
+
+      if (issymmetric) {
+         for (int i = 0; i < n; i++) {
+            for (int j = 0; j < n; j++) {
+               V[i][j] = A[i][j];
+            }
+         }
+   
+         // Tridiagonalize.
+         tred2();
+   
+         // Diagonalize.
+         tql2();
+
+      } else {
+         H = new double[n][n];
+         ort = new double[n];
+         
+         for (int j = 0; j < n; j++) {
+            for (int i = 0; i < n; i++) {
+               H[i][j] = A[i][j];
+            }
+         }
+   
+         // Reduce to Hessenberg form.
+         orthes();
+   
+         // Reduce Hessenberg to real Schur form.
+         hqr2();
+      }
+   }
+
+/* ------------------------
+   Public Methods
+ * ------------------------ */
+
+   /** Return the eigenvector matrix
+   @return     V
+   */
+
+   public Matrix getV () {
+      return new Matrix(V,n,n);
+   }
+
+   /** Return the real parts of the eigenvalues
+   @return     real(diag(D))
+   */
+
+   public double[] getRealEigenvalues () {
+      return d;
+   }
+
+   /** Return the imaginary parts of the eigenvalues
+   @return     imag(diag(D))
+   */
+
+   public double[] getImagEigenvalues () {
+      return e;
+   }
+
+   /** Return the block diagonal eigenvalue matrix
+   @return     D
+   */
+
+   public Matrix getD () {
+      Matrix X = new Matrix(n,n);
+      double[][] D = X.getArray();
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            D[i][j] = 0.0;
+         }
+         D[i][i] = d[i];
+         if (e[i] > 0) {
+            D[i][i+1] = e[i];
+         } else if (e[i] < 0) {
+            D[i][i-1] = e[i];
+         }
+      }
+      return X;
+   }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/EigenvalueDecomposition.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SparseMatrix.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SparseMatrix.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SparseMatrix.java	(revision 3653)
@@ -0,0 +1,271 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package JamaPlus;
+
+import JamaPlus.SparseSVD.SparseSVDException;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public class SparseMatrix {
+  private int m, n, nnz;
+  private int[] colpts, rowinds;
+  private double[] vals;
+  private double[] tempRow;  // stockage temporaire pour certains calculs (opb)
+
+  public SparseMatrix(int m, int n) { // null matrix
+    this.m = m;
+    this.n = n;
+    nnz = 0;
+    colpts = new int[n+1];
+    rowinds = new int[0];
+    vals = new double[0];
+  }
+
+   private static class Triple implements Comparable<Triple> {
+    int row;
+    int col;
+    double val;
+
+    private Triple(int row, int col, double val) {
+      this.row = row;
+      this.col = col;
+      this.val = val;
+    }
+    private Triple(int row, int col) {
+      this.row = row;
+      this.col = col;
+    }
+    public int compareTo(Triple t) {
+      int res = col - t.col;
+      if(res==0) res = row - t.row;
+      return res;
+    }
+  }
+
+ public SparseMatrix(int m, int n, ArrayList<Integer> rows, ArrayList<Integer> cols,
+          ArrayList<Double> values) {
+    this.m = m;
+    this.n = n;
+    nnz = rows.size();
+    if (nnz!=cols.size()||nnz!=rows.size())
+      throw new ArrayIndexOutOfBoundsException(
+              "Size of lines, cols and values don't agree");
+    colpts = new int[n+1];
+    rowinds = new int[nnz];
+    vals = new double[nnz];
+    Triple[] triples = new Triple[nnz];
+    for(int i=0; i<nnz; i++) 
+     triples[i] = new Triple(rows.get(i), cols.get(i), values.get(i));    
+    Arrays.sort(triples);
+    colpts[0] = 0;
+    int c = 0;
+    for(int i=0; i<nnz; i++) {
+      if(i>0 && triples[i].row == triples[i-1].row && triples[i].col == triples[i-1].col) 
+        throw new ArrayIndexOutOfBoundsException(
+              "Two values with same row and column numbers");
+      while(c<triples[i].col) colpts[++c] = i;
+      rowinds[i] = triples[i].row;
+      vals[i] = triples[i].val;
+    }
+    while(c<n) colpts[++c] = nnz;
+  }
+
+public SparseMatrix(int m, int n, ArrayList<Integer> rows, ArrayList<Integer> cols,
+          double value) {
+    this.m = m;
+    this.n = n;
+    nnz = rows.size();
+    if (nnz!=cols.size()||nnz!=rows.size())
+      throw new ArrayIndexOutOfBoundsException(
+              "Size of lines, cols and values don't agree");
+    colpts = new int[n+1];
+    rowinds = new int[nnz];
+        vals = new double[nnz];
+    Triple[] triples = new Triple[nnz];
+    for(int i=0; i<nnz; i++) 
+     triples[i] = new Triple(rows.get(i), cols.get(i));    
+    Arrays.sort(triples);
+    colpts[0] = 0;
+    int c = 0;
+    for(int i=0; i<nnz; i++) {
+      if(i>0 && triples[i].row == triples[i-1].row && triples[i].col == triples[i-1].col) 
+        throw new ArrayIndexOutOfBoundsException(
+              "Two values with same row and column numbers");
+      while(c<triples[i].col) colpts[++c] = i;
+      rowinds[i] = triples[i].row;
+      vals[i] = value;
+    }
+    while(c<n) colpts[++c] = nnz;
+  }
+
+  private SparseMatrix(int m, int n, int nnz, int[] colpts, int[] rowinds, double[] vals) {
+    this.m = m;
+    this.n = n;
+    this.nnz = nnz;
+    this.colpts = colpts;
+    this.rowinds = rowinds;
+    this.vals = vals;
+  }
+
+  public SparseMatrix(Matrix mat) {  // convert a dense matrix
+    m = mat.getRowDimension();
+    n = mat.getColumnDimension();
+    long nbval = mat.getNumberNonZeroValues();
+    if (nbval>Integer.MAX_VALUE) throw new ArrayIndexOutOfBoundsException(
+              "Number of non-zero values exceeds 32 bits integer");
+    nnz = (int) nbval;
+    colpts = new int[n+1];
+    rowinds = new int[nnz];
+    vals = new double[nnz];
+    int nval = 0;
+    for (int j = 0; j<n; j++) {
+      colpts[j] = nval;
+      for (int i = 0; i<m; i++) if (mat.get(i, j)!=0) {
+          rowinds[nval] = i;
+          vals[nval++] = mat.get(i, j);
+        }
+    }
+    colpts[n] = nnz;
+  }
+
+  public SparseMatrix copy() {
+    int[] colpts1 = new int[n+1];
+    int[] rowinds1 = new int[nnz];
+    double[] vals1 = new double[nnz];
+    System.arraycopy(colpts, 0, colpts1, 0, n+1);
+    System.arraycopy(rowinds, 0, rowinds1, 0, nnz);
+    System.arraycopy(vals, 0, vals1, 0, nnz);
+    return new SparseMatrix(m, n, nnz, colpts1, rowinds1, vals1);
+  }
+
+  public int getRowDimension() {
+    return m;
+  }
+
+  public int getColumnDimension() {
+    return n;
+  }
+
+  public double get(int i, int j) {
+    try {
+      for (int nval = colpts[j]; nval<colpts[j+1]; nval++)
+        if (rowinds[nval]==i) return vals[nval];
+      return 0;
+    } catch (ArrayIndexOutOfBoundsException ex) {
+      throw new ArrayIndexOutOfBoundsException("Sparse matrix : "
+              +ex.getLocalizedMessage());
+    }
+  }
+
+  public SparseMatrix transpose() {
+    int[] colpts1 = new int[m+1];
+    int[] rowinds1 = new int[nnz];
+    double[] vals1 = new double[nnz];
+    for (int v = 0; v<nnz; v++) colpts1[rowinds[v]]++;  // nnz in each row
+    colpts1[m] = nnz-colpts1[m-1];
+    for (int r = m-1; r>0; r--)
+      colpts1[r] = colpts1[r+1]-colpts1[r-1]; // starting point of the previous row
+    colpts1[0] = 0;
+    int i = 0;
+    for (int c = 0; c<n; c++) while (i<colpts[c+1]) {
+        int j = colpts1[rowinds[i]+1]++;  // j : index of the value in the new vectors
+        rowinds1[j] = c;
+        vals1[j] = vals[i++];
+      }
+    return new SparseMatrix(n, m, nnz, colpts1, rowinds1, vals1);
+  }
+
+  public void nulColumnSuppression() {
+    ArrayList<Integer> colpts1 = new ArrayList<Integer>();
+    colpts1.add(0);
+    for (int i = 0; i<n; i++) if (colpts[i+1]>colpts[i])
+        colpts1.add(colpts[i+1]);
+    n = colpts1.size()-1;
+    colpts = new int[n+1];
+    for (int i = 0; i<=n; i++) colpts[i] = colpts1.get(i);
+  }
+
+  public double elementSum() {
+    double s = 0;
+    for (int i = 0; i<nnz; i++) s += vals[i];
+
+    return s;
+  }
+
+  public Matrix lineSum() {
+    double[] S = new double[m];
+    for (int i = 0; i<nnz; i++) S[rowinds[i]] += vals[i];
+
+    return new Matrix(S, m);
+  }
+
+  public Matrix columnSum() {
+    double[] S = new double[n];
+    for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++)
+        S[i] += vals[j];
+
+    return new Matrix(S, 1);
+  }
+
+  public SparseMatrix timesEquals(double s) {
+    for (int i = 0; i<nnz; i++) {
+      vals[i] *= s;
+    }
+    return this;
+  }
+
+  public SparseMatrix firstColumnTimesEqual(Matrix B) {
+    double[][] A = B.getArray();
+    for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++)
+        vals[j] *= A[rowinds[j]][0];
+    return this;
+  }
+
+  public SparseMatrix firstLineTimesEqual(Matrix B) {
+    double[][] A = B.getArray();
+    for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++)
+        vals[j] *= A[0][i];
+    return this;
+  }
+
+  public void opa(double x[], double y[]) {
+    // Computes y = Ax (x et y : length n)
+    Arrays.fill(y, 0);
+    for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++)
+        y[rowinds[j]] += vals[j]*x[i];
+  }
+
+  public void opb(double x[], double y[]) {
+    // Computes y = A'Ax (x et y : length n)
+    if (tempRow==null) tempRow = new double[m];
+    else Arrays.fill(tempRow, 0);
+    Arrays.fill(y, 0);
+    for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++)
+        tempRow[rowinds[j]] += vals[j]*x[i];
+    for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++)
+        y[i] += vals[j]*tempRow[rowinds[j]];
+  }
+
+  public SparseSVD svd(int dim) throws SparseSVD.SparseSVDException {
+    return new SparseSVD(this, dim);
+  }
+
+  /** Analyse factorielle de correspondances
+  @return     Analyse factorielle de correspondances
+  @see Analyse factorielle de correspondances
+   */
+  public SparseAFC afc() {
+    try {
+      return new SparseAFC(this);
+    } catch (SparseSVDException ex) {
+      return null;
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SparseMatrix.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/Matrix.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/Matrix.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/Matrix.java	(revision 3653)
@@ -0,0 +1,1221 @@
+package JamaPlus;
+
+import java.text.NumberFormat;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+import java.io.PrintWriter;
+import java.io.BufferedReader;
+import java.io.StreamTokenizer;
+import JamaPlus.util.*;
+import java.util.ArrayList;
+
+/**
+Jama = Java Matrix class.
+<P>
+The Java Matrix Class provides the fundamental operations of numerical
+linear algebra.  Various constructors create Matrices from two dimensional
+arrays of double precision floating point numbers.  Various "gets" and
+"sets" provide access to submatrices and matrix elements.  Several methods 
+implement basic matrix arithmetic, including matrix addition and
+multiplication, matrix norms, and element-by-element array operations.
+Methods for reading and printing matrices are also included.  All the
+operations in this version of the Matrix Class involve real matrices.
+Complex matrices may be handled in a future version.
+<P>
+Five fundamental matrix decompositions, which consist of pairs or triples
+of matrices, permutation vectors, and the like, produce results in five
+decomposition classes.  These decompositions are accessed by the Matrix
+class to compute solutions of simultaneous linear equations, determinants,
+inverses and other matrix functions.  The five decompositions are:
+<P><UL>
+<LI>Cholesky Decomposition of symmetric, positive definite matrices.
+<LI>LU Decomposition of rectangular matrices.
+<LI>QR Decomposition of rectangular matrices.
+<LI>Singular Value Decomposition of rectangular matrices.
+<LI>Eigenvalue Decomposition of both symmetric and nonsymmetric square matrices.
+</UL>
+<DL>
+<DT><B>Example of use:</B></DT>
+<P>
+<DD>Solve a linear system A x = b and compute the residual norm, ||b - A x||.
+<P><PRE>
+double[][] vals = {{1.,2.,3},{4.,5.,6.},{7.,8.,10.}};
+Matrix A = new Matrix(vals);
+Matrix b = Matrix.random(3,1);
+Matrix x = A.solve(b);
+Matrix r = A.times(x).minus(b);
+double rnorm = r.normInf();
+</PRE></DD>
+</DL>
+
+@author The MathWorks, Inc. and the National Institute of Standards and Technology.
+@version 5 August 1998
+ */
+public class Matrix implements Cloneable, java.io.Serializable {
+
+  /* ------------------------
+  Class variables
+   * ------------------------ */
+  /** Array for internal storage of elements.
+  @serial internal array storage.
+   */
+  private double[][] A;
+  /** Row and column dimensions.
+  @serial row dimension.
+  @serial column dimension.
+   */
+  private int m, n;
+
+  /* ------------------------
+  Constructors
+   * ------------------------ */
+  /** Construct an m-by-n matrix of zeros. 
+  @param m    Number of rows.
+  @param n    Number of colums.
+   */
+  public Matrix(int m, int n) {
+    this.m = m;
+    this.n = n;
+    A = new double[m][n];
+  }
+
+  /** Construct an m-by-n constant matrix.
+  @param m    Number of rows.
+  @param n    Number of colums.
+  @param s    Fill the matrix with this scalar value.
+   */
+  public Matrix(int m, int n, double s) {
+    this.m = m;
+    this.n = n;
+    A = new double[m][n];
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = s;
+      }
+    }
+  }
+
+  /** Construct a matrix from a 2-D array.
+  @param A    Two-dimensional array of doubles.
+  @exception  IllegalArgumentException All rows must have the same length
+  @see        #constructWithCopy
+   */
+  public Matrix(double[][] A) {
+    m = A.length;
+    n = A[0].length;
+    for (int i = 0; i < m; i++) {
+      if (A[i].length != n) {
+        throw new IllegalArgumentException("All rows must have the same length.");
+      }
+    }
+    this.A = A;
+  }
+
+  /** Construct a matrix quickly without checking arguments.
+  @param A    Two-dimensional array of doubles.
+  @param m    Number of rows.
+  @param n    Number of colums.
+   */
+  public Matrix(double[][] A, int m, int n) {
+    this.A = A;
+    this.m = m;
+    this.n = n;
+  }
+
+  /** Construct a matrix from a one-dimensional packed array
+  @param vals One-dimensional array of doubles, packed by columns (ala Fortran).
+  @param m    Number of rows.
+  @exception  IllegalArgumentException Array length must be a multiple of m.
+   */
+  public Matrix(double vals[], int m) {
+    this.m = m;
+    n = (m != 0 ? vals.length / m : 0);
+    if (m * n != vals.length) {
+      throw new IllegalArgumentException("Array length must be a multiple of m.");
+    }
+    A = new double[m][n];
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = vals[i + j * m];
+      }
+    }
+  }
+
+  /* ------------------------
+  Public Methods
+   * ------------------------ */
+  /** Construct a matrix from a copy of a 2-D array.
+  @param A    Two-dimensional array of doubles.
+  @exception  IllegalArgumentException All rows must have the same length
+   */
+  public static Matrix constructWithCopy(double[][] A) {
+    int m = A.length;
+    int n = A[0].length;
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      if (A[i].length != n) {
+        throw new IllegalArgumentException("All rows must have the same length.");
+      }
+      for (int j = 0; j < n; j++) {
+        C[i][j] = A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** Make a deep copy of a matrix
+   */
+  public Matrix copy() {
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      System.arraycopy(A[i], 0, C[i], 0, n);
+    }
+    return X;
+  }
+
+  /** Clone the Matrix object.
+   */
+  public Object clone() {
+    return this.copy();
+  }
+
+  /** Access the internal two-dimensional array.
+  @return     Pointer to the two-dimensional array of matrix elements.
+   */
+  public double[][] getArray() {
+    return A;
+  }
+
+  /** Copy the internal two-dimensional array.
+  @return     Two-dimensional array copy of matrix elements.
+   */
+  public double[][] getArrayCopy() {
+    double[][] C = new double[m][n];
+    for (int i = 0; i < m; i++) {
+      System.arraycopy(A[i], 0, C[i], 0, n);
+    }
+    return C;
+  }
+
+  /** Make a one-dimensional column packed copy of the internal array.
+  @return     Matrix elements packed in a one-dimensional array by columns.
+   */
+  public double[] getColumnPackedCopy() {
+    double[] vals = new double[m * n];
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        vals[i + j * m] = A[i][j];
+      }
+    }
+    return vals;
+  }
+
+  /** Make a one-dimensional row packed copy of the internal array.
+  @return     Matrix elements packed in a one-dimensional array by rows.
+   */
+  public double[] getRowPackedCopy() {
+    double[] vals = new double[m * n];
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        vals[i * n + j] = A[i][j];
+      }
+    }
+    return vals;
+  }
+
+  /** Get row dimension.
+  @return     m, the number of rows.
+   */
+  public int getRowDimension() {
+    return m;
+  }
+
+  /** Get column dimension.
+  @return     n, the number of columns.
+   */
+  public int getColumnDimension() {
+    return n;
+  }
+
+  /** Get a single element.
+  @param i    Row index.
+  @param j    Column index.
+  @return     A(i,j)
+  @exception  ArrayIndexOutOfBoundsException
+   */
+  public double get(int i, int j) {
+    return A[i][j];
+  }
+
+  /** Get a submatrix.
+  @param i0   Initial row index
+  @param i1   Final row index
+  @param j0   Initial column index
+  @param j1   Final column index
+  @return     A(i0:i1,j0:j1)
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public Matrix getMatrix(int i0, int i1, int j0, int j1) {
+    Matrix X = new Matrix(i1 - i0 + 1, j1 - j0 + 1);
+    double[][] B = X.getArray();
+    try {
+      for (int i = i0; i <= i1; i++) {
+        for (int j = j0; j <= j1; j++) {
+          B[i - i0][j - j0] = A[i][j];
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+    return X;
+  }
+
+  /** Get a submatrix.
+  @param r    Array of row indices.
+  @param c    Array of column indices.
+  @return     A(r(:),c(:))
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public Matrix getMatrix(int[] r, int[] c) {
+    Matrix X = new Matrix(r.length, c.length);
+    double[][] B = X.getArray();
+    try {
+      for (int i = 0; i < r.length; i++) {
+        for (int j = 0; j < c.length; j++) {
+          B[i][j] = A[r[i]][c[j]];
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+    return X;
+  }
+
+  /** Get a submatrix.
+  @param i0   Initial row index
+  @param i1   Final row index
+  @param c    Array of column indices.
+  @return     A(i0:i1,c(:))
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public Matrix getMatrix(int i0, int i1, int[] c) {
+    Matrix X = new Matrix(i1 - i0 + 1, c.length);
+    double[][] B = X.getArray();
+    try {
+      for (int i = i0; i <= i1; i++) {
+        for (int j = 0; j < c.length; j++) {
+          B[i - i0][j] = A[i][c[j]];
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+    return X;
+  }
+
+  /** Get a submatrix.
+  @param r    Array of row indices.
+  @param i0   Initial column index
+  @param i1   Final column index
+  @return     A(r(:),j0:j1)
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public Matrix getMatrix(int[] r, int j0, int j1) {
+    Matrix X = new Matrix(r.length, j1 - j0 + 1);
+    double[][] B = X.getArray();
+    try {
+      for (int i = 0; i < r.length; i++) {
+        for (int j = j0; j <= j1; j++) {
+          B[i][j - j0] = A[r[i]][j];
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+    return X;
+  }
+
+  /** Set a single element.
+  @param i    Row index.
+  @param j    Column index.
+  @param s    A(i,j).
+  @exception  ArrayIndexOutOfBoundsException
+   */
+  public void set(int i, int j, double s) {
+    A[i][j] = s;
+  }
+
+  /** Set a submatrix.
+  @param i0   Initial row index
+  @param i1   Final row index
+  @param j0   Initial column index
+  @param j1   Final column index
+  @param X    A(i0:i1,j0:j1)
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public void setMatrix(int i0, int i1, int j0, int j1, Matrix X) {
+    try {
+      for (int i = i0; i <= i1; i++) {
+        for (int j = j0; j <= j1; j++) {
+          A[i][j] = X.get(i - i0, j - j0);
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+  }
+
+  /** Set a submatrix.
+  @param r    Array of row indices.
+  @param c    Array of column indices.
+  @param X    A(r(:),c(:))
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public void setMatrix(int[] r, int[] c, Matrix X) {
+    try {
+      for (int i = 0; i < r.length; i++) {
+        for (int j = 0; j < c.length; j++) {
+          A[r[i]][c[j]] = X.get(i, j);
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+  }
+
+  /** Set a submatrix.
+  @param r    Array of row indices.
+  @param j0   Initial column index
+  @param j1   Final column index
+  @param X    A(r(:),j0:j1)
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public void setMatrix(int[] r, int j0, int j1, Matrix X) {
+    try {
+      for (int i = 0; i < r.length; i++) {
+        for (int j = j0; j <= j1; j++) {
+          A[r[i]][j] = X.get(i, j - j0);
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+  }
+
+  /** Set a submatrix.
+  @param i0   Initial row index
+  @param i1   Final row index
+  @param c    Array of column indices.
+  @param X    A(i0:i1,c(:))
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public void setMatrix(int i0, int i1, int[] c, Matrix X) {
+    try {
+      for (int i = i0; i <= i1; i++) {
+        for (int j = 0; j < c.length; j++) {
+          A[i][c[j]] = X.get(i - i0, j);
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+  }
+
+  /** Matrix transpose.
+  @return    A'
+   */
+  public Matrix transpose() {
+    Matrix X = new Matrix(n, m);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[j][i] = A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** One norm
+  @return    maximum column sum.
+   */
+  public double norm1() {
+    double f = 0;
+    for (int j = 0; j < n; j++) {
+      double s = 0;
+      for (int i = 0; i < m; i++) {
+        s += Math.abs(A[i][j]);
+      }
+      f = Math.max(f, s);
+    }
+    return f;
+  }
+
+  /** Two norm
+  @return    maximum singular value.
+   */
+  public double norm2() {
+    return (new SingularValueDecomposition(this).norm2());
+  }
+
+  /** Infinity norm
+  @return    maximum row sum.
+   */
+  public double normInf() {
+    double f = 0;
+    for (int i = 0; i < m; i++) {
+      double s = 0;
+      for (int j = 0; j < n; j++) {
+        s += Math.abs(A[i][j]);
+      }
+      f = Math.max(f, s);
+    }
+    return f;
+  }
+
+  /** Frobenius norm
+  @return    sqrt of sum of squares of all elements.
+   */
+  public double normF() {
+    double f = 0;
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        f = Math.hypot(f, A[i][j]);
+      }
+    }
+    return f;
+  }
+
+  /**  Unary minus
+  @return    -A
+   */
+  public Matrix uminus() {
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = -A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** C = A + B
+  @param B    another matrix
+  @return     A + B
+   */
+  public Matrix plus(Matrix B) {
+    checkMatrixDimensions(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = A[i][j] + B.A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** A = A + B
+  @param B    another matrix
+  @return     A + B
+   */
+  public Matrix plusEquals(Matrix B) {
+    checkMatrixDimensions(B);
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = A[i][j] + B.A[i][j];
+      }
+    }
+    return this;
+  }
+
+  /** C = A - B
+  @param B    another matrix
+  @return     A - B
+   */
+  public Matrix minus(Matrix B) {
+    checkMatrixDimensions(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = A[i][j] - B.A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** A = A - B
+  @param B    another matrix
+  @return     A - B
+   */
+  public Matrix minusEquals(Matrix B) {
+    checkMatrixDimensions(B);
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = A[i][j] - B.A[i][j];
+      }
+    }
+    return this;
+  }
+
+  /** Element-by-element multiplication, C = A.*B
+  @param B    another matrix
+  @return     A.*B
+   */
+  public Matrix arrayTimes(Matrix B) {
+    checkMatrixDimensions(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = A[i][j] * B.A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** Element-by-element multiplication in place, A = A.*B
+  @param B    another matrix
+  @return     A.*B
+   */
+  public Matrix arrayTimesEquals(Matrix B) {
+    checkMatrixDimensions(B);
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = A[i][j] * B.A[i][j];
+      }
+    }
+    return this;
+  }
+
+  /** Element-by-element right division, C = A./B
+  @param B    another matrix
+  @return     A./B
+   */
+  public Matrix arrayRightDivide(Matrix B) {
+    checkMatrixDimensions(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = A[i][j] / B.A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** Element-by-element right division in place, A = A./B
+  @param B    another matrix
+  @return     A./B
+   */
+  public Matrix arrayRightDivideEquals(Matrix B) {
+    checkMatrixDimensions(B);
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = A[i][j] / B.A[i][j];
+      }
+    }
+    return this;
+  }
+
+  /** Element-by-element left division, C = A.\B
+  @param B    another matrix
+  @return     A.\B
+   */
+  public Matrix arrayLeftDivide(Matrix B) {
+    checkMatrixDimensions(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = B.A[i][j] / A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** Element-by-element left division in place, A = A.\B
+  @param B    another matrix
+  @return     A.\B
+   */
+  public Matrix arrayLeftDivideEquals(Matrix B) {
+    checkMatrixDimensions(B);
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = B.A[i][j] / A[i][j];
+      }
+    }
+    return this;
+  }
+
+  /** Multiply a matrix by a scalar, C = s*A
+  @param s    scalar
+  @return     s*A
+   */
+  public Matrix times(double s) {
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = s * A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** Multiply a matrix by a scalar in place, A = s*A
+  @param s    scalar
+  @return     replace A by s*A
+   */
+  public Matrix timesEquals(double s) {
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = s * A[i][j];
+      }
+    }
+    return this;
+  }
+
+  /** Linear algebraic matrix multiplication, A * B
+  @param B    another matrix
+  @return     Matrix product, A * B
+  @exception  IllegalArgumentException Matrix inner dimensions must agree.
+   */
+  public Matrix times(Matrix B) {
+    if (B.m != n) {
+      throw new IllegalArgumentException("Matrix inner dimensions must agree.");
+    }
+    Matrix X = new Matrix(m, B.n);
+    double[][] C = X.getArray();
+    double[] Bcolj = new double[n];
+    for (int j = 0; j < B.n; j++) {
+      for (int k = 0; k < n; k++) {
+        Bcolj[k] = B.A[k][j];
+      }
+      for (int i = 0; i < m; i++) {
+        double[] Arowi = A[i];
+        double s = 0;
+        for (int k = 0; k < n; k++) {
+          s += Arowi[k] * Bcolj[k];
+        }
+        C[i][j] = s;
+      }
+    }
+    return X;
+  }
+
+  /** LU Decomposition
+  @return     LUDecomposition
+  @see LUDecomposition
+   */
+  public LUDecomposition lu() {
+    return new LUDecomposition(this);
+  }
+
+  /** QR Decomposition
+  @return     QRDecomposition
+  @see QRDecomposition
+   */
+  public QRDecomposition qr() {
+    return new QRDecomposition(this);
+  }
+
+  /** Cholesky Decomposition
+  @return     CholeskyDecomposition
+  @see CholeskyDecomposition
+   */
+  public CholeskyDecomposition chol() {
+    return new CholeskyDecomposition(this);
+  }
+
+  /** Singular Value Decomposition
+  @return     SingularValueDecomposition
+  @see SingularValueDecomposition
+   */
+  public SingularValueDecomposition svd() {
+    return new SingularValueDecomposition(this);
+  }
+
+  /** Eigenvalue Decomposition
+  @return     EigenvalueDecomposition
+  @see EigenvalueDecomposition
+   */
+  public EigenvalueDecomposition eig() {
+    return new EigenvalueDecomposition(this);
+  }
+
+  /** Solve A*X = B
+  @param B    right hand side
+  @return     solution if A is square, least squares solution otherwise
+   */
+  public Matrix solve(Matrix B) {
+    return (m == n ? (new LUDecomposition(this)).solve(B) : (new QRDecomposition(this)).solve(B));
+  }
+
+  /** Solve X*A = B, which is also A'*X' = B'
+  @param B    right hand side
+  @return     solution if A is square, least squares solution otherwise.
+   */
+  public Matrix solveTranspose(Matrix B) {
+    return transpose().solve(B.transpose());
+  }
+
+  /** Matrix inverse or pseudoinverse
+  @return     inverse(A) if A is square, pseudoinverse otherwise.
+   */
+  public Matrix inverse() {
+    return solve(identity(m, m));
+  }
+
+  /** Matrix determinant
+  @return     determinant
+   */
+  public double det() {
+    return new LUDecomposition(this).det();
+  }
+
+  /** Matrix rank
+  @return     effective numerical rank, obtained from SVD.
+   */
+  public int rank() {
+    return new SingularValueDecomposition(this).rank();
+  }
+
+  /** Matrix condition (2 norm)
+  @return     ratio of largest to smallest singular value.
+   */
+  public double cond() {
+    return new SingularValueDecomposition(this).cond();
+  }
+
+  /** Matrix trace.
+  @return     sum of the diagonal elements.
+   */
+  public double trace() {
+    double t = 0;
+    for (int i = 0; i < Math.min(m, n); i++) {
+      t += A[i][i];
+    }
+    return t;
+  }
+
+  /** Generate matrix with random elements
+  @param m    Number of rows.
+  @param n    Number of colums.
+  @return     An m-by-n matrix with uniformly distributed random elements.
+   */
+  public static Matrix random(int m, int n) {
+    Matrix A = new Matrix(m, n);
+    double[][] X = A.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        X[i][j] = Math.random();
+      }
+    }
+    return A;
+  }
+
+  /** Generate identity matrix
+  @param m    Number of rows.
+  @param n    Number of colums.
+  @return     An m-by-n matrix with ones on the diagonal and zeros elsewhere.
+   */
+  public static Matrix identity(int m, int n) {
+    Matrix A = new Matrix(m, n);
+    double[][] X = A.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        X[i][j] = (i == j ? 1.0 : 0.0);
+      }
+    }
+    return A;
+  }
+
+  /** Print the matrix to stdout.   Line the elements up in columns
+   * with a Fortran-like 'Fw.d' style format.
+  @param w    Column width.
+  @param d    Number of digits after the decimal.
+   */
+  public void print(int w, int d) {
+    print(new PrintWriter(System.out, true), w, d);
+  }
+
+  /** Print the matrix to the output stream.   Line the elements up in
+   * columns with a Fortran-like 'Fw.d' style format.
+  @param output Output stream.
+  @param w      Column width.
+  @param d      Number of digits after the decimal.
+   */
+  public void print(PrintWriter output, int w, int d) {
+    DecimalFormat format = new DecimalFormat();
+    format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
+    format.setMinimumIntegerDigits(1);
+    format.setMaximumFractionDigits(d);
+    format.setMinimumFractionDigits(d);
+    format.setGroupingUsed(false);
+    print(output, format, w + 2);
+  }
+
+  /** Print the matrix to stdout.  Line the elements up in columns.
+   * Use the format object, and right justify within columns of width
+   * characters.
+   * Note that is the matrix is to be read back in, you probably will want
+   * to use a NumberFormat that is set to US Locale.
+  @param format A  Formatting object for individual elements.
+  @param width     Field width for each column.
+  @see java.text.DecimalFormat#setDecimalFormatSymbols
+   */
+  public void print(NumberFormat format, int width) {
+    print(new PrintWriter(System.out, true), format, width);
+  }
+
+  // DecimalFormat is a little disappointing coming from Fortran or C's printf.
+  // Since it doesn't pad on the left, the elements will come out different
+  // widths.  Consequently, we'll pass the desired column width in as an
+  // argument and do the extra padding ourselves.
+  /** Print the matrix to the output stream.  Line the elements up in columns.
+   * Use the format object, and right justify within columns of width
+   * characters.
+   * Note that is the matrix is to be read back in, you probably will want
+   * to use a NumberFormat that is set to US Locale.
+  @param output the output stream.
+  @param format A formatting object to format the matrix elements 
+  @param width  Column width.
+  @see java.text.DecimalFormat#setDecimalFormatSymbols
+   */
+  public void print(PrintWriter output, NumberFormat format, int width) {
+    output.println();  // start on new line.
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        String s = format.format(A[i][j]); // format the number
+        int padding = Math.max(1, width - s.length()); // At _least_ 1 space
+        for (int k = 0; k < padding; k++) {
+          output.print(' ');
+        }
+        output.print(s);
+      }
+      output.println();
+    }
+    output.println();   // end with blank line.
+  }
+
+  /** Read a matrix from a stream.  The format is the same the print method,
+   * so printed matrices can be read back in (provided they were printed using
+   * US Locale).  Elements are separated by
+   * whitespace, all the elements for each row appear on a single line,
+   * the last row is followed by a blank line.
+  @param input the input stream.
+   */
+  @SuppressWarnings("unchecked")
+  public static Matrix read(BufferedReader input) throws java.io.IOException {
+    StreamTokenizer tokenizer = new StreamTokenizer(input);
+
+    // Although StreamTokenizer will parse numbers, it doesn't recognize
+    // scientific notation (E or D); however, Double.valueOf does.
+    // The strategy here is to disable StreamTokenizer's number parsing.
+    // We'll only get whitespace delimited words, EOL's and EOF's.
+    // These words should all be numbers, for Double.valueOf to parse.
+
+    tokenizer.resetSyntax();
+    tokenizer.wordChars(0, 255);
+    tokenizer.whitespaceChars(0, ' ');
+    tokenizer.eolIsSignificant(true);
+    java.util.Vector v = new java.util.Vector();
+
+    // Ignore initial empty lines
+    while (tokenizer.nextToken() == StreamTokenizer.TT_EOL);
+    if (tokenizer.ttype == StreamTokenizer.TT_EOF) {
+      throw new java.io.IOException("Unexpected EOF on matrix read.");
+    }
+    do {
+      v.addElement(Double.valueOf(tokenizer.sval)); // Read & store 1st row.
+    } while (tokenizer.nextToken() == StreamTokenizer.TT_WORD);
+
+    int n = v.size();  // Now we've got the number of columns!
+    double row[] = new double[n];
+    for (int j = 0; j < n; j++) // extract the elements of the 1st row.
+    {
+      row[j] = ((Double) v.elementAt(j)).doubleValue();
+    }
+    v.removeAllElements();
+    v.addElement(row);  // Start storing rows instead of columns.
+    while (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
+      // While non-empty lines
+      v.addElement(row = new double[n]);
+      int j = 0;
+      do {
+        if (j >= n) {
+          throw new java.io.IOException("Row " + v.size() + " is too long.");
+        }
+        row[j++] = Double.valueOf(tokenizer.sval).doubleValue();
+      } while (tokenizer.nextToken() == StreamTokenizer.TT_WORD);
+      if (j < n) {
+        throw new java.io.IOException("Row " + v.size() + " is too short.");
+      }
+    }
+    int m = v.size();  // Now we've got the number of rows.
+    double[][] A = new double[m][];
+    v.copyInto(A);  // copy the rows out of the vector
+    return new Matrix(A);
+  }
+
+
+  /* ------------------------
+  Private Methods
+   * ------------------------ */
+  /** Check if size(A) == size(B) **/
+  private void checkMatrixDimensions(Matrix B) {
+    if (B.m != m || B.n != n) {
+      throw new IllegalArgumentException("Matrix dimensions must agree.");
+    }
+  }
+
+  /* ---------------------------------
+  Quelques méthodes supplémentaires
+   * ---------------------------------*/
+  private void checkLineDimension(Matrix B) {
+    if (B.m != m) {
+      throw new IllegalArgumentException("Matrix line dimension must agree.");
+    }
+  }
+
+  private void checkColumnDimension(Matrix B) {
+    if (B.n != n) {
+      throw new IllegalArgumentException("Matrix column dimension must agree.");
+    }
+  }
+
+  public long getNumberNonZeroValues() {
+    long nnz = 0;
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        if (A[i][j] != 0) nnz++;
+      }
+    }
+    return nnz;
+  }
+
+  public double minColumn(int j) {
+    double min = Double.POSITIVE_INFINITY;
+    for (int i = 0; i < m; i++) {
+      min = Math.min(min, A[i][j]);
+    }
+    return min;
+  }
+
+  public double maxColumn(int j) {
+    double max = Double.NEGATIVE_INFINITY;
+    for (int i = 0; i < m; i++) {
+      max = Math.max(max, A[i][j]);
+    }
+    return max;
+  }
+
+  public double elementSum() {
+    double s = 0;
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        s += A[i][j];
+      }
+    }
+    return s;
+  }
+
+  public Matrix lineSum() {
+    Matrix S = new Matrix(m, 1);
+    double s[][] = S.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        s[i][0] += A[i][j];
+      }
+    }
+    return S;
+  }
+
+  public Matrix lineMean() {
+    Matrix S = new Matrix(m, 1);
+    double s[][] = S.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        s[i][0] += A[i][j];
+      }
+      s[i][0] /= n;
+    }
+    return S;
+  }
+
+  public Matrix columnSum() {
+    Matrix S = new Matrix(1, n);
+    double s[][] = S.getArray();
+    for (int j = 0; j < n; j++) {
+      for (int i = 0; i < m; i++) {
+        s[0][j] += A[i][j];
+      }
+    }
+    return S;
+  }
+
+  public Matrix columnMean() {
+    Matrix S = new Matrix(1, n);
+    double s[][] = S.getArray();
+    for (int j = 0; j < n; j++) {
+      for (int i = 0; i < m; i++) {
+        s[0][j] += A[i][j];
+      }
+      s[0][j] /= m;
+    }
+    return S;
+  }
+
+  public Matrix columnCovariance() {
+    double mean[] = new double[n];
+    for (int j = 0; j < n; j++) {
+      for (int i = 0; i < m; i++) {
+        mean[j] += A[i][j];
+      }
+      mean[j] /= m;
+    }
+    Matrix X = new Matrix(n, n);
+    double[][] B = X.getArray();
+    double[] Acolj = new double[m];
+    int coef = m > 2 ? m-1 : 1;
+    for (int j = 0; j < n; j++) {
+      for (int k = 0; k < m; k++) {
+        Acolj[k] = A[k][j] - mean[j];
+      }
+      for (int i = 0; i < n; i++) {
+        double[] Atrowi = new double[m];
+        for (int k = 0; k < m; k++) {
+          Atrowi[k] = A[k][i] - mean[i];
+        }
+        double s = 0;
+        for (int k = 0; k < m; k++) {
+          s += Atrowi[k] * Acolj[k];
+        }
+        B[i][j] = s / coef;
+      }
+    }
+    return X;
+  }
+
+public Matrix firstLineMinus(Matrix B) {
+     checkColumnDimension(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = A[i][j] - B.A[0][j];
+      }
+    }
+    return X;
+ 
+}
+  public Matrix nulColumnSuppression() {
+    ArrayList<Integer> cols = new ArrayList<Integer>();
+    for (int j = 0; j < n; j++) {
+      for (int i = 0; i < m; i++) {
+        if (A[i][j] != 0) {
+          cols.add(j);
+          break;
+        }
+      }
+    }
+    int[] c = new int[cols.size()];
+    for (int i = 0; i < c.length; i++) {
+      c[i] = cols.get(i);
+    }
+    return getMatrix(0, m - 1, c);
+  }
+
+  public Matrix arrayInverse() {
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = 1 / A[i][j];
+      }
+    }
+    return X;
+  }
+
+  public Matrix arraySqrt() {
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = Math.sqrt(A[i][j]);
+      }
+    }
+    return X;
+  }
+
+  public Matrix firstColumTimes(Matrix B) {
+    checkLineDimension(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+
+        C[i][j] = A[i][j] * B.A[i][0];
+      }
+    }
+    return X;
+  }
+
+  public Matrix firstColumnTimesEqual(Matrix B) {
+    checkLineDimension(B);
+    for (int i = 0; i < m; i++) {
+       for (int j = 0; j < n; j++) {
+
+        A[i][j] *= B.A[i][0];
+      }
+    }
+    return this;
+  }
+
+  public Matrix firstLineTimesEqual(Matrix B) {
+    checkColumnDimension(B);
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] *= B.A[0][j];
+      }
+    }
+    return this;
+  }
+
+  public Matrix firstLineTimes(Matrix B) {
+    checkColumnDimension(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = A[i][j] * B.A[0][j];
+      }
+    }
+    return X;
+  }
+
+  public void fixColumnSigns() {
+    for (int j = 0; j < n; j++) {
+      int i = 0;
+      while (i<m && A[i][j] == 0) i++;
+      if (i==m || A[i][j] > 0)  continue;
+      while (i < m) {
+        A[i][j] = -A[i][j];
+        i++;
+      }
+    }
+  }
+
+  /** Analyse factorielle de correspondances
+  @return     Analyse factorielle de correspondances
+  @see Analyse factorielle de correspondances
+   */
+  public AFC afc() {
+    return new AFC(this);
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/Matrix.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SparseAFC.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SparseAFC.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SparseAFC.java	(revision 3653)
@@ -0,0 +1,82 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package JamaPlus;
+
+import JamaPlus.SparseSVD.SparseSVDException;
+
+/**
+ /**
+ *
+ * SparseAFC analyse factorielle des correspondances (matrices creuses)
+ * mat :  matrice binaire (0. ou 1.) profil des lignes (un individu par ligne, un caractère par colonne)
+ * CP: composantes principales,
+ * VP: valeurs d'inertie, 
+ * CG: centres de gravité des CP contenant un même caractère (non calculé dans cette version)
+ * [p,q] = size(mat); p:nb de lignes, q:nb de col
+ * 
+ * @author Bernard Victorri
+ */
+public class SparseAFC {
+  private double[][] CP;
+  private double[] VP;
+  private int p, q, n;
+
+  SparseAFC(SparseMatrix Arg) throws SparseSVDException {
+    SparseMatrix mat = Arg.copy();
+    mat.nulColumnSuppression();
+    p = mat.getRowDimension();
+    q = mat.getColumnDimension();
+    n = Math.min(Math.min(p, q), 5); 
+    // n : nombre de composantes principales espérées (pas plus de 5)
+    if (n == 0) return;
+    if (n == 1) {
+      CP = new double[p][1];
+      VP = new double[1];
+      return;
+    }
+    double f = mat.elementSum();
+    if (f == 0) return;
+    mat = mat.timesEquals(1 / f);
+    Matrix r = mat.lineSum();
+    Matrix r1 = r.arrayInverse();
+    Matrix r2 = r.arraySqrt();
+    Matrix r3 = r2.arrayInverse();
+    Matrix c = mat.columnSum();
+    Matrix c1 = c.arrayInverse();
+    Matrix c2 = c.arraySqrt();
+    Matrix c3 = c2.arrayInverse();
+    mat = mat.firstColumnTimesEqual(r3);
+    mat = mat.firstLineTimesEqual(c3);
+    SparseSVD svd = mat.svd(n);
+    Matrix cp = svd.getU();
+    Matrix vp = new Matrix(svd.getSingularValues(), 1);
+    n = vp.getColumnDimension();   
+    // peut-être moins de composantes principales effectivement calculées
+     if (n == 0) return;
+    if (n == 1) {
+      CP = new double[p][1];
+      VP = new double[1];
+      return;
+    }
+    cp = cp.getMatrix(0, p - 1, 1, n - 1);
+    cp = cp.firstColumnTimesEqual(r2);
+    vp = vp.getMatrix(0, 0, 1, n - 1);
+    cp = cp.firstLineTimesEqual(vp);
+    cp.fixColumnSigns();
+    cp = cp.firstColumnTimesEqual(r1);
+    CP = cp.getArray();
+    VP = vp.getColumnPackedCopy();
+  }
+
+  public Matrix getCP() {
+    if (CP == null) return null;
+    return new Matrix(CP, p, n - 1);
+  }
+
+  public double[] getVP() {
+    return VP;
+  }
+}
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src matt/JamaPlus/SparseAFC.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/.settings/org.eclipse.jdt.groovy.core.prefs
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/.settings/org.eclipse.jdt.groovy.core.prefs	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/.settings/org.eclipse.jdt.groovy.core.prefs	(revision 3653)
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+groovy.compiler.level=40
+groovy.script.filters=**/*.dsld,y,**/*.gradle,n

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/.settings/org.eclipse.jdt.groovy.core.prefs
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/.settings/org.eclipse.core.resources.prefs
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/.settings/org.eclipse.core.resources.prefs	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/.settings/org.eclipse.core.resources.prefs	(revision 3653)
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+encoding//src/org/txm/annotation/urs/messages_fr.properties=UTF-8
+encoding/<project>=UTF-8

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/.settings/org.eclipse.core.resources.prefs
___________________________________________________________________
Added: svn:mime-type
   + text/plain


Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/.settings
___________________________________________________________________
Added: svn:ignore
   + target


Index: TXM/trunk/bundles/org.txm.analec.rcp/.classpath
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/.classpath	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/.classpath	(revision 3653)
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con"
+		path="org.eclipse.jdt.launching.JRE_CONTAINER" />
+	<classpathentry kind="con"
+		path="org.eclipse.pde.core.requiredPlugins">
+		<accessrules>
+			<accessrule kind="accessible" pattern="**" />
+		</accessrules>
+	</classpathentry>
+	<classpathentry kind="src" path="src" />
+	<classpathentry exported="true" kind="lib"
+		path="libs/itext-pdfa-5.5.8.jar" />
+	<classpathentry exported="true" kind="lib"
+		path="libs/itext-xtra-5.5.8.jar" />
+	<classpathentry exported="true" kind="lib"
+		path="libs/jcommon-1.0.23.jar" />
+	<classpathentry exported="true" kind="lib"
+		path="libs/jcommon-xml-1.0.23.jar" />
+	<classpathentry exported="true" kind="lib"
+		path="libs/xmlworker-5.5.8.jar" />
+	<classpathentry exported="true" kind="lib"
+		path="libs/itextpdf-5.5.4.jar" />
+	<classpathentry exported="true" kind="lib"
+		path="libs/glazedlists_java15-1.9.0.jar" />
+	<classpathentry exported="true" kind="con"
+		path="GROOVY_DSL_SUPPORT" />
+	<classpathentry kind="output" path="bin" />
+</classpath>
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/.classpath
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/META-INF/MANIFEST.MF
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/META-INF/MANIFEST.MF	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/META-INF/MANIFEST.MF	(revision 3653)
@@ -0,0 +1,194 @@
+Manifest-Version: 1.0
+Export-Package: JamaPlus,
+ JamaPlus.util,
+ analecrcp,
+ ca.odell.glazedlists,
+ ca.odell.glazedlists.calculation,
+ ca.odell.glazedlists.event,
+ ca.odell.glazedlists.gui,
+ ca.odell.glazedlists.hibernate,
+ ca.odell.glazedlists.impl,
+ ca.odell.glazedlists.impl.adt,
+ ca.odell.glazedlists.impl.adt.barcode2,
+ ca.odell.glazedlists.impl.beans,
+ ca.odell.glazedlists.impl.ctp,
+ ca.odell.glazedlists.impl.event,
+ ca.odell.glazedlists.impl.filter,
+ ca.odell.glazedlists.impl.functions,
+ ca.odell.glazedlists.impl.gui,
+ ca.odell.glazedlists.impl.io,
+ ca.odell.glazedlists.impl.java15,
+ ca.odell.glazedlists.impl.matchers,
+ ca.odell.glazedlists.impl.nio,
+ ca.odell.glazedlists.impl.pmap,
+ ca.odell.glazedlists.impl.rbp,
+ ca.odell.glazedlists.impl.reflect,
+ ca.odell.glazedlists.impl.sort,
+ ca.odell.glazedlists.impl.swing,
+ ca.odell.glazedlists.impl.swt,
+ ca.odell.glazedlists.impl.testing,
+ ca.odell.glazedlists.impl.text,
+ ca.odell.glazedlists.io,
+ ca.odell.glazedlists.jfreechart,
+ ca.odell.glazedlists.matchers,
+ ca.odell.glazedlists.migrationkit,
+ ca.odell.glazedlists.migrationkit.swing,
+ ca.odell.glazedlists.migrationkit.swt,
+ ca.odell.glazedlists.nachocalendar,
+ ca.odell.glazedlists.swing,
+ ca.odell.glazedlists.swt,
+ ca.odell.glazedlists.util.concurrent,
+ com.itextpdf.awt,
+ com.itextpdf.awt.geom,
+ com.itextpdf.awt.geom.gl,
+ com.itextpdf.awt.geom.misc,
+ com.itextpdf.testutils,
+ com.itextpdf.text,
+ com.itextpdf.text.api,
+ com.itextpdf.text.error_messages,
+ com.itextpdf.text.exceptions,
+ com.itextpdf.text.factories,
+ com.itextpdf.text.html,
+ com.itextpdf.text.html.simpleparser,
+ com.itextpdf.text.io,
+ com.itextpdf.text.log,
+ com.itextpdf.text.pdf,
+ com.itextpdf.text.pdf.codec,
+ com.itextpdf.text.pdf.codec.wmf,
+ com.itextpdf.text.pdf.collection,
+ com.itextpdf.text.pdf.crypto,
+ com.itextpdf.text.pdf.draw,
+ com.itextpdf.text.pdf.events,
+ com.itextpdf.text.pdf.fonts,
+ com.itextpdf.text.pdf.fonts.cmaps,
+ com.itextpdf.text.pdf.fonts.otf,
+ com.itextpdf.text.pdf.hyphenation,
+ com.itextpdf.text.pdf.interfaces,
+ com.itextpdf.text.pdf.internal,
+ com.itextpdf.text.pdf.languages,
+ com.itextpdf.text.pdf.mc,
+ com.itextpdf.text.pdf.ocg,
+ com.itextpdf.text.pdf.parser,
+ com.itextpdf.text.pdf.pdfcleanup,
+ com.itextpdf.text.pdf.qrcode,
+ com.itextpdf.text.pdf.richmedia,
+ com.itextpdf.text.pdf.security,
+ com.itextpdf.text.pdf.spatial,
+ com.itextpdf.text.pdf.spatial.objects,
+ com.itextpdf.text.pdf.spatial.units,
+ com.itextpdf.text.pdf.util,
+ com.itextpdf.text.xml,
+ com.itextpdf.text.xml.simpleparser,
+ com.itextpdf.text.xml.simpleparser.handler,
+ com.itextpdf.text.xml.xmp,
+ com.itextpdf.text.zugferd,
+ com.itextpdf.text.zugferd.checkers,
+ com.itextpdf.text.zugferd.checkers.basic,
+ com.itextpdf.text.zugferd.checkers.comfort,
+ com.itextpdf.text.zugferd.checkers.extended,
+ com.itextpdf.text.zugferd.exceptions,
+ com.itextpdf.text.zugferd.profiles,
+ com.itextpdf.tool.xml,
+ com.itextpdf.tool.xml.css,
+ com.itextpdf.tool.xml.css.apply,
+ com.itextpdf.tool.xml.css.parser,
+ com.itextpdf.tool.xml.css.parser.state,
+ com.itextpdf.tool.xml.exceptions,
+ com.itextpdf.tool.xml.html,
+ com.itextpdf.tool.xml.html.head,
+ com.itextpdf.tool.xml.html.pdfelement,
+ com.itextpdf.tool.xml.html.table,
+ com.itextpdf.tool.xml.net,
+ com.itextpdf.tool.xml.net.exc,
+ com.itextpdf.tool.xml.parser,
+ com.itextpdf.tool.xml.parser.io,
+ com.itextpdf.tool.xml.parser.state,
+ com.itextpdf.tool.xml.pipeline,
+ com.itextpdf.tool.xml.pipeline.css,
+ com.itextpdf.tool.xml.pipeline.ctx,
+ com.itextpdf.tool.xml.pipeline.end,
+ com.itextpdf.tool.xml.pipeline.html,
+ com.itextpdf.tool.xml.util,
+ com.itextpdf.xmp,
+ com.itextpdf.xmp.impl,
+ com.itextpdf.xmp.impl.xpath,
+ com.itextpdf.xmp.options,
+ com.itextpdf.xmp.properties,
+ com.keypoint,
+ org.eclipse.jface.fieldassist,
+ org.jfree,
+ org.jfree.base,
+ org.jfree.base.config,
+ org.jfree.base.log,
+ org.jfree.base.modules,
+ org.jfree.date,
+ org.jfree.io,
+ org.jfree.layout,
+ org.jfree.resources,
+ org.jfree.text,
+ org.jfree.threads,
+ org.jfree.ui,
+ org.jfree.ui.about,
+ org.jfree.ui.about.resources,
+ org.jfree.ui.action,
+ org.jfree.ui.tabbedui,
+ org.jfree.util,
+ org.jfree.xml,
+ org.jfree.xml.attributehandlers,
+ org.jfree.xml.factory.objects,
+ org.jfree.xml.generator,
+ org.jfree.xml.generator.model,
+ org.jfree.xml.parser,
+ org.jfree.xml.parser.coretypes,
+ org.jfree.xml.util,
+ org.jfree.xml.writer,
+ org.jfree.xml.writer.coretypes,
+ org.txm.annotation.urs,
+ org.txm.annotation.urs.commands,
+ org.txm.annotation.urs.export,
+ org.txm.annotation.urs.imports,
+ org.txm.annotation.urs.preferences,
+ org.txm.annotation.urs.search,
+ org.txm.annotation.urs.testers,
+ org.txm.annotation.urs.toolbar,
+ org.txm.annotation.urs.view,
+ org.txm.annotation.urs.widgets,
+ org.txm.macro.urs,
+ org.txm.macro.urs.check,
+ org.txm.macro.urs.democrat,
+ org.txm.macro.urs.edit,
+ org.txm.macro.urs.exploit,
+ org.txm.macro.urs.export,
+ org.txm.macro.urs.prototypes.cqp,
+ org.txm.macro.urs.prototypes.exploit,
+ org.txm.macro.urs.prototypes.misc,
+ visuAnalec,
+ visuAnalec.chaines,
+ visuAnalec.donnees,
+ visuAnalec.elements,
+ visuAnalec.fichiers,
+ visuAnalec.statistiques,
+ visuAnalec.texte,
+ visuAnalec.util,
+ visuAnalec.vue
+Bundle-SymbolicName: org.txm.annotation.urs.rcp;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Name: %Bundle-Name.0
+Require-Bundle: org.eclipse.ui;visibility:=reexport,org.eclipse.core.r
+ untime;visibility:=reexport,org.eclipse.jface;visibility:=reexport,or
+ g.eclipse.swt;visibility:=reexport,org.eclipse.core.expressions;bundl
+ e-version="3.4.600";visibility:=reexport,org.txm.core;bundle-version=
+ "0.8.3";visibility:=reexport,org.txm.rcp;bundle-version="0.8.3";visib
+ ility:=reexport,org.txm.utils.core;visibility:=reexport,org.txm.conco
+ rdance.rcp;bundle-version="1.0.0";visibility:=reexport,org.txm.progre
+ ssion.rcp;bundle-version="1.0.0";visibility:=reexport,org.txm.lexical
+ table.rcp;bundle-version="1.0.0";visibility:=reexport,org.txm.edition
+ .rcp;bundle-version="1.0.0";visibility:=reexport,org.txm.annotation.r
+ cp;visibility:=reexport
+Bundle-ActivationPolicy: lazy
+Bundle-ManifestVersion: 2
+Bundle-Activator: analecrcp.Activator
+Bundle-RequiredExecutionEnvironment: JavaSE-16
+Bundle-Vendor: %Bundle-Vendor
+Automatic-Module-Name: org.txm.annotation.urs.rcp
+Eclipse-BundleShape: dir

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/META-INF/MANIFEST.MF
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/.groovy/suggestions.xdsl
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/.groovy/suggestions.xdsl	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/.groovy/suggestions.xdsl	(revision 3653)
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<projectSuggestions/>
Index: TXM/trunk/bundles/org.txm.analec.rcp/.project
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/.project	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/.project	(revision 3653)
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.txm.annotation.urs.rcp</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.groovy.core.groovyNature</nature>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/.project
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/eclipse/jface/fieldassist/TXMSimpleContentProposalProvider.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/eclipse/jface/fieldassist/TXMSimpleContentProposalProvider.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/eclipse/jface/fieldassist/TXMSimpleContentProposalProvider.java	(revision 3653)
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Amir Kouchekinia <amir@pyrus.us> - bug 200762
+ *******************************************************************************/
+package org.eclipse.jface.fieldassist;
+
+import java.util.ArrayList;
+
+import org.txm.annotation.urs.preferences.URSPreferencePage;
+import org.txm.annotation.urs.preferences.URSPreferences;
+import org.txm.core.preferences.TXMPreferences;
+import org.txm.rcp.TxmPreferences;
+
+/**
+ * SimpleContentProposalProvider is a class designed to map a static list of
+ * Strings to content proposals.
+ * 
+ * Modified to find values 
+ * 
+ * @see IContentProposalProvider
+ * @since 3.2
+ * 
+ */
+public class TXMSimpleContentProposalProvider implements IContentProposalProvider {
+
+	/*
+	 * The proposals provided.
+	 */
+	private String[] proposals;
+
+	/*
+	 * The proposals mapped to IContentProposal. Cached for speed in the case
+	 * where filtering is not used.
+	 */
+	private IContentProposal[] contentProposals;
+
+	/*
+	 * Boolean that tracks whether filtering is used.
+	 */
+	private boolean filterProposals = false;
+
+	/**
+	 * Construct a SimpleContentProposalProvider whose content proposals are
+	 * always the specified array of Objects.
+	 * 
+	 * @param proposals
+	 *            the array of Strings to be returned whenever proposals are
+	 *            requested.
+	 */
+	public TXMSimpleContentProposalProvider(String[] proposals) {
+		super();
+		this.proposals = proposals;
+	}
+
+	/**
+	 * Return an array of Objects representing the valid content proposals for a
+	 * field. 
+	 * 
+	 * @param contents
+	 *            the current contents of the field (only consulted if filtering
+	 *            is set to <code>true</code>)
+	 * @param position
+	 *            the current cursor position within the field (ignored)
+	 * @return the array of Objects that represent valid proposals for the field
+	 *         given its current content.
+	 */
+	@Override
+	public IContentProposal[] getProposals(String contents, int position) {
+		
+		if (filterProposals) {
+//			System.out.println("getProposals...");
+			ArrayList<ContentProposal> list = new ArrayList<ContentProposal>();
+			
+			boolean prefixeSearch = URSPreferences.getInstance().getBoolean(URSPreferences.PREFIX_AUTOCOMPLETION);
+			if (prefixeSearch) {
+				for (int i = 0; i < proposals.length; i++) {
+					if (proposals[i].length() >= contents.length()
+							&& proposals[i].substring(0, contents.length())
+									.equalsIgnoreCase(contents)) {
+						list.add(new ContentProposal(proposals[i]));
+					}
+				}
+			} else {
+				contents = contents.toLowerCase();
+				for (int i = 0; i < proposals.length; i++) {
+					if (proposals[i].toLowerCase().contains(contents)) {
+						list.add(new ContentProposal(proposals[i]));
+					}
+				}
+			}
+			
+			return list.toArray(new IContentProposal[list.size()]);
+		}
+		
+		if (contentProposals == null) {
+			contentProposals = new IContentProposal[proposals.length];
+			for (int i = 0; i < proposals.length; i++) {
+				contentProposals[i] = new ContentProposal(proposals[i]);
+			}
+		}
+		return contentProposals;
+	}
+
+	/**
+	 * Set the Strings to be used as content proposals.
+	 * 
+	 * @param items
+	 *            the array of Strings to be used as proposals.
+	 */
+	public void setProposals(String[] items) {
+		this.proposals = items;
+		contentProposals = null;
+	}
+
+	/**
+	 * Set the boolean that controls whether proposals are filtered according to
+	 * the current field content.
+	 * 
+	 * @param filterProposals
+	 *            <code>true</code> if the proposals should be filtered to
+	 *            show only those that match the current contents of the field,
+	 *            and <code>false</code> if the proposals should remain the
+	 *            same, ignoring the field content.
+	 * @since 3.3
+	 */
+	public void setFiltering(boolean filterProposals) {
+		this.filterProposals = filterProposals;
+		// Clear any cached proposals.
+		contentProposals = null;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/eclipse/jface/fieldassist/TXMSimpleContentProposalProvider.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/eclipse/jface/fieldassist/TXMAutoCompleteField.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/eclipse/jface/fieldassist/TXMAutoCompleteField.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/eclipse/jface/fieldassist/TXMAutoCompleteField.java	(revision 3653)
@@ -0,0 +1,114 @@
+package org.eclipse.jface.fieldassist;
+
+import java.util.ArrayList;
+
+import org.eclipse.jface.bindings.keys.KeyStroke;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * AutoCompleteField is a class which attempts to auto-complete a user's
+ * keystrokes by activating a popup that filters a list of proposals according
+ * to the content typed by the user.
+ * 
+ * @see ContentProposalAdapter
+ * @see SimpleContentProposalProvider
+ * 
+ * @since 3.3
+ */
+public class TXMAutoCompleteField {
+
+	private TXMSimpleContentProposalProvider proposalProvider;
+	private TXMContentProposalAdapter adapter;
+	boolean open = false;
+
+	public boolean isOpen() { return adapter.isProposalPopupOpen();};
+	
+	/**
+	 * Construct an AutoComplete field on the specified control, whose
+	 * completions are characterized by the specified array of Strings.
+	 * 
+	 * @param control
+	 *            the control for which autocomplete is desired. May not be
+	 *            <code>null</code>.
+	 * @param controlContentAdapter
+	 *            the <code>IControlContentAdapter</code> used to obtain and
+	 *            update the control's contents. May not be <code>null</code>.
+	 * @param proposals
+	 *            the array of Strings representing valid content proposals for
+	 *            the field.
+	 */
+	public TXMAutoCompleteField(Control control,
+			IControlContentAdapter controlContentAdapter, String[] proposals, KeyStroke keyStroke) {
+		this(control, controlContentAdapter, proposals, keyStroke, null);
+	}
+	
+	/**
+	 * Construct an AutoComplete field on the specified control, whose
+	 * completions are characterized by the specified array of Strings.
+	 * 
+	 * @param control
+	 *            the control for which autocomplete is desired. May not be
+	 *            <code>null</code>.
+	 * @param controlContentAdapter
+	 *            the <code>IControlContentAdapter</code> used to obtain and
+	 *            update the control's contents. May not be <code>null</code>.
+	 * @param proposals
+	 *            the array of Strings representing valid content proposals for
+	 *            the field.
+	 */
+	public TXMAutoCompleteField(Control control,
+			IControlContentAdapter controlContentAdapter, String[] proposals, KeyStroke keyStroke, char[] autoActivationCharacters) {
+		proposalProvider = new TXMSimpleContentProposalProvider(proposals);
+		proposalProvider.setFiltering(true);
+		
+		adapter = new TXMContentProposalAdapter(control, controlContentAdapter,
+				proposalProvider, keyStroke, autoActivationCharacters);
+		adapter.setPropagateKeys(true);
+		adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
+		adapter.addContentProposalListener(new IContentProposalListener2() {
+			@Override
+			public void proposalPopupOpened(ContentProposalAdapter adapter) {
+				open = true;
+			}
+			
+			@Override
+			public void proposalPopupClosed(ContentProposalAdapter adapter) {
+				open = false;
+			}
+		});
+	}
+	
+	/**
+	 * Construct an AutoComplete field on the specified control, whose
+	 * completions are characterized by the specified array of Strings.
+	 * 
+	 * @param control
+	 *            the control for which autocomplete is desired. May not be
+	 *            <code>null</code>.
+	 * @param controlContentAdapter
+	 *            the <code>IControlContentAdapter</code> used to obtain and
+	 *            update the control's contents. May not be <code>null</code>.
+	 * @param proposals
+	 *            the array of Strings representing valid content proposals for
+	 *            the field.
+	 */
+	public TXMAutoCompleteField(Control control,
+			IControlContentAdapter controlContentAdapter, String[] proposals) {
+		this(control, controlContentAdapter, proposals, null, null);
+	}
+
+	/**
+	 * Set the Strings to be used as content proposals.
+	 * 
+	 * @param proposals
+	 *            the array of Strings to be used as proposals.
+	 */
+	public void setProposals(String[] proposals) {
+		proposalProvider.setProposals(proposals);
+	}
+
+	public void open() {
+		if (open) adapter.close();
+		else adapter.open();
+	}
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/eclipse/jface/fieldassist/TXMAutoCompleteField.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/eclipse/jface/fieldassist/TXMContentProposalAdapter.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/eclipse/jface/fieldassist/TXMContentProposalAdapter.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/eclipse/jface/fieldassist/TXMContentProposalAdapter.java	(revision 3653)
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Hannes Erven <hannes@erven.at> - Bug 293841 - [FieldAssist] NumLock keyDown event should not close the proposal popup [with patch]
+ *******************************************************************************/
+package org.eclipse.jface.fieldassist;
+
+import java.util.ArrayList;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.jface.bindings.keys.KeyStroke;
+import org.eclipse.jface.dialogs.PopupDialog;
+import org.eclipse.jface.preference.JFacePreferences;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.Util;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * ContentProposalAdapter can be used to attach content proposal behavior to a
+ * control. This behavior includes obtaining proposals, opening a popup dialog,
+ * managing the content of the control relative to the selections in the popup,
+ * and optionally opening up a secondary popup to further describe proposals.
+ * <p>
+ * A number of configurable options are provided to determine how the control
+ * content is altered when a proposal is chosen, how the content proposal popup
+ * is activated, and whether any filtering should be done on the proposals as
+ * the user types characters.
+ * <p>
+ * This class provides some overridable methods to allow clients to manually
+ * control the popup. However, most of the implementation remains private.
+ * 
+ * @since 3.2
+ */
+public class TXMContentProposalAdapter extends ContentProposalAdapter {
+	public TXMContentProposalAdapter(Control control, IControlContentAdapter controlContentAdapter, IContentProposalProvider proposalProvider, KeyStroke keyStroke, char[] autoActivationCharacters) {
+		super(control, controlContentAdapter, proposalProvider, keyStroke, autoActivationCharacters);
+		// TODO Auto-generated constructor stub
+	}
+	
+	public void open() {
+		super.openProposalPopup();
+	}
+	
+	public void close() {
+		super.closeProposalPopup();
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/eclipse/jface/fieldassist/TXMContentProposalAdapter.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/URSAnnotationReIndexer.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/URSAnnotationReIndexer.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/URSAnnotationReIndexer.java	(revision 3653)
@@ -0,0 +1,165 @@
+package org.txm.annotation.urs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.osgi.util.NLS;
+import org.txm.Toolbox;
+import org.txm.searchengine.cqp.AbstractCqiClient;
+import org.txm.searchengine.cqp.CQPSearchEngine;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.searchengine.cqp.corpus.Property;
+import org.txm.searchengine.cqp.serverException.CqiServerError;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.elements.Unite;
+
+/**
+ * Re index Analec corpus words and annotations with TXM corpus words
+ * 
+ * @author mdecorde
+ *
+ */
+public class URSAnnotationReIndexer {
+	
+	MainCorpus corpus;
+	
+	Corpus analecCorpus;
+	
+	File aafile;
+	
+	public boolean debug = false;
+	
+	public URSAnnotationReIndexer(MainCorpus corpus, Corpus analecCorpus) {
+		this.corpus = corpus;
+		this.analecCorpus = analecCorpus;
+	}
+	
+	public boolean process() throws CqiClientException, IOException, CqiServerError {
+		
+		int corpusSize = corpus.getSize();
+		if (corpusSize == 0) {
+			Log.warning("Error: The CQP corpus is empty ?");
+			return false;
+		}
+		String text = analecCorpus.getTexte();
+		int isearch = 0; // the current search start position
+		
+		AbstractCqiClient CQI = CQPSearchEngine.getCqiClient();
+		Property word = corpus.getProperty("word");
+		
+		int positions[] = new int[corpusSize];
+		for (int i = 0; i < corpusSize; i++) {
+			positions[i] = i;
+		}
+		
+		int positionsCorrespondances[] = new int[corpusSize];
+		String strs[] = CQI.cpos2Str(word.getQualifiedName(), positions);
+		
+		for (int i = 0; i < corpusSize; i++) {
+			int idx = text.indexOf(strs[i], isearch);
+			if (idx < 0) {
+				Log.finer("Error: cannot find word='" + strs[i] + "' (word with position in CQP corpus=" + positions[i] + ") in text with current carret=" + isearch + ". Aborting.");
+				
+				Log.finer("Current text slice is (-20, +20 characters): ");
+				Log.finer("* before: " + text.substring(Math.max(0, isearch - 20), Math.min(isearch + 20, isearch)));
+				Log.finer("* after: " + text.substring(isearch, Math.min(isearch + 20, text.length() - 1)));
+				
+				return false;
+			}
+			positionsCorrespondances[i] = idx;
+			isearch = idx + strs[i].length();
+		}
+		
+		if (debug) Log.finer(Arrays.toString(positions));
+		if (debug) Log.finer(Arrays.toString(positionsCorrespondances));
+		
+		isearch = 0;
+		ArrayList<Unite> unites = analecCorpus.getToutesUnites();
+		if (debug) Log.finer("units not-sorted: ");
+		if (debug) printUnits(unites);
+		Collections.sort(unites, new Comparator<Unite>() {
+			
+			@Override
+			public int compare(Unite o1, Unite o2) {
+				int d = o1.getDeb() - o2.getDeb();
+				if (d == 0) return o1.getFin() - o2.getFin();
+				else return d;
+			}
+		});
+		if (debug) Log.finer("units sorted: ");
+		if (debug) printUnits(unites);
+		
+		int iunite = 0;
+		for (Unite unite : unites) {
+			if (debug) Log.finer("Updating ");
+			if (debug) printUnite(unite);
+			int start = unite.getDeb();
+			int end = unite.getFin();
+			
+			boolean startFound = false;
+			boolean endFound = false;
+			int i = 0; // or not : unites are sorted by start position, we don't need to browse all words \o/
+			for (; i < positionsCorrespondances.length; i++) {
+				if (startFound && endFound) break; // no need to go further
+				if (debug) Log.finer("i=" + i + " positionsCorrespondances[i]=" + positionsCorrespondances[i]);
+				if (!startFound && start < positionsCorrespondances[i]) {
+					unite.setDeb(i - 1);
+					startFound = true;
+				}
+				if (!endFound && end <= positionsCorrespondances[i]) {
+					unite.setFin(i - 1);
+					endFound = true;
+				}
+			}
+			
+			if (!endFound && i == positionsCorrespondances.length) {
+				unite.setFin(i - 1);
+				endFound = true;
+			}
+			if (!startFound && i == positionsCorrespondances.length) {
+				unite.setDeb(i - 1);
+				startFound = true;
+			}
+			
+			if (!(startFound && endFound)) {
+				String s = "Error: cannot find words positions for unite of type=" + unite.getType() + " and unit carret positions=[" + start + ", " + end + "]. Aborting";
+				Log.finer(s);
+				
+				Log.finer("5 last found units are: ");
+				for (int j = 4; j >= 0; j--) {
+					if (iunite - j >= 0) {
+						printUnite(unites.get(iunite - j));
+					}
+				}
+				return false;
+			}
+			// if (i > 0) i--; // restart at previous word
+			iunite++;
+		}
+		if (debug) Log.finer("units updated: ");
+		if (debug) printUnits(unites);
+		return true;
+	}
+	
+	public static void printUnite(Unite unite) {
+		System.out.print(unite.getType() + "[" + unite.getDeb() + ", " + unite.getFin() + "]");
+	}
+	
+	public static void printUnits(List<Unite> units) {
+		int i = 0;
+		for (Unite u : units) {
+			if (i > 0) System.out.print(", ");
+			printUnite(u);
+			i++;
+		}
+		System.out.println();
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/URSAnnotationReIndexer.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/imports/DOMURSAnnotationsImporter.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/imports/DOMURSAnnotationsImporter.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/imports/DOMURSAnnotationsImporter.java	(revision 3653)
@@ -0,0 +1,177 @@
+package org.txm.annotation.urs.imports;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.HashMap;
+
+import javax.xml.stream.XMLInputFactory;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.txm.importer.PersonalNamespaceContext;
+import org.txm.searchengine.cqp.AbstractCqiClient;
+import org.txm.searchengine.cqp.CQPSearchEngine;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+import org.txm.utils.xml.DomUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.vue.Vue;
+
+public class DOMURSAnnotationsImporter {
+
+	MainCorpus mainCorpus;
+	Corpus analecCorpus;
+	File annotationsDirectory;
+	private Vue analecVue;
+	private IProgressMonitor monitor;
+	private XMLInputFactory factory;
+	protected static PersonalNamespaceContext Nscontext = new PersonalNamespaceContext();
+
+	public DOMURSAnnotationsImporter(IProgressMonitor monitor, File outputDirectory, MainCorpus mainCorpus, Corpus analecCorpus, Vue analecVue) {
+		
+		this.annotationsDirectory = outputDirectory;
+		this.mainCorpus = mainCorpus;
+		this.analecCorpus = analecCorpus;
+		this.analecVue = analecVue;
+		this.monitor = monitor;
+	}
+
+	public boolean process() throws Exception {
+		
+		if (!annotationsDirectory.exists()) return false;
+		if (!annotationsDirectory.isDirectory()) return false;
+
+		File[] ursFiles = annotationsDirectory.listFiles(new FilenameFilter() {
+			@Override
+			public boolean accept(File dir, String name) {
+				return name.matches(".+-urs\\.xml");
+			}
+		});
+
+		if (ursFiles == null || ursFiles.length == 0) {
+			Log.warning("No XML files found in "+annotationsDirectory);
+			return false;
+		}
+
+		factory = XMLInputFactory.newInstance();
+
+		for (File xmlAnalec : ursFiles) {
+			
+			String textid = xmlAnalec.getName().substring(0, xmlAnalec.getName().length() - 8);
+			Log.info("Processing text: "+textid);
+			processText(textid, xmlAnalec);
+		}
+
+		return true;
+	}
+
+	private void processText(String textid, File xmlAnalec) throws Exception {
+		AbstractCqiClient CQI = CQPSearchEngine.getCqiClient();
+
+		HashMap<String, HashMap<String, String>> elementProperties = new HashMap<String, HashMap<String, String>>();
+
+		Document doc = DomUtils.load(xmlAnalec);
+		NodeList textElements = doc.getElementsByTagName("stdf");
+		for (int iText = 0 ; iText < textElements.getLength() ; ) {
+			Element text = (Element)textElements.item(iText);
+
+			NodeList backElements = text.getElementsByTagName("annotations");
+			for (int iBack = 0 ; iBack < backElements.getLength() ; ) {
+				Element back = (Element)backElements.item(iBack);
+
+				NodeList divElements = text.getElementsByTagName("div");
+				for (int ifvLib = 0 ; ifvLib < divElements.getLength() ; ifvLib++) {
+					Element divElement = (Element)divElements.item(ifvLib);
+					String n = divElement.getAttribute("type");
+					if (n == null) n = "";
+					if (n.endsWith("-fs")) {
+						getElementPropertiesFromFvLibElement(elementProperties, divElement);
+					}
+				}
+				
+				NodeList children = back.getElementsByTagName("spanGrp");
+				for (int iChild = 0 ; iChild < children.getLength() ; iChild++) {
+					Element spanGrpElement = (Element)children.item(iChild);
+					String type = spanGrpElement.getAttribute("type");
+					String n = spanGrpElement.getAttribute("subtype");
+					if (type.equals("Unit")) {
+						getUnitesFromSpanGrp(spanGrpElement, n);
+					}
+				}
+				
+				children = back.getElementsByTagName("joinGrp");
+				for (int iChild = 0 ; iChild < children.getLength() ; iChild++) {
+					Element joinGrpElement = (Element)children.item(iChild);
+					String type = joinGrpElement.getAttribute("type");
+					String n = joinGrpElement.getAttribute("subtype");
+					if (type.equals("Relation")) {
+						getRelationsFromJoinGrp(joinGrpElement, n);
+					}
+				}
+				
+				children = back.getElementsByTagName("joinGrp");
+				for (int iChild = 0 ; iChild < children.getLength() ; iChild++) {
+					Element joinGrpElement = (Element)children.item(iChild);
+					String type = joinGrpElement.getAttribute("type");
+					String n = joinGrpElement.getAttribute("subtype");
+					if (type.equals("Schema")) {
+						getSchemasFromJoinGrp(joinGrpElement, n);
+					}
+				}
+
+				break; // stop at first back
+			}
+
+			break; // stop at first text
+		}
+	}
+
+	private void getSchemasFromJoinGrp(Element joinGrpElement, String n) {
+		NodeList children = joinGrpElement.getElementsByTagName("join");
+		for (int iChild = 0 ; iChild < children.getLength() ; iChild++) {
+			Element joinElement = (Element)children.item(iChild);
+			String id = joinElement.getAttribute("id");
+			String target = joinElement.getAttribute("target");
+			String ana = joinElement.getAttribute("ana");
+		}
+	}
+
+	private void getRelationsFromJoinGrp(Element joinGrpElement, String n) {
+		// TODO Auto-generated method stub
+		
+	}
+
+	private void getUnitesFromSpanGrp(Element spanGrpElement, String n) {
+		// TODO Auto-generated method stub
+		
+	}
+
+	private void getElementPropertiesFromFvLibElement(HashMap<String, HashMap<String, String>> elementProperties, Element divElement) {
+		NodeList fsElements = divElement.getElementsByTagName("fs");
+		for (int iChild = 0 ; iChild < fsElements.getLength() ; iChild++) {
+			Element fsElement = (Element)fsElements.item(iChild);
+			String id = fsElement.getAttribute("id");
+
+			if (elementProperties.containsKey(id)) {
+				Log.warning(NLS.bind("Warning: duplicated fsElement id: {0}.", id));
+			} else {
+				HashMap<String, String> properties = new HashMap<String, String>();
+				elementProperties.put(id, properties);
+				NodeList fElements = fsElement.getElementsByTagName("f");
+				for (int iChild2 = 0 ; iChild2 < fElements.getLength() ; iChild2++) {
+					Element fElement = (Element)fElements.item(iChild2);
+					String name = fElement.getAttribute("name");
+					if (properties.containsKey(name)) {
+						Log.warning(NLS.bind("Warning: duplicated fElement name: {0} in {1} fsElement.", name, id));
+					} else {
+						properties.put(name, fElement.getTextContent().trim());
+					}
+				}
+			}
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/imports/DOMURSAnnotationsImporter.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/imports/URSAnnotationsImporter.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/imports/URSAnnotationsImporter.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/imports/URSAnnotationsImporter.java	(revision 3653)
@@ -0,0 +1,578 @@
+package org.txm.annotation.urs.imports;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.importer.PersonalNamespaceContext;
+import org.txm.searchengine.cqp.AbstractCqiClient;
+import org.txm.searchengine.cqp.CQPSearchEngine;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.searchengine.cqp.corpus.Subcorpus;
+import org.txm.searchengine.cqp.corpus.query.CQLQuery;
+import org.txm.utils.ConsoleProgressBar;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.Relation;
+import visuAnalec.elements.Schema;
+import visuAnalec.elements.Unite;
+import visuAnalec.fichiers.FichiersGlozz;
+import visuAnalec.fichiers.FichiersJava;
+import visuAnalec.vue.Vue;
+
+public class URSAnnotationsImporter {
+	
+	protected MainCorpus mainCorpus;
+	
+	protected Corpus analecCorpus;
+	
+	protected File annotationsDirectory;
+	
+	protected Vue analecVue;
+	
+	protected IProgressMonitor monitor;
+	
+	protected XMLInputFactory factory;
+	
+	protected File aamFile;
+	
+	protected File evFile;
+	
+	protected static PersonalNamespaceContext Nscontext = new PersonalNamespaceContext();
+	
+	public URSAnnotationsImporter(IProgressMonitor monitor, File outputDirectory, File aamFile, File evFile, MainCorpus mainCorpus, Corpus analecCorpus, Vue analecVue) {
+		this.annotationsDirectory = outputDirectory;
+		this.aamFile = aamFile;
+		this.evFile = evFile;
+		this.mainCorpus = mainCorpus;
+		this.analecCorpus = analecCorpus;
+		this.analecVue = analecVue;
+		this.monitor = monitor;
+	}
+	
+	public boolean process() throws Exception {
+		
+		if (!annotationsDirectory.exists()) {
+			Log.warning(NLS.bind("Error: annotationsDirectory does not exist: {0}.", annotationsDirectory.getAbsolutePath()));
+			return false;
+		}
+		if (!annotationsDirectory.isDirectory()) {
+			Log.warning(NLS.bind("Error: annotationsDirectory is not a directory: {0}.", annotationsDirectory.getAbsolutePath()));
+			return false;
+		}
+		
+		if (aamFile == null || !aamFile.exists() || aamFile.isDirectory()) {
+			Log.warning(NLS.bind("Warning: aamFile does not exist: {0}.", aamFile));
+		} 
+		else {
+			if (!FichiersGlozz.importerModeleGlozz(analecCorpus, aamFile)) {
+				Log.warning(NLS.bind("Error while importing Glozz model: {0}", aamFile));
+				return false;
+			}
+		}
+		
+		if (evFile == null || !evFile.exists() || evFile.isDirectory()) {
+			Log.warning(NLS.bind("Warning: evFile does not exist: {0}.", evFile));
+		}
+		else {
+			Vue vue = URSCorpora.getVue(analecCorpus);
+			if (!FichiersJava.ouvrirVue(vue, evFile)) {
+				Log.warning(NLS.bind("Error while importing View: {0}", evFile));
+				return false;
+			}
+		}
+		
+		File[] ursFiles = annotationsDirectory.listFiles(new FilenameFilter() {
+			
+			@Override
+			public boolean accept(File dir, String name) {
+				return name.matches(".+-urs\\.xml");
+			}
+		});
+		
+		if (ursFiles == null || ursFiles.length == 0) {
+			Log.warning(NLS.bind("No XML files found in {0}.", annotationsDirectory));
+			return false;
+		}
+		Arrays.sort(ursFiles);
+		
+		factory = XMLInputFactory.newInstance();
+		List<String> cqpTextIds = Arrays.asList(mainCorpus.getCorpusTextIdsList());
+		
+		List<Integer> all_result_summary = Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0);
+		
+		if (monitor != null) monitor.subTask(NLS.bind("Processing {0} text(s)...", ursFiles.length));
+		for (File xmlTXMFile : ursFiles) {
+			String textid = xmlTXMFile.getName().substring(0, xmlTXMFile.getName().length() - 8);
+			Log.warning(NLS.bind("Processing text: {0}.", textid));
+			if (cqpTextIds.contains(textid)) {
+				if (monitor != null) monitor.subTask(NLS.bind("Processing the {0} text...", textid));
+				// N unit, N unit error, N unit no match error, N unit too much match error, N Relation, N Relation error, N Schema, N Schema error
+				List<Integer> result_summary = processText(textid, xmlTXMFile);
+				
+				Log.info(textid + " import report: ");
+				Log.info(" N Units added: " + result_summary.get(0));
+				Log.info(" N Units error: " + result_summary.get(1));
+				Log.info(" N Units no match error: " + result_summary.get(2));
+				Log.info(" N Units too much match error: " + result_summary.get(3));
+				Log.info(" N Relations added: " + result_summary.get(4));
+				Log.info(" N Relations error: " + result_summary.get(5));
+				Log.info(" N Schemas added: " + result_summary.get(6));
+				Log.info(" N Schemas error: " + result_summary.get(7));
+				
+				for (int i = 0; i < all_result_summary.size(); i++) {
+					all_result_summary.set(i, all_result_summary.get(i) + result_summary.get(i));
+				}
+			}
+			else {
+				Log.warning(NLS.bind("Warning: cannot found text with ID={0} in current CQP corpus.", textid));
+			}
+			
+			if (monitor != null && monitor.isCanceled()) {
+				return false;
+			}
+		}
+		
+		if (!aamFile.exists()) {
+			Vue vue = URSCorpora.getVue(analecCorpus);
+			vue.retablirVueParDefaut();
+		}
+		
+		Log.info("Final import report: ");
+		Log.info(" N Units added: " + all_result_summary.get(0));
+		Log.info(" N Units error: " + all_result_summary.get(1));
+		Log.info(" N Units no match error: " + all_result_summary.get(2));
+		Log.info(" N Units too much match error: " + all_result_summary.get(3));
+		Log.info(" N Relations added: " + all_result_summary.get(4));
+		Log.info(" N Relations error: " + all_result_summary.get(5));
+		Log.info(" N Schemas added: " + all_result_summary.get(6));
+		Log.info(" N Schemas error: " + all_result_summary.get(7));
+		
+		return true;
+	}
+	
+	private int getPosition(Subcorpus textSubcorpus, HashMap<String, int[]> id2position, String id) {
+		int[] positions = id2position.get(id);
+		int start = textSubcorpus.getMatches().get(0).getStart();
+		int end = textSubcorpus.getMatches().get(0).getEnd();
+		if (positions.length == 0) { // no word for id=deb
+			return -1;
+		}
+		
+		for (int p : positions) {
+			if (start <= p && p <= end) {
+				return p;
+			}
+		}
+		
+		return -2;
+	}
+	
+	private List<Integer> processText(String textid, File xmlTXMFile) throws Exception {
+		AbstractCqiClient CQI = CQPSearchEngine.getCqiClient();
+		// N unit, N unit error, N unit no match error, N unit too much match error, N Relation, N Relation error, N Schema, N Schema error
+		int nUnitsAdded = 0;
+		int nUnitsError = 0;
+		int nUnitsNoMatchError = 0;
+		int nUnitsTooMuchMatchError = 0;
+		int nRelationsAdded = 0;
+		int nRelationsError = 0;
+		int nSchemaAdded = 0;
+		int nSchemaError = 0;
+		
+		unites.clear();
+		relations.clear();
+		schemas.clear();
+		elementProperties.clear();
+		
+		if (!parseXMLTXMFile(xmlTXMFile)) return null; // fill unites, relations, schemas and elementProperties
+		
+		// if (unites.size() > 0) System.out.println(unites);
+		// if (relations.size() > 0) System.out.println(relations);
+		// if (schemas.size() > 0) System.out.println(schemas);
+		// if (elementProperties.size() > 0) System.out.println(elementProperties);
+		// for (String u : unites.keySet()) if (!elementProperties.containsKey(u+"-fs")) System.out.println("MISSIGN ELEM PROPERTIES: "+u);
+		// for (String u : relations.keySet()) if (!elementProperties.containsKey(u+"-fs")) System.out.println("MISSIGN ELEM PROPERTIES: "+u);
+		// for (String u : schemas.keySet()) if (!elementProperties.containsKey(u+"-fs")) System.out.println("MISSIGN ELEM PROPERTIES: "+u);
+		
+		CQLQuery textQuery = new CQLQuery("[_.text_id=\"" + textid + "\"] expand to text");
+		Subcorpus textSubCorpus = mainCorpus.createSubcorpus(textQuery, "TXTTMP");
+		textSubCorpus.compute();
+		
+		HashSet<String> ids = new HashSet<>();
+		for (String id : unites.keySet()) {
+			ids.add(unites.get(id)[2]);
+			ids.add(unites.get(id)[3]);
+		}
+		String[] idsArray = ids.toArray(new String[ids.size()]);
+		int[] idsIds = CQI.str2Id(mainCorpus.getProperty("id").getQualifiedName(), idsArray);
+		
+		HashMap<String, int[]> id2position = new HashMap<>();
+		for (int i = 0; i < idsArray.length; i++) {
+			int[] positions = CQI.id2Cpos(mainCorpus.getProperty("id").getQualifiedName(), idsIds[i]);
+			id2position.put(idsArray[i], positions);
+		}
+		
+		Structure structure = analecCorpus.getStructure();
+		HashSet<String> unitesStructure = structure.getUnites();
+		HashSet<String> relationsStructure = structure.getRelations();
+		HashSet<String> schemasStructure = structure.getSchemas();
+		
+		ConsoleProgressBar cpb = new ConsoleProgressBar(unites.size());
+		for (String id : unites.keySet()) {
+			cpb.tick();
+			String ana = unites.get(id)[0];
+			String type = unites.get(id)[1];
+			if (!unitesStructure.contains(type)) {
+				structure.ajouterType(Unite.class, type);
+			}
+			String deb = unites.get(id)[2];
+			String fin = unites.get(id)[3];
+			if (elementProperties.containsKey(ana)) {
+				
+				int start = getPosition(textSubCorpus, id2position, deb);
+				int end = getPosition(textSubCorpus, id2position, fin);
+				
+				if (start < 0) {
+					nUnitsError++;
+					if (start == -1) {
+						Log.warning(NLS.bind("WARNING: no position found word id = {0}.", deb));
+						nUnitsNoMatchError++;
+					}
+					else {
+						Log.warning(NLS.bind("WARNING: too many positions found for word id = {0}.", deb));
+						nUnitsTooMuchMatchError++;
+					}
+				}
+				else if (end < 0) {
+					nUnitsError++;
+					if (end == -1) {
+						Log.warning(NLS.bind("WARNING: no position found word id = {0}.", fin));
+						nUnitsNoMatchError++;
+					}
+					else {
+						Log.warning(NLS.bind("WARNING: too many positions found for word id = {0}.", fin));
+						nUnitsTooMuchMatchError++;
+					}
+				}
+				else { // OK
+					
+					// System.out.println("create unite: "+type+" ["+deb+", "+fin+"]");
+					Unite unite = analecCorpus.addUniteSaisie(type, start, end);
+					HashMap<String, String> props = elementProperties.get(ana);
+					HashSet<String> nomsProps = structure.getNomsProps(Unite.class, type);
+					for (String prop : props.keySet()) {
+						if (!nomsProps.contains(prop)) {
+							structure.ajouterProp(Unite.class, type, prop);
+						}
+						unite.putProp(prop, props.get(prop));
+					}
+					unitesRef.put(id, unite);
+					nUnitsAdded++;
+				}
+			}
+			else {
+				Log.warning(NLS.bind("Warning no properties found for element id={0} and ana={1}.", id, ana));
+			}
+		}
+		cpb.done();
+		
+		cpb = new ConsoleProgressBar(relations.size());
+		for (String id : relations.keySet()) {
+			cpb.tick();
+			String ana = relations.get(id)[0];
+			String type = relations.get(id)[1];
+			if (!relationsStructure.contains(type)) {
+				structure.ajouterType(Relation.class, type);
+			}
+			String target = relations.get(id)[2];
+			
+			if (elementProperties.containsKey(ana)) {
+				
+				String[] wordsref = target.split(" ");
+				String[] wordsid = new String[wordsref.length];
+				for (int i = 0; i < wordsref.length; i++)
+					wordsid[i] = wordsref[i].substring(1);
+				try {
+					Unite elt1 = unitesRef.get(wordsid[0]);
+					Unite elt2 = unitesRef.get(wordsid[1]);
+					if (elt1 != null && elt2 != null) {
+						// System.out.println("create relation: "+type+" ["+deb+", "+fin+"]");
+						
+						Relation relation = analecCorpus.addRelationSaisie(type, elt1, elt2);
+						HashMap<String, String> props = elementProperties.get(ana);
+						HashSet<String> nomsProps = structure.getNomsProps(Relation.class, type);
+						for (String prop : props.keySet()) {
+							if (!nomsProps.contains(prop)) {
+								structure.ajouterProp(Relation.class, type, prop);
+							}
+							relation.putProp(prop, props.get(prop));
+						}
+						nRelationsAdded++;
+					}
+					else {
+						Log.warning(NLS.bind("ERROR: relation element not found {0}.", Arrays.toString(wordsref)));
+						nRelationsError++;
+					}
+				}
+				catch (Exception e) {
+					
+				}
+			}
+			else {
+				Log.warning(NLS.bind("Warning no properties found for element id={0}", id));
+			}
+		}
+		cpb.done();
+		
+		cpb = new ConsoleProgressBar(schemas.size());
+		for (String id : schemas.keySet()) {
+			cpb.tick();
+			String ana = schemas.get(id)[0];
+			String type = schemas.get(id)[1];
+			if (!schemasStructure.contains(type)) {
+				structure.ajouterType(Schema.class, type);
+			}
+			String target = schemas.get(id)[2];
+			if (elementProperties.containsKey(ana)) {
+				String[] unitsref = target.split(" ");
+				try {
+					// System.out.println("create relation: "+type+" ["+deb+", "+fin+"]");
+					Schema schema = new Schema(type);
+					for (String unitid : unitsref) {
+						unitid = unitid.substring(1); // remove '#'
+						if (unitesRef.containsKey(unitid)) {
+							Unite unite = unitesRef.get(unitid);
+							schema.ajouter(unite);
+						}
+						else {
+							Log.warning(NLS.bind("Warning: missing unit id: {0}.", unitid));
+							nSchemaError++;
+						}
+					}
+					analecCorpus.addSchemaLu(schema);
+					HashMap<String, String> props = elementProperties.get(ana);
+					HashSet<String> nomsProps = structure.getNomsProps(Schema.class, type);
+					for (String prop : props.keySet()) {
+						if (!nomsProps.contains(prop)) {
+							structure.ajouterProp(Schema.class, type, prop);
+						}
+						schema.putProp(prop, props.get(prop));
+					}
+					nSchemaAdded++;
+				}
+				catch (Exception e) {
+					Log.warning(NLS.bind("Error while creating schema with id={0}", id));
+				}
+			}
+			else {
+				Log.warning(NLS.bind("Warning no properties found for element id={0}.", id));
+			}
+		}
+		cpb.done();
+		
+		textSubCorpus.delete();
+		return Arrays.asList(nUnitsAdded, nUnitsError, nUnitsNoMatchError, nUnitsTooMuchMatchError,
+				nRelationsAdded, nRelationsError,
+				nSchemaAdded, nSchemaError);
+	}
+	
+	private boolean parseXMLTXMFile(File xmlTXMFile) throws XMLStreamException, MalformedURLException, IOException {
+		InputStream inputData = xmlTXMFile.toURI().toURL().openStream();
+		factory = XMLInputFactory.newInstance();
+		XMLStreamReader parser = factory.createXMLStreamReader(inputData);
+		
+		String currentType = null;
+		String currentN = null;
+		String currentAna = null;
+		String currentName = null;
+		String currentPropValue = null;
+		
+		int processMode = 0; // 0 nothing, 1 elements 2 properties
+		
+		if (!goToStandOff(parser)) {
+			Log.warning(NLS.bind("Error: cannot find the 'standOff' element in {0}.", xmlTXMFile));
+			return false;
+		}
+		String localname = null;
+		for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser.next()) {
+			switch (event) {
+				case XMLStreamConstants.START_ELEMENT:
+					localname = parser.getLocalName();
+					
+					if (localname.equals("annotationGrp")) {
+						currentType = parser.getAttributeValue(null, "type");
+						currentN = parser.getAttributeValue(null, "subtype");
+						if (currentType != null && currentN != null) {
+							processMode = 1;
+						}
+						else {
+							Log.warning(NLS.bind("Warning found {0} without 'type' and 'n' attribute", localname));
+							processMode = 0;
+						}
+					}
+					else if (localname.equals("div")) {
+						String type = parser.getAttributeValue(null, "type");
+						if (type == null) type = "";
+						if (type.endsWith("-fs"))
+							processMode = 2;
+					}
+					
+					if (processMode == 1) {
+						if (localname.equals("span") || localname.equals("link")) {
+							String id = parser.getAttributeValue(null, "id");
+							String ana = parser.getAttributeValue(null, "ana");
+							// System.out.println("SPAN id="+id +" ana="+ana+" currentType="+currentType+" currentN="+currentN);
+							if ("Unit".equals(currentType)) {
+								String from = parser.getAttributeValue(null, "from");
+								String to = parser.getAttributeValue(null, "to");
+								registerUnite(id, ana, currentN, from, to);
+							}
+							else if ("Relation".equals(currentType)) {
+								String target = parser.getAttributeValue(null, "target");
+								registerRelation(id, ana, currentN, target);
+							}
+							else if ("Schema".equals(currentType)) {
+								String target = parser.getAttributeValue(null, "target");
+								registerSchema(id, ana, currentN, target);
+							}
+						}
+					}
+					else if (processMode == 2) {
+						if (localname.equals("fs")) {
+							currentAna = parser.getAttributeValue(null, "id");
+							if (elementProperties.get(currentAna) != null) Log.warning(NLS.bind("WARNING: duplicated element properties: {0}.", currentAna));
+							elementProperties.put(currentAna, new HashMap<String, String>());
+						}
+						else if (localname.equals("f")) {
+							currentName = parser.getAttributeValue(null, "name");
+							currentPropValue = "";
+						}
+					}
+					else {
+						// nothing to do
+					}
+					
+					break;
+				case XMLStreamConstants.CHARACTERS:
+					if (processMode == 2 && currentAna != null && currentName != null) {
+						currentPropValue += parser.getText();
+					}
+					break;
+				case XMLStreamConstants.END_ELEMENT:
+					localname = parser.getLocalName();
+					if (localname.equals("standOff")) { // stop all
+						parser.close();
+						inputData.close();
+						return true;
+					}
+					else if (processMode == 1 && localname.equals("annotationGrp")) { // stop all
+						currentType = null;
+						currentN = null;
+						processMode = 0;
+					}
+					else if (processMode == 2 && localname.equals("div")) {
+						processMode = 0;
+					}
+					
+					if (processMode == 1) {
+						
+					}
+					else if (processMode == 2) {
+						if (localname.equals("fs")) {
+							currentAna = null;
+						}
+						else if (localname.equals("f")) {
+							if (currentName != null && currentAna != null) {
+								elementProperties.get(currentAna).put(currentName, currentPropValue);
+							}
+							currentName = null;
+						}
+					}
+					else {
+						// nothing to do
+					}
+					
+					break;
+				
+				case XMLStreamConstants.END_DOCUMENT:
+					parser.close();
+					inputData.close();
+					return false;
+			}
+		}
+		parser.close();
+		inputData.close();
+		
+		return false; // standOff not found
+	}
+	
+	HashMap<String, HashMap<String, String>> elementProperties = new HashMap<>();
+	
+	HashMap<String, String[]> unites = new HashMap<>(); // id -> {ana, type, from, to}
+	
+	HashMap<String, Unite> unitesRef = new HashMap<>(); // id -> Unite
+	
+	private void registerUnite(String id, String ana, String type, String from, String to) {
+		String[] data = { ana.substring(1), type, from.substring(5), to.substring(5) };
+		if (unites.containsKey(id)) {
+			Log.warning(NLS.bind("Warning: duplicated Unite id: {0}.", id));
+		}
+		else {
+			unites.put(id, data);
+		}
+	}
+	
+	HashMap<String, String[]> relations = new HashMap<>(); // id -> {ana, type, target}
+	
+	private void registerRelation(String id, String ana, String type, String target) {
+		String[] data = { ana.substring(1), type, target };
+		if (relations.containsKey(id)) {
+			Log.warning(NLS.bind("Warning: duplicated Relation id: {0}.", id));
+		}
+		else {
+			relations.put(id, data);
+		}
+	}
+	
+	HashMap<String, String[]> schemas = new HashMap<>(); // id -> {ana, type, target}
+	
+	private void registerSchema(String id, String ana, String type, String target) {
+		String[] data = { ana.substring(1), type, target };
+		// System.out.println("R schema: "+id+" : "+Arrays.toString(data));
+		if (schemas.containsKey(id)) {
+			Log.warning(NLS.bind("Warning: duplicated Schema id: {0}.", id));
+		}
+		else {
+			schemas.put(id, data);
+		}
+	}
+	
+	private boolean goToStandOff(XMLStreamReader parser) throws XMLStreamException {
+		for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser.next()) {
+			switch (event) {
+				case XMLStreamConstants.START_ELEMENT:
+					String localname = parser.getLocalName();
+					if (localname.equals("standOff")) return true;
+					break;
+			}
+		}
+		return false;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/imports/URSAnnotationsImporter.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/package.html
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/package.html	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/package.html	(revision 3653)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+
+	MAIN DOCUMENTATION
+	<br> Get the Analec corpus using the @see(URSCorpora) class
+
+</body>
+</html>
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/package.html
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportGlozzCorpus.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportGlozzCorpus.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportGlozzCorpus.java	(revision 3653)
@@ -0,0 +1,262 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.Arrays;
+
+import org.apache.commons.io.FilenameUtils;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.MessageBox;
+import org.kohsuke.args4j.Option;
+import org.txm.Toolbox;
+import org.txm.annotation.urs.URSAnnotationReIndexer;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.objects.Project;
+import org.txm.rcp.handlers.scripts.ExecuteImportScript;
+import org.txm.rcp.messages.TXMUIMessages;
+import org.txm.rcp.swt.widget.parameters.ParametersDialog;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.searchengine.cqp.CQPSearchEngine;
+import org.txm.searchengine.cqp.corpus.CorpusManager;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.AsciiUtils;
+import org.txm.utils.DeleteDir;
+import org.txm.utils.io.IOUtils;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.fichiers.FichiersGlozz;
+import visuAnalec.fichiers.FichiersJava;
+
+public class ImportGlozzCorpus extends AbstractHandler {
+	
+	
+	
+	// @Option(name="aafile",usage="an example file", widget="File", required=true, def="text.aa")
+	// File aafile;
+	
+	// @Option(name="acfile",usage="an example file", widget="File", required=true, def="annotations.ac")
+	// File acfile
+	
+	@Option(name = "glozzDirectory", usage = "A folder containing the Glozz files: aa ac and aam", widget = "Folder", required = true, def = "glozz")
+	File glozzDirectory;
+	
+	@Option(name = "aamfile", usage = "The aam file to use", widget = "File", required = true, def = "model.aam")
+	File aamfile;
+	
+	private String name;
+	
+	/*
+	 * (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		try {
+			// Open the parameters input dialog box
+			if (!ParametersDialog.open(this)) return null;
+			
+			// END OF PARAMETERS
+			if (!glozzDirectory.exists()) {
+				Log.warning(Messages.ImportGlozzCorpus_0);
+				return null;
+			}
+			
+			name = glozzDirectory.getName();
+			name = AsciiUtils.buildId(name);
+			String newCorpusName = name.toUpperCase();
+			if (Toolbox.workspace.getProject(newCorpusName) != null) {
+				boolean b = MessageDialog.openConfirm(Display.getCurrent().getActiveShell(), TXMUIMessages.warning, NLS.bind(TXMUIMessages.theP0CorpusDirectoryAlreadyExistsDoYouWantToReplaceIt,
+						newCorpusName));
+				if (!b) {
+					Log.info("Import aborted.");
+					return null;
+				}
+			}
+			
+			final File srcDir = new File(glozzDirectory, name);
+			Log.info(NLS.bind(Messages.ImportGlozzCorpus_1, srcDir));
+			DeleteDir.deleteDirectory(srcDir);
+			srcDir.mkdir();
+			
+			final File ecDir = new File(glozzDirectory, "ec"); //$NON-NLS-1$
+			Log.info(NLS.bind(Messages.ImportGlozzCorpus_3, ecDir));
+			DeleteDir.deleteDirectory(ecDir);
+			ecDir.mkdir();
+			
+			
+			if (!srcDir.exists()) {
+				Log.warning(Messages.ImportGlozzCorpus_4);
+				return null;
+			}
+			
+			if (!ecDir.exists()) {
+				Log.warning(Messages.ImportGlozzCorpus_5);
+				return null;
+			}
+			
+			// write the TXT file WITH paragraphs
+			File[] aaFiles = glozzDirectory.listFiles(new FilenameFilter() {
+				
+				@Override
+				public boolean accept(File dir, String name) {
+					return name.endsWith(".aa"); //$NON-NLS-1$
+				}
+			});
+			File[] acFiles = glozzDirectory.listFiles(new FilenameFilter() {
+				
+				@Override
+				public boolean accept(File dir, String name) {
+					return name.endsWith(".ac"); //$NON-NLS-1$
+				}
+			});
+			
+			if (aaFiles == null || aaFiles.length == 0) {
+				Log.warning(NLS.bind(Messages.ImportGlozzCorpus_8, glozzDirectory));
+				return false;
+			}
+			if (acFiles == null || acFiles.length == 0) {
+				Log.warning(NLS.bind(Messages.ImportGlozzCorpus_9, glozzDirectory));
+				return false;
+			}
+			if (aaFiles.length != acFiles.length) {
+				Log.warning(NLS.bind(Messages.ImportGlozzCorpus_10, glozzDirectory));
+				return false;
+			}
+			
+			Log.info(NLS.bind(Messages.ImportGlozzCorpus_11, glozzDirectory));
+			Arrays.sort(acFiles);
+			Arrays.sort(aaFiles);
+			for (int i = 0; i < aaFiles.length; i++) {
+				File acFile = acFiles[i];
+				File aaFile = aaFiles[i];
+				String name = acFile.getName();
+				int idx = name.indexOf("."); //$NON-NLS-1$
+				if (idx > 0) name = name.substring(0, idx);
+				
+				File txtFile = new File(srcDir, name + ".txt"); //$NON-NLS-1$
+				File ecFile = new File(ecDir, name + ".ec"); //$NON-NLS-1$
+				Corpus tmpAnalecCorpus = new Corpus(); // need a temporary corpus
+				
+				if (!FichiersGlozz.importerGlozz(tmpAnalecCorpus, acFile, aaFile)) {
+					Log.warning(Messages.ImportGlozzCorpus_15);
+					return null;
+				}
+				
+				final String texte = tmpAnalecCorpus.getTexte();
+				int debParag = 0;
+				Integer[] finPars = tmpAnalecCorpus.getFinParagraphes();
+				StringBuffer newTexte = new StringBuffer(texte.length() + finPars.length);
+				for (int iParagraph = 0; iParagraph < finPars.length; iParagraph++) {
+					newTexte.append(texte.substring(debParag, finPars[iParagraph])).append("\n"); //$NON-NLS-1$
+					debParag = finPars[iParagraph];
+				}
+				
+				IOUtils.write(txtFile, newTexte.toString()); // write the TXT file for TXM TXT import module
+				FichiersJava.enregistrerCorpus(tmpAnalecCorpus, ecFile); // write for later
+				
+				if (!txtFile.exists()) {
+					Log.warning(Messages.ImportGlozzCorpus_17);
+					return null;
+				}
+			}
+			
+			Project project = Toolbox.workspace.getProject(newCorpusName);
+			if (project != null) {
+				// CQPSearchEngine.getEngine().stop();
+				project.delete();
+			}
+			project = new Project(Toolbox.workspace, newCorpusName);
+			project.setName(newCorpusName);
+			project.setSourceDirectory(srcDir.getAbsolutePath());
+			project.setImportModuleName("txt");
+			project.getEditionDefinition("default").setBuildEdition(true);
+			
+			JobHandler job = ExecuteImportScript.executeScript(project);
+			if (job == null) { // job is scheduled in ExecuteImportScript.executeScript
+				Log.warning(Messages.ImportGlozzCorpus_23);
+				return null;
+			}
+			
+			JobHandler job2 = new JobHandler(Messages.ImportGlozzCorpus_24) {
+				
+				@Override
+				protected IStatus run(IProgressMonitor monitor) {
+					try {
+						MainCorpus corpus = CorpusManager.getCorpusManager().getCorpus(name.toUpperCase());
+						if (corpus == null) {
+							Log.warning("The CQP corpus was not created. Aborting.");
+							return Status.CANCEL_STATUS;
+						}
+						corpus.compute(false);
+						Corpus analecCorpus = URSCorpora.getCorpus(corpus);
+						analecCorpus.clearAll(); // remove all : annotations, structure
+						File[] ecFiles = ecDir.listFiles(IOUtils.HIDDENFILE_FILTER);
+						Arrays.sort(ecFiles);
+						for (File ecFile : ecFiles) {
+							FichiersJava.concatener(ecFile, analecCorpus);
+						}
+						
+						Log.info(NLS.bind(Messages.ImportGlozzCorpus_25, aamfile));
+						if (!FichiersGlozz.importerModeleGlozz(analecCorpus, aamfile)) {
+							Log.warning(Messages.ImportGlozzCorpus_26);
+							return Status.CANCEL_STATUS;
+						}
+						//
+						// System.out.println("Importing Glozz corpus from: "+acfile+" and "+aafile);
+						// if (!FichiersGlozz.importerGlozz(analecCorpus, acfile, aafile)) {
+						// System.out.println("Error while importing Glozz corpus.");
+						// return null;
+						// }
+						
+						Log.info(Messages.ImportGlozzCorpus_27);
+						URSCorpora.removeCorpus(corpus); // remove old corpus if any
+						
+						URSAnnotationReIndexer aari = new URSAnnotationReIndexer(corpus, analecCorpus);
+						if (!aari.process()) {
+							Log.warning(Messages.ImportGlozzCorpus_28);
+							return Status.CANCEL_STATUS;
+						}
+						
+						Log.info(Messages.ImportGlozzCorpus_29);
+						URSCorpora.saveCorpus(analecCorpus);
+						URSCorpora.getVue(analecCorpus).retablirVueParDefaut();
+						Log.info(Messages.ImportGlozzCorpus_30);
+						analecCorpus.setTexte(""); // free memory //$NON-NLS-1$
+						DeleteDir.deleteDirectory(ecDir); // cleaning
+						DeleteDir.deleteDirectory(srcDir); // cleaning
+						
+						return Status.OK_STATUS;
+					}
+					catch (Exception e) {
+						Log.warning(NLS.bind(Messages.ImportGlozzCorpus_32, e.getLocalizedMessage()));
+						Log.printStackTrace(e);
+						return Status.CANCEL_STATUS;
+					}
+				}
+			};
+			job.join(0, null);
+			if (job.getResult() == Status.OK_STATUS) {
+				job2.startJob(true); // wait for the TXT import job to finish
+			}
+			else {
+				Log.warning("Export could not be finished since the corpus import failed.");
+			}
+			return null;
+		}
+		catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return null;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportGlozzCorpus.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadVue.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadVue.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadVue.java	(revision 3653)
@@ -0,0 +1,59 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.Toolbox;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.fichiers.FichiersJava;
+import visuAnalec.vue.Vue;
+
+public class LoadVue  extends AbstractHandler {
+
+	/** The ID. */
+	public static String ID = "org.txm.annotation.urs.commands.LoadAnnotationStructure"; //$NON-NLS-1$
+
+	/** The selection. */
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		
+		Object first = CorporaView.getFirstSelectedObject();
+		if (!(first instanceof org.txm.searchengine.cqp.corpus.CQPCorpus)) {
+			Log.warning(NLS.bind(Messages.LoadVue_0, first));
+			return null;
+		}
+		
+		MainCorpus mainCorpus = ((org.txm.searchengine.cqp.corpus.CQPCorpus)first).getMainCorpus();
+		
+		load(mainCorpus);
+		return null;
+	}
+	
+	public boolean load(MainCorpus mainCorpus) {
+		Log.info(NLS.bind(Messages.LoadVue_1, mainCorpus.getName()));
+		Vue vue = URSCorpora.getVue(mainCorpus);
+		if (!FichiersJava.ouvrirVue(vue)) {
+			Log.warning(Messages.LoadVue_2);
+			return false;
+		}
+		
+		Log.info(Messages.LoadVue_3);
+		return true;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadVue.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadStructure.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadStructure.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadStructure.java	(revision 3653)
@@ -0,0 +1,59 @@
+package org.txm.annotation.urs.commands;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.donnees.VisuStructure;
+import visuAnalec.fichiers.FichiersJava;
+
+public class LoadStructure  extends AbstractHandler {
+
+	/** The ID. */
+	public static String ID = "org.txm.annotation.urs.commands.LoadAnnotationStructure"; //$NON-NLS-1$
+
+	/** The selection. */
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		
+		Object first = CorporaView.getFirstSelectedObject();
+		if (!(first instanceof org.txm.searchengine.cqp.corpus.CQPCorpus)) {
+			Log.warning(NLS.bind(Messages.LoadStructure_0, first));
+			return null;
+		}
+		
+		MainCorpus mainCorpus = ((org.txm.searchengine.cqp.corpus.CQPCorpus)first).getMainCorpus();
+		Corpus corpus = URSCorpora.getCorpus(mainCorpus);
+//		if (VisuStructure.isOpen()) {
+//			System.out.println("Structure de corpus en cours d'édition. Abandon.");
+//			return null;
+//		}
+		
+		
+		return null;
+	}
+	
+	public static boolean load(Corpus corpus) {
+		Log.info(NLS.bind(Messages.LoadStructure_1, corpus));
+		if (!FichiersJava.ouvrirStructure(corpus)) {
+			Log.warning(Messages.LoadStructure_2);
+			return false;
+		}
+		Log.info(Messages.LoadStructure_3);
+		return true;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadStructure.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/OpenDemocratTools.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/OpenDemocratTools.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/OpenDemocratTools.java	(revision 3653)
@@ -0,0 +1,68 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+
+import org.codehaus.groovy.macro.methods.MacroGroovyMethods.MacroValuePlaceholder;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.kohsuke.args4j.Option;
+import org.txm.Toolbox;
+import org.txm.annotation.urs.view.ElementPropertiesView;
+import org.txm.rcp.views.fileexplorer.MacroExplorer;
+import org.txm.utils.logger.Log;
+
+public class OpenDemocratTools  extends AbstractHandler {
+
+	/** The ID. */
+	public static String ID = "org.txm.annotation.urs.commands.LoadAnnotationStructure"; //$NON-NLS-1$
+
+	@Option(name="ecfile",usage="an example file", widget="File", required=true, def="text.ec")
+	File ecfile;
+
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+
+		return open();
+	}
+
+	public static boolean open() {
+		try {
+			IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+			MacroExplorer view = (MacroExplorer) page.findView(MacroExplorer.ID);
+			// close Element View if opened
+			if (view == null) {
+				view = (MacroExplorer) page.showView(MacroExplorer.ID);
+				page.activate(view);
+			}
+
+			if (view == null) {
+				return false;
+			}
+
+			try {
+				File ursDirectory = new File(Toolbox.getTxmHomePath(), "scripts/groovy/user/org/txm/macro/urs/democrat");
+				view.getTreeViewer().setSelection(new StructuredSelection(ursDirectory));
+				view.getTreeViewer().expandToLevel(ursDirectory, TreeViewer.ALL_LEVELS);
+				//view.getTreeViewer().expandToLevel(elementOrTreePath, level);.collapseAll();
+			} catch (Throwable tr) {
+				Log.info("Democrat macro are in the org/txm/macro/urs/democrat sub directory of the Macro view");
+			}
+			return false;
+		} catch (PartInitException e1) {
+			Log.warning(NLS.bind("Part initialisation error: {0}.", e1.getLocalizedMessage()));
+			Log.printStackTrace(e1);
+		}
+		return false;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/OpenDemocratTools.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/RestoreAnnotations.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/RestoreAnnotations.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/RestoreAnnotations.java	(revision 3653)
@@ -0,0 +1,104 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.view.ElementPropertiesView;
+import org.txm.annotation.urs.view.ElementSearchView;
+import org.txm.annotation.rcp.editor.AnnotationExtension;
+import org.txm.annotation.urs.Messages;
+import org.txm.edition.rcp.editors.SynopticEditionEditor;
+import org.txm.rcp.TXMWindows;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.fichiers.FichiersJava;
+
+public class RestoreAnnotations  extends AbstractHandler {
+
+	/** The ID. */
+	public static String ID = RestoreAnnotations.class.getSimpleName(); //$NON-NLS-1$
+	Corpus corpus;
+	/** The selection. */
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+
+		Object first = CorporaView.getFirstSelectedObject();
+		if (!(first instanceof org.txm.searchengine.cqp.corpus.CQPCorpus)) {
+			Log.warning(NLS.bind(Messages.SaveCorpus_0, first));
+			return null;
+		}
+		final MainCorpus mainCorpus = ((org.txm.searchengine.cqp.corpus.CQPCorpus)first).getMainCorpus();
+		if (restore(mainCorpus, event)) {
+			Log.info("Annotations restored.");
+		} else {
+			Log.info("No annotations to restore.");
+		}
+
+		return null;
+	}
+
+	/**
+	 * 
+	 * @param mainCorpus
+	 * @param event
+	 * @return true is annotations have been modified
+	 */
+	public static boolean restore(final MainCorpus mainCorpus, ExecutionEvent event) {
+		
+		
+		Corpus acorpus = URSCorpora.getCorpus(mainCorpus);
+		if (!acorpus.isModifie()) return false; // nothing to do
+		
+		acorpus.fermer();
+		URSCorpora.revert(mainCorpus);
+
+		mainCorpus.setIsModified(false);
+		
+		if (event != null) {
+			
+			HandlerUtil.getActiveShell(event).getDisplay().syncExec(new Runnable() {
+				@Override
+				public void run() {
+					
+					CorporaView.refreshObject(mainCorpus);
+					
+					ElementPropertiesView.closeView();
+					
+					ElementSearchView.closeView();
+					
+					// find out which editor is using the MainCorpus
+					for (IWorkbenchPage page : TXMWindows.getActiveWindow().getPages()) {
+						for (IEditorReference editor_ref : page.getEditorReferences()) {
+							IEditorPart editor = editor_ref.getEditor(false);
+							if (editor != null && editor instanceof SynopticEditionEditor) {
+								SynopticEditionEditor seditor = ((SynopticEditionEditor)editor);
+								if (seditor.getTXMEditorExtensions(AnnotationExtension.class).size() > 0) {
+									if (mainCorpus.equals(seditor.getCorpus())) {
+										seditor.setDirty(false);
+										seditor.close();
+									}
+								}
+							}
+						}
+					}
+				}
+			});
+		}
+		return true;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/RestoreAnnotations.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ExportGlozzCorpus.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ExportGlozzCorpus.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ExportGlozzCorpus.java	(revision 3653)
@@ -0,0 +1,92 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.kohsuke.args4j.Option;
+import org.txm.annotation.urs.Messages;
+import org.txm.annotation.urs.export.ExportToGlozzMacro;
+import org.txm.rcp.swt.widget.parameters.ParametersDialog;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.searchengine.cqp.serverException.CqiServerError;
+import org.txm.utils.logger.Log;
+
+public class ExportGlozzCorpus extends AbstractHandler {
+	
+	@Option(name = "exportDirectory", usage = "the result directory ", widget = "Folder", required = true, def = "result directory")
+	File exportDirectory;
+	
+	@Option(name = "unit_type", usage = "A unit type to export", widget = "String", required = true, def = "MENTION")
+	String unit_type;
+	
+	/*
+	 * (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		try {
+			// Open the parameters input dialog box
+			if (!ParametersDialog.open(this)) return null;
+			
+			Object first = CorporaView.getFirstSelectedObject();
+			if (!(first instanceof org.txm.searchengine.cqp.corpus.CQPCorpus)) {
+				Log.warning(NLS.bind(Messages.ExportGlozzCorpus_0, first));
+				return null;
+			}
+			
+			final MainCorpus mainCorpus = ((org.txm.searchengine.cqp.corpus.CQPCorpus) first).getMainCorpus();
+			
+			JobHandler job = new JobHandler(NLS.bind(Messages.ExportGlozzCorpus_1, mainCorpus.getName())) {
+				
+				@Override
+				protected IStatus run(IProgressMonitor monitor) {
+					this.runInit(monitor);
+					try {
+						if (exportDirectory == null) {
+							Log.warning("No export directory set. aBorting");
+							return Status.CANCEL_STATUS;
+						}
+						exportDirectory.mkdirs();
+						
+						export(exportDirectory, mainCorpus, unit_type);
+					}
+					catch (ThreadDeath e) {
+						Log.warning(Messages.ExportGlozzCorpus_2);
+					}
+					catch (Throwable e) {
+						Log.warning(NLS.bind(Messages.ExportGlozzCorpus_3, e.getLocalizedMessage()));
+						Log.printStackTrace(e);
+						return Status.CANCEL_STATUS;
+					}
+					return Status.OK_STATUS;
+				}
+			};
+			job.schedule();
+			
+			return null;
+		}
+		catch (Throwable e) {
+			Log.warning(NLS.bind(Messages.ExportGlozzCorpus_3, e.getLocalizedMessage()));
+			Log.printStackTrace(e);
+		}
+		return null;
+	}
+	
+	public static void export(File exportDirectory, MainCorpus mainCorpus, String unit_type) throws NumberFormatException, IOException, CqiServerError, CqiClientException {
+		ExportToGlozzMacro exporter = new ExportToGlozzMacro();
+		File exportFile = new File(exportDirectory, mainCorpus.getID());
+		exporter.doExport(mainCorpus, unit_type, exportFile.getAbsolutePath());
+		return;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ExportGlozzCorpus.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/EditVue.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/EditVue.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/EditVue.java	(revision 3653)
@@ -0,0 +1,65 @@
+package org.txm.annotation.urs.commands;
+
+import java.awt.Dimension;
+import java.awt.Point;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.VisuMain;
+import visuAnalec.donnees.Corpus;
+import visuAnalec.util.GMessages;
+import visuAnalec.vue.VisuVue;
+import visuAnalec.vue.Vue;
+
+public class EditVue  extends AbstractHandler {
+
+	/** The ID. */
+	public static String ID = EditVue.class.getName(); //$NON-NLS-1$
+	Vue vue;
+	/** The selection. */
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+
+		Object first = CorporaView.getFirstSelectedObject();
+		if (!(first instanceof org.txm.searchengine.cqp.corpus.CQPCorpus)) {
+			Log.warning("Selection is not a corpus: "+first);
+			return null;
+		}
+		
+		MainCorpus mainCorpus = ((org.txm.searchengine.cqp.corpus.CQPCorpus)first).getMainCorpus();
+		Corpus corpus = URSCorpora.getCorpus(mainCorpus);
+		vue = URSCorpora.getVue(corpus);
+
+		javax.swing.SwingUtilities.invokeLater(new Runnable() {
+			public void run() {
+				try {
+					//System.out.println("Show editor...");
+					//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+					VisuVue visuVue = VisuVue.newVisuVue(null, vue);
+					visuVue.setExtendedState(VisuMain.NORMAL);
+					
+					Point locFenetre = new Point(50, 50);
+					Dimension dimFenetre = new Dimension(500, 500);
+					visuVue.setLocation(locFenetre);
+					visuVue.setSize(dimFenetre);
+					
+					visuVue.setVisible(true);
+				} catch (Throwable ex) {
+					GMessages.erreurFatale(ex);
+				}
+			}
+		});
+
+		return null;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/EditVue.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/EditStructure.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/EditStructure.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/EditStructure.java	(revision 3653)
@@ -0,0 +1,74 @@
+package org.txm.annotation.urs.commands;
+
+import java.awt.Dimension;
+import java.awt.Point;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.osgi.util.NLS;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.annotation.urs.view.ElementPropertiesView;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.VisuMain;
+import visuAnalec.donnees.Corpus;
+import visuAnalec.donnees.VisuStructure;
+import visuAnalec.util.GMessages;
+
+public class EditStructure  extends AbstractHandler {
+
+	/** The ID. */
+	public static String ID = "org.txm.annotation.urs.commands.LoadAnnotationStructure"; //$NON-NLS-1$
+	
+	/** The selection. */
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+
+		Object first = CorporaView.getFirstSelectedObject();
+		if (!(first instanceof org.txm.searchengine.cqp.corpus.CQPCorpus)) {
+			Log.warning(NLS.bind(Messages.EditStructure_0, first));
+			return null;
+		}
+		
+		MainCorpus mainCorpus = ((org.txm.searchengine.cqp.corpus.CQPCorpus)first).getMainCorpus();
+		Corpus corpus = URSCorpora.getCorpus(mainCorpus);
+
+		//System.out.println("Editing structure for corpus="+corpus);
+
+		ElementPropertiesView.closeView(); // ensure no properties are modified
+		open(corpus);
+
+		return null;
+	}
+	
+	public static void open(final Corpus corpus2) {
+		javax.swing.SwingUtilities.invokeLater(new Runnable() {
+			public void run() {
+				try {
+					//System.out.println("Show editor...");
+					//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+					VisuStructure visuStructure = VisuStructure.newVisuStructure(null, corpus2);
+					visuStructure.setExtendedState(VisuMain.NORMAL);
+					
+					Point locFenetre = new Point(50, 50);
+					Dimension dimFenetre = new Dimension(500, 500);
+					visuStructure.setLocation(locFenetre);
+					visuStructure.setSize(dimFenetre);
+					
+					visuStructure.setVisible(true);
+					visuStructure.agencer();
+				} catch (Throwable ex) {
+					GMessages.erreurFatale(ex);
+				}
+			}
+		});
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/EditStructure.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportTEICorpus.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportTEICorpus.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportTEICorpus.java	(revision 3653)
@@ -0,0 +1,152 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.kohsuke.args4j.Option;
+import org.txm.Toolbox;
+import org.txm.annotation.urs.URSAnnotationReIndexer;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.objects.Project;
+import org.txm.rcp.handlers.scripts.ExecuteImportScript;
+import org.txm.rcp.swt.widget.parameters.ParametersDialog;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.searchengine.cqp.corpus.CorpusManager;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.AsciiUtils;
+import org.txm.utils.DeleteDir;
+import org.txm.utils.io.IOUtils;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.fichiers.FichiersTEI;
+
+public class ImportTEICorpus  extends AbstractHandler {
+	
+	@Option(name="xmlFile",usage="an example file", widget="File", required=true, def="text.xml")
+	File xmlFile;
+	
+	private String name;
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		try {
+			// Open the parameters input dialog box
+			if (!ParametersDialog.open(this)) return null;
+			
+			// END OF PARAMETERS
+			if (!(xmlFile.exists())) {
+				Log.warning(NLS.bind(Messages.ImportTEICorpus_0, xmlFile));
+				return null;
+			}
+			
+			name = xmlFile.getName();
+			int idx = name.indexOf("."); //$NON-NLS-1$
+			name = name.substring(0, idx);
+			name = AsciiUtils.buildId(name);
+			
+			File srcDir = new File(xmlFile.getParentFile(), name);
+			Log.info(Messages.ImportTEICorpus_2);
+			DeleteDir.deleteDirectory(srcDir);
+			srcDir.mkdir();
+			
+			if (!srcDir.exists()) {
+				Log.warning(Messages.ImportTEICorpus_3);
+				return null;
+			}
+			
+			// write the TXT file WITH paragraphs
+			File txtFile = new File(srcDir, name+".txt"); //$NON-NLS-1$
+			Corpus tmpAnalecCorpus = new Corpus(); // need a temporary corpus
+			Log.info(NLS.bind(Messages.ImportTEICorpus_5, xmlFile));
+			if (!FichiersTEI.convertir(xmlFile, new File("/tmp"), tmpAnalecCorpus)) { //$NON-NLS-1$
+				Log.warning(Messages.ImportTEICorpus_7);
+				return null;
+			}
+			
+			final String texte = tmpAnalecCorpus.getTexte();
+			int debParag = 0;
+			Integer[] finPars = tmpAnalecCorpus.getFinParagraphes();
+			StringBuffer newTexte = new StringBuffer(texte.length() + finPars.length);
+			for (int i = 0 ; i < finPars.length ; i++) {
+				newTexte.append(texte.substring(debParag, finPars[i])).append("\n"); //$NON-NLS-1$
+				debParag = finPars[i];
+			}
+			
+			IOUtils.write(txtFile, newTexte.toString());
+			
+			if (!txtFile.exists()) {
+				Log.warning(Messages.ImportTEICorpus_9);
+				return null;
+			}
+			
+			Project project = new Project(Toolbox.workspace, name.toUpperCase());
+			project.setSourceDirectory(srcDir.getAbsolutePath());
+			project.setImportModuleName("txt");
+			project.getEditionDefinition("default").setBuildEdition(true);
+			
+			JobHandler job = ExecuteImportScript.executeScript(project);
+			if (job == null) { // job is scheduled in ExecuteImportScript.executeScript
+				Log.warning(Messages.ImportTEICorpus_15);
+				return null;
+			}
+			
+			JobHandler job2 = new JobHandler(Messages.ImportTEICorpus_16) {
+				
+				@Override
+				protected IStatus run(IProgressMonitor monitor) {
+					try {
+						MainCorpus corpus = CorpusManager.getCorpusManager().getCorpus(name.toUpperCase());
+						File analecDirectory = new File(corpus.getProjectDirectory(), "analec"); //$NON-NLS-1$
+						analecDirectory.mkdirs();
+						Corpus analecCorpus = URSCorpora.getCorpus(corpus);
+						analecCorpus.clearAll(); // remove all : annotations, structure
+						
+						Log.info(NLS.bind(Messages.ImportTEICorpus_18, xmlFile));
+						if (!FichiersTEI.convertir(xmlFile, analecDirectory, analecCorpus)) {
+							Log.warning(Messages.ImportTEICorpus_19);
+							return null;
+						}
+						
+						Log.info(Messages.ImportTEICorpus_20);
+						
+						URSCorpora.removeCorpus(corpus); // remove old corpus if any
+						
+						URSAnnotationReIndexer aari = new URSAnnotationReIndexer(corpus, analecCorpus);
+						if (!aari.process()) {
+							Log.warning(Messages.ImportTEICorpus_21);
+							return null;
+						}
+						
+						Log.info(Messages.ImportTEICorpus_22);
+						URSCorpora.saveCorpus(analecCorpus);
+						URSCorpora.getVue(analecCorpus).retablirVueParDefaut();
+						Log.info(Messages.ImportTEICorpus_23);
+						
+						return Status.OK_STATUS;
+					} catch (Exception e) {
+						Log.warning(NLS.bind(Messages.ImportTEICorpus_24, e));
+						Log.printStackTrace(e);
+						return Status.CANCEL_STATUS;
+					}
+				}
+			};
+			job2.startJob(true); // wait for the TXT import job to finish
+			return null;
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return null;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportTEICorpus.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadStructureFromGlozz.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadStructureFromGlozz.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadStructureFromGlozz.java	(revision 3653)
@@ -0,0 +1,69 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.osgi.util.NLS;
+import org.kohsuke.args4j.Option;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.rcp.swt.widget.parameters.ParametersDialog;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.fichiers.FichiersGlozz;
+
+public class LoadStructureFromGlozz  extends AbstractHandler {
+
+	@Option(name="aamfile",usage="an example file", widget="File", required=true, def="model.aam")
+	File aamfile;
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		
+		Object first = CorporaView.getFirstSelectedObject();
+		if (!(first instanceof org.txm.searchengine.cqp.corpus.CQPCorpus)) {
+			Log.warning(NLS.bind(Messages.LoadStructureFromGlozz_0, first));
+			return null;
+		}
+		
+		MainCorpus mainCorpus = ((org.txm.searchengine.cqp.corpus.CQPCorpus)first).getMainCorpus();
+		Corpus corpus = URSCorpora.getCorpus(mainCorpus);
+		
+//		if (VisuStructure.isOpen()) {
+//			System.out.println("Structure de corpus en cours d'édition. Abandon.");
+//			return null;
+//		}
+
+		if (!ParametersDialog.open(this)) return null;
+
+		Log.info(NLS.bind(Messages.LoadStructureFromGlozz_1, mainCorpus));
+		
+		// END OF PARAMETERS
+		load(aamfile, corpus);
+		return null;
+	}
+	
+	public static boolean load(File aamfile, Corpus corpus) {
+		if (!(aamfile.exists() && aamfile.exists() && aamfile.exists())) {
+			Log.warning(Messages.LoadStructureFromGlozz_2);
+			return false;
+		}
+		
+		File fichierModele = aamfile;
+		if (!FichiersGlozz.importerModeleGlozz(corpus, fichierModele)) {
+			Log.warning(Messages.LoadStructureFromGlozz_3);
+			return false;
+		}
+		
+		Log.info(Messages.LoadStructureFromGlozz_4);
+		return true;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadStructureFromGlozz.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveStructureAsGlozzModel.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveStructureAsGlozzModel.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveStructureAsGlozzModel.java	(revision 3653)
@@ -0,0 +1,49 @@
+package org.txm.annotation.urs.commands;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.osgi.util.NLS;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.fichiers.FichiersGlozz;
+
+public class SaveStructureAsGlozzModel  extends AbstractHandler {
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+
+		Object first = CorporaView.getFirstSelectedObject();
+		if (!(first instanceof org.txm.searchengine.cqp.corpus.CQPCorpus)) {
+			Log.warning(NLS.bind(Messages.SaveStructureAsGlozzModel_0, first));
+			return null;
+		}
+		
+		MainCorpus mainCorpus = ((org.txm.searchengine.cqp.corpus.CQPCorpus)first).getMainCorpus();
+		
+		Corpus corpus = URSCorpora.getCorpus(mainCorpus);
+
+//		if (VisuStructure.isOpen()) {
+//			System.out.println("Structure de corpus en cours d'édition. Abandon.");
+//			return null;
+//		}
+		
+		Log.info(NLS.bind(Messages.SaveStructureAsGlozzModel_1, corpus));
+
+		if (!FichiersGlozz.exporterModeleGlozz(corpus.getStructure())) {
+			Log.warning(Messages.SaveStructureAsGlozzModel_2);
+			return null;
+		}
+
+		Log.info(Messages.SaveStructureAsGlozzModel_3);
+		return null;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveStructureAsGlozzModel.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadCorpus.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadCorpus.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadCorpus.java	(revision 3653)
@@ -0,0 +1,74 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.kohsuke.args4j.Option;
+import org.txm.Toolbox;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.rcp.swt.widget.parameters.ParametersDialog;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.fichiers.FichiersJava;
+import visuAnalec.util.Fichiers;
+import visuAnalec.util.Fichiers.Commande;
+
+public class LoadCorpus  extends AbstractHandler {
+
+	/** The ID. */
+	public static String ID = "org.txm.annotation.urs.commands.LoadAnnotationStructure"; //$NON-NLS-1$
+
+	@Option(name="ecfile",usage="an example file", widget="File", required=true, def="text.ec")
+	File ecfile;
+
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		
+		Object first = CorporaView.getFirstSelectedObject();
+		if (!(first instanceof org.txm.searchengine.cqp.corpus.CQPCorpus)) {
+			Log.warning(NLS.bind(Messages.LoadCorpus_0, first));
+			return null;
+		}
+		
+		MainCorpus mainCorpus = ((org.txm.searchengine.cqp.corpus.CQPCorpus)first).getMainCorpus();
+		Corpus corpus = URSCorpora.getCorpus(mainCorpus);
+		
+		Log.info(Messages.LoadCorpus_1);
+		
+		if (!ParametersDialog.open(this)) return null;
+
+		load(ecfile, corpus);
+		
+		return null;
+	}
+	
+	public static boolean load(File ecfile, Corpus corpus) {
+		if (!(ecfile.exists())) {
+			Log.warning(Messages.LoadCorpus_2);
+			return false;
+		}
+		File fichierCorpus = ecfile;
+		Log.info(NLS.bind(Messages.LoadCorpus_3, fichierCorpus));
+		if (!FichiersJava.ouvrirCorpus(corpus, fichierCorpus, false)) {
+			Log.warning(Messages.LoadCorpus_4);
+			return false;
+		}
+		
+		Log.info(Messages.LoadCorpus_5);
+		return true;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/LoadCorpus.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportGlozzAnnotations.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportGlozzAnnotations.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportGlozzAnnotations.java	(revision 3653)
@@ -0,0 +1,101 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.kohsuke.args4j.Option;
+import org.txm.annotation.urs.URSAnnotationReIndexer;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.rcp.swt.widget.parameters.ParametersDialog;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.corpus.CorpusManager;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.searchengine.cqp.serverException.CqiServerError;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.fichiers.FichiersGlozz;
+
+public class ImportGlozzAnnotations  extends AbstractHandler {
+
+
+
+	@Option(name="aafile",usage="an example file", widget="File", required=true, def="text.aa")
+	File aafile;
+
+	@Option(name="aamfile",usage="an example file", widget="File", required=true, def="model.aam")
+	File aamfile;
+
+	@Option(name="acfile",usage="an example file", widget="File", required=true, def="annotations.ac")
+	File acfile;
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		try {
+			// Open the parameters input dialog box
+			if (!ParametersDialog.open(this)) return null;
+
+			// END OF PARAMETERS
+			
+			return doImport(aafile, aamfile, acfile);
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return null;
+	}
+	
+	public static boolean doImport(File aafile, File aamfile, File acfile) throws CqiClientException, IOException, CqiServerError {
+		if (!(aafile.exists() && aafile.exists() && aafile.exists())) {
+			Log.warning(Messages.ImportGlozzAnnotations_0);
+			return false;
+		}
+
+		Object first = CorporaView.getFirstSelectedObject();
+		if (!(first instanceof org.txm.searchengine.cqp.corpus.CQPCorpus)) {
+			Log.warning(NLS.bind(Messages.ImportGlozzAnnotations_1, first));
+			return false;
+		}
+		
+		MainCorpus mainCorpus = ((org.txm.searchengine.cqp.corpus.CQPCorpus)first).getMainCorpus();
+		Corpus analecCorpus = URSCorpora.getCorpus(mainCorpus);
+		analecCorpus.clearAll(); // remove all : annotations, structure
+		
+		Log.info(NLS.bind(Messages.ImportGlozzAnnotations_2, aamfile));
+		if (!FichiersGlozz.importerModeleGlozz(analecCorpus, aamfile)) {
+			Log.warning(Messages.ImportGlozzAnnotations_3);
+			return false;
+		}
+		
+		Log.info(NLS.bind(Messages.ImportGlozzAnnotations_4, acfile, aafile));
+		if (!FichiersGlozz.importerGlozz(analecCorpus, acfile, aafile)) {
+			Log.warning(Messages.ImportGlozzAnnotations_6);
+			return false;
+		}
+		
+		Log.info(Messages.ImportGlozzAnnotations_7);
+		URSAnnotationReIndexer aari = new URSAnnotationReIndexer(mainCorpus, analecCorpus);
+		if (!aari.process()) {
+			Log.warning(Messages.ImportGlozzAnnotations_8);
+			return false;
+		}
+		
+		Log.info(Messages.ImportGlozzAnnotations_9);
+		URSCorpora.saveCorpus(analecCorpus);
+		
+		Log.info(Messages.ImportGlozzAnnotations_10);
+		return true;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportGlozzAnnotations.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveVue.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveVue.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveVue.java	(revision 3653)
@@ -0,0 +1,51 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.osgi.util.NLS;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.fichiers.FichiersJava;
+
+public class SaveVue  extends AbstractHandler {
+
+	/** The ID. */
+	public static String ID = "org.txm.annotation.urs.commands.LoadAnnotationStructure"; //$NON-NLS-1$
+	Corpus corpus;
+	/** The selection. */
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+
+		Object first = CorporaView.getFirstSelectedObject();
+		if (!(first instanceof org.txm.searchengine.cqp.corpus.CQPCorpus)) {
+			Log.warning(NLS.bind(Messages.SaveVue_0, first));
+			return null;
+		}
+		
+		MainCorpus mainCorpus = ((org.txm.searchengine.cqp.corpus.CQPCorpus)first).getMainCorpus();
+		corpus = URSCorpora.getCorpus(mainCorpus);
+
+		File binaryCorpusDirectory = mainCorpus.getProjectDirectory();
+		File fichierVue = new File(binaryCorpusDirectory, "/analec/"+mainCorpus.getID()+".ecv"); //$NON-NLS-1$ //$NON-NLS-2$
+		Log.info(NLS.bind(Messages.SaveVue_3, corpus, fichierVue));
+
+		if (!FichiersJava.enregistrerCorpus(corpus, fichierVue)) {
+			Log.warning(Messages.SaveVue_5);
+			return null;
+		}
+
+		return null;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveVue.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/URSToolsMenuContribution.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/URSToolsMenuContribution.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/URSToolsMenuContribution.java	(revision 3653)
@@ -0,0 +1,167 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Comparator;
+
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MenuEvent;
+import org.eclipse.swt.events.MenuListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.txm.Toolbox;
+import org.txm.rcp.TXMWindows;
+import org.txm.rcp.handlers.scripts.ExecuteGroovyMacro;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.utils.logger.Log;
+
+public class URSToolsMenuContribution extends ContributionItem {
+
+	Menu menu;
+	int index;
+	public URSToolsMenuContribution() {
+		super();
+	}
+	public URSToolsMenuContribution(String id) {
+		super(id);
+	}
+
+	@Override
+	public void fill(Menu menu, int index) {
+		this.menu = menu;
+		this.index = index;
+
+
+		menu.addMenuListener(new MenuListener() {
+
+			@Override
+			public void menuShown(MenuEvent e) {
+				onOpen(URSToolsMenuContribution.this.menu, URSToolsMenuContribution.this.index);
+			}
+
+			@Override
+			public void menuHidden(MenuEvent e) { }
+		});
+	}
+
+	public File getMacroDirectory() {
+		//create the menu item
+		String w = Toolbox.getTxmHomePath();
+		if (w == null || w.length() == 0) return null;
+
+		return new File(w, "scripts/groovy/user/org/txm/macro/urs");
+	}
+
+	public void onOpen(Menu menu, int index) {
+
+		File macroDirectory = getMacroDirectory();
+		if (macroDirectory == null) return;
+
+		File subDirectory = new File(macroDirectory, this.getId());
+		
+		File[] files = subDirectory.listFiles();
+		if (files == null || files.length == 0) {
+
+			MenuItem[] menuItems = menu.getItems();
+			for (int i = 0; i < menuItems.length; i++) {
+				menuItems[i].dispose();
+			}
+
+//			MenuItem menuItem = new MenuItem(menu, SWT.CHECK, index);
+//			menuItem.setText("<no macro>");
+//			menuItem.addSelectionListener(new SelectionAdapter() {
+//				public void widgetSelected(SelectionEvent e) {
+//					Log.info("To populate this menu, you must create macros in the 'ui/menu/main' macro directory.");
+//				}
+//			});
+			return;
+		}
+
+		populate(menu, subDirectory, index);
+	}
+
+	public static void populate(Menu menu, File directory, int index) {
+
+		// First empty
+		MenuItem[] menuItems = menu.getItems();
+		for (int i = 0; i < menuItems.length; i++) {
+			menuItems[i].dispose();
+		}
+
+		// Find files
+		File[] files = directory.listFiles();
+
+		// first are directories
+		Arrays.sort(files, new Comparator<File>() {
+			@Override
+			public int compare(File arg0, File arg1) {
+				if (arg0.isDirectory()) {
+					if (arg1.isDirectory()) {
+						return arg0.getName().compareTo(arg1.getName());
+					} else {
+						return -1;
+					}
+				} else if (arg1.isFile()) {
+					return arg0.getName().compareTo(arg1.getName());
+				} else {
+					return 1;
+				}
+			}
+
+		});
+		for (File f : files) {
+			if (f.getName().endsWith("Macro.groovy")) {
+				MenuItem menuItem = new MenuItem(menu, SWT.PUSH);
+				menuItem.setText(f.getName().substring(0, f.getName().length()-12).replaceAll("([A-Z])([^A-Z])", " $1$2"));
+				menuItem.addSelectionListener(new MacroSelectionAdapter(f));
+			} else if (f.isDirectory()) {
+				MenuItem subMenuItem = new MenuItem(menu, SWT.CASCADE);
+				subMenuItem.setText(f.getName());
+				Menu submenu = new Menu(menu);
+				subMenuItem.setMenu(submenu);
+				populate(submenu, f, 0);
+			}
+		}
+	}
+
+	public static class MacroSelectionAdapter extends SelectionAdapter {
+		File macro;
+		public MacroSelectionAdapter(File macro) {
+			this.macro = macro;
+		}
+
+		public void widgetSelected(SelectionEvent e) {
+			IWorkbenchWindow acWindow = TXMWindows.getActiveWindow();
+			IWorkbenchPart page = acWindow.getActivePage().getActivePart();
+			ExecuteGroovyMacro.execute(macro.getAbsolutePath(), page, CorporaView.getInstance().getTreeViewer().getSelection(), null, null, null);
+		}
+	}
+
+	public static class MacroDirectoryMenu extends Menu {
+
+		File directory;
+		int index;
+
+		public MacroDirectoryMenu(Menu parentMenu, File dir, int i) {
+			super(parentMenu);
+			this.directory = dir;
+			this.index = i;
+			this.addMenuListener(new MenuListener() {
+
+				@Override
+				public void menuShown(MenuEvent e) {
+					populate(MacroDirectoryMenu.this, directory, index);
+				}
+
+				@Override
+				public void menuHidden(MenuEvent e) { }
+			});
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/URSToolsMenuContribution.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveStructure.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveStructure.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveStructure.java	(revision 3653)
@@ -0,0 +1,54 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.osgi.util.NLS;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.fichiers.FichiersJava;
+
+public class SaveStructure  extends AbstractHandler {
+
+	/** The ID. */
+	public static String ID = SaveStructure.class.getSimpleName();
+	/** The selection. */
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+
+		Object first = CorporaView.getFirstSelectedObject();
+		if (!(first instanceof org.txm.searchengine.cqp.corpus.CQPCorpus)) {
+			Log.warning(NLS.bind(Messages.SaveStructure_0, first));
+			return null;
+		}
+		
+		MainCorpus mainCorpus = ((org.txm.searchengine.cqp.corpus.CQPCorpus)first).getMainCorpus();
+		return save(mainCorpus);
+	}
+	
+	public static boolean save(MainCorpus mainCorpus) {
+		Corpus corpus = URSCorpora.getCorpus(mainCorpus);
+
+		File binaryCorpusDirectory = mainCorpus.getProjectDirectory();
+		File fichierStructure = new File(binaryCorpusDirectory, "/analec/"+mainCorpus.getID()+".ecs"); //$NON-NLS-1$ //$NON-NLS-2$
+		Log.info(NLS.bind(Messages.SaveStructure_3, corpus, fichierStructure));
+
+		if (!FichiersJava.enregistrerStructure(corpus, fichierStructure)) {
+			Log.warning(Messages.SaveStructure_5);
+			return false;
+		}
+
+		return true;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveStructure.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ExportTEICorpus.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ExportTEICorpus.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ExportTEICorpus.java	(revision 3653)
@@ -0,0 +1,103 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.kohsuke.args4j.Option;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.annotation.urs.export.URSAnnotationTEIExporter;
+import org.txm.rcp.swt.widget.parameters.ParametersDialog;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.vue.Vue;
+
+/**
+ * Export the Analec annotation of the selected Corpus
+ * 
+ * @author mdecorde
+ *
+ */
+public class ExportTEICorpus  extends AbstractHandler {
+
+	@Option(name="outputDirectory",usage="zip the result", widget="Folder", required=true, def="outputdir")
+	File outputDirectory;
+	
+	@Option(name="createArchive",usage="zip the result", widget="Boolean", required=true, def="true")
+	Boolean createArchive;
+	
+	@Option(name="copyXMLTXMFiles",usage="Copy the XML Files in the 'texts' directory", widget="Boolean", required=true, def="false")
+	Boolean copyXMLTXMFiles;
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		try {
+			// Open the parameters input dialog box
+			if (!ParametersDialog.open(this)) return null;
+
+			Object first = CorporaView.getFirstSelectedObject();
+			if (!(first instanceof org.txm.searchengine.cqp.corpus.CQPCorpus)) {
+				Log.warning(NLS.bind(Messages.ExportTEICorpus_0, first));
+				return null;
+			}
+			
+			final MainCorpus mainCorpus = ((org.txm.searchengine.cqp.corpus.CQPCorpus)first).getMainCorpus();
+			final Corpus analecCorpus = URSCorpora.getCorpus(mainCorpus);
+			final Vue vue = URSCorpora.getVue(mainCorpus);
+			outputDirectory.mkdirs();
+			JobHandler job = new JobHandler(NLS.bind(Messages.ExportTEICorpus_1P0, mainCorpus.getName())) {
+				
+				@Override
+				protected IStatus run(IProgressMonitor monitor) {
+					try {
+						this.runInit(monitor);
+						if (!export(true, outputDirectory, createArchive, monitor, mainCorpus, analecCorpus, vue, copyXMLTXMFiles)) {
+							Log.warning(Messages.ExportTEICorpus_2);
+							return Status.CANCEL_STATUS;
+						} else {
+							return Status.OK_STATUS;
+						}
+					} catch (Exception e) {
+						Log.warning(NLS.bind(Messages.ExportTEICorpus_3, e.getLocalizedMessage()));
+						Log.printStackTrace(e);
+						return Status.CANCEL_STATUS;
+					}
+				}
+			};
+			job.schedule();
+			
+		} catch (Exception e) {
+			Log.warning(NLS.bind(Messages.ExportTEICorpus_3, e.getLocalizedMessage()));
+			Log.printStackTrace(e);
+		}
+		return null;
+	}
+	
+	public static boolean export(boolean standoffAnnotations, File outputDirectory, boolean createArchive, IProgressMonitor monitor, MainCorpus mainCorpus, Corpus analecCorpus, Vue vue, boolean copyXMLTXMFiles) throws Exception {
+		String name = mainCorpus.getID();
+		File finalOutputDirectory = new File(outputDirectory, name);
+		int n = 2;
+		while (finalOutputDirectory.exists()) {
+			finalOutputDirectory = new File(outputDirectory, name+" ("+n+")"); //$NON-NLS-1$ //$NON-NLS-2$
+			n++;
+		}
+		finalOutputDirectory.mkdirs();
+		URSAnnotationTEIExporter exporter = new URSAnnotationTEIExporter(monitor, finalOutputDirectory, mainCorpus, analecCorpus, vue, copyXMLTXMFiles);
+		boolean ret = exporter.process(standoffAnnotations, createArchive);
+		
+		return ret;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ExportTEICorpus.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/DoInstallStep.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/DoInstallStep.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/DoInstallStep.java	(revision 3653)
@@ -0,0 +1,71 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.framework.Version;
+import org.txm.Toolbox;
+import org.txm.annotation.urs.Messages;
+import org.txm.annotation.urs.preferences.URSPreferences;
+import org.txm.utils.BundleUtils;
+import org.txm.utils.logger.Log;
+
+/**
+ * Copy macros from bundle to TXM macro directory
+ * 
+ * @author mdecorde
+ *
+ */
+public class DoInstallStep  extends org.txm.rcp.commands.TxmCommand {
+
+	/** The ID. */
+	public static String ID = "org.txm.annotation.urs.commands.DoInstallStep"; //$NON-NLS-1$
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) {
+			install();
+			return null;
+	}
+	
+	public void install() {
+		
+		Log.info(Messages.DoInstallStep_2);
+		String saved = URSPreferences.getInstance().getString(URSPreferences.VERSION); //$NON-NLS-1$
+		Version currentVersion = BundleUtils.getBundleVersion("org.txm.annotation.urs.rcp"); //$NON-NLS-1$
+		
+		if (saved != null && saved.length() > 0) {
+			Version savedVersion = new Version(saved);
+			if (currentVersion.compareTo(savedVersion) <= 0) {
+				Log.info(Messages.DoInstallStep_5);
+				//System.out.println("No post-installation of URS to do");
+				return; // nothing to do
+			}
+		}
+		Log.info(NLS.bind(Messages.DoInstallStep_6, currentVersion));
+		
+		File previousURSMacroDirectory = new File(Toolbox.getTxmHomePath(), "scripts/groovy/user/org/txm/macro/analec"); //$NON-NLS-1$
+		if (previousURSMacroDirectory.exists() && saved != null && saved.length() > 0) {
+			File back = new File(previousURSMacroDirectory.getParentFile(), "urs_"+saved); //$NON-NLS-1$
+			if (back.exists()) {
+				Log.info(NLS.bind(Messages.DoInstallStep_9, back.getAbsolutePath()));
+				return;
+			}
+			previousURSMacroDirectory.renameTo(back);
+			Log.info(NLS.bind(Messages.DoInstallStep_11, back.getAbsolutePath()));
+		}
+		
+		File macroDirectory = new File(Toolbox.getTxmHomePath(), "scripts/groovy/user/org/txm/macro/analec"); //$NON-NLS-1$
+		if (!BundleUtils.copyFiles("org.txm.annotation.urs.rcp", "src", "org/txm/macro/", "urs", macroDirectory, true)) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+			Log.warning(NLS.bind(Messages.DoInstallStep_17, macroDirectory.getAbsolutePath()));
+			return;
+		}
+		
+		Log.fine(Messages.DoInstallStep_18);
+		URSPreferences.getInstance().put(URSPreferences.VERSION, currentVersion.toString());
+		return;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/DoInstallStep.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportTEIAnnotations.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportTEIAnnotations.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportTEIAnnotations.java	(revision 3653)
@@ -0,0 +1,143 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.kohsuke.args4j.Option;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.annotation.urs.imports.URSAnnotationsImporter;
+import org.txm.core.messages.TXMCoreMessages;
+import org.txm.rcp.swt.widget.parameters.ParametersDialog;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.vue.Vue;
+/**
+ * Export the Analec annotation of the selected Corpus
+ * 
+ * @author mdecorde
+ *
+ */
+public class ImportTEIAnnotations  extends AbstractHandler {
+
+	@Option(name="directory",usage="the directory containing the XML-TEI-URS annotations files", widget="Folder", required=true, def="annotations")
+	File directory;
+	
+	@Option(name="aamFile",usage="The Glozz model file", widget="FileOpen", required=false, def="model.aam")
+	File aamFile;
+	
+	@Option(name="evFile",usage="The Analec view file", widget="FileOpen", required=false, def="view.ev")
+	File evFile;
+	
+	//@Option(name="standoffAnnotations",usage="select this if the directory contains standoff annotation files", widget="Boolean", required=true, def="false")
+	//boolean standoffAnnotations;
+	@Option(name="resetAnnotations",usage="Remove the old annotations", widget="Boolean", required=true, def="false")
+	Boolean resetAnnotations;
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		try {
+			// Open the parameters input dialog box
+			if (!ParametersDialog.open(this)) return null;
+
+			Object first = CorporaView.getFirstSelectedObject();
+			if (!(first instanceof org.txm.searchengine.cqp.corpus.CQPCorpus)) {
+				Log.warning(NLS.bind(Messages.ImportTEIAnnotations_0, first));
+				return null;
+			}
+			
+			final MainCorpus mainCorpus = ((org.txm.searchengine.cqp.corpus.CQPCorpus)first).getMainCorpus();
+			final Corpus analecCorpus = URSCorpora.getCorpus(mainCorpus);
+			final Vue vue = URSCorpora.getVue(mainCorpus);
+			
+			JobHandler job = new JobHandler(NLS.bind(Messages.ImportTEIAnnotations_1, mainCorpus.getName())) {
+				
+				@Override
+				protected IStatus run(IProgressMonitor monitor) {
+					try {
+						if (resetAnnotations) {
+							analecCorpus.clearAnnot();
+						}
+						
+						if (!importer(monitor, directory, aamFile, evFile, true, mainCorpus, analecCorpus, vue)) {
+							Log.warning(Messages.ImportTEIAnnotations_2);
+							return Status.CANCEL_STATUS;
+						} else {
+							return Status.OK_STATUS;
+						}
+					} catch (Throwable e) {
+						Log.warning(NLS.bind(Messages.ImportTEIAnnotations_3, e.getLocalizedMessage()));
+						Log.printStackTrace(e);
+						return Status.CANCEL_STATUS;
+					}
+				}
+			};
+			job.schedule();
+			
+		} catch (Exception e) {
+			Log.warning(NLS.bind(Messages.ImportTEIAnnotations_3, e.getLocalizedMessage()));
+			Log.printStackTrace(e);
+		}
+		return null;
+	}
+
+	/**
+	 * <pre>
+	 * IProgressMonitor monitor = getIProgressMonitor();
+	 * File directory = new File("resultdir");
+	 * File aamFile = new File("model.aam");
+	 * Boolean stdf = true;
+	 * String name = "BROWN";
+	 * MainCorpus mainCorpus = CorpusManager.getCorpusManager().getCorpus(name)
+	 * Corpus analecCorpus = URSCorpora.getCorpus(name.toUpperCase());
+	 * Vue vue = URSCorpora.getVue(name);
+	 * 
+     * ImportTEIAnnotations.importer(monitor, directory, aamFile, stdf, mainCorpus, analecCorpus, vue);
+     *</pre>
+	 * @param monitor
+	 * @param annotationDirectory
+	 * @param aamFile
+	 * @param standoffAnnotations
+	 * @param mainCorpus
+	 * @param analecCorpus
+	 * @param vue
+	 * @return
+	 * @throws Exception
+	 */
+	public static boolean importer(IProgressMonitor monitor, File annotationDirectory, File aamFile, File evFile, boolean standoffAnnotations, MainCorpus mainCorpus, Corpus analecCorpus, Vue vue) throws Exception {
+//		if (!standoffAnnotations) { // use stax because files are too big for DOM process
+//			AnalecAnnotationsImporter importer = new AnalecAnnotationsImporter(monitor, annotationDirectory, mainCorpus, analecCorpus, vue);
+//			boolean ret = importer.process();
+//			if (ret) System.out.println("Done: "+analecCorpus.getToutesUnites().size()+" unites "+analecCorpus.getToutesRelations().size()+" relations "+analecCorpus.getTousSchemas().size()+" schemas.");
+//			return ret;
+//		} else {
+//			DOMAnalecAnnotationsImporter importer = new DOMAnalecAnnotationsImporter(monitor, annotationDirectory, mainCorpus, analecCorpus, vue);
+//			boolean ret = importer.process();
+//			if (ret) System.out.println("Done: "+analecCorpus.getToutesUnites().size()+" unites "+analecCorpus.getToutesRelations().size()+" relations "+analecCorpus.getTousSchemas().size()+" schemas.");
+//			return ret;
+//		}
+		//TODO: DOMAnalecAnnotationsImporter not finished
+		URSAnnotationsImporter importer = new URSAnnotationsImporter(monitor, annotationDirectory, aamFile, evFile, mainCorpus, analecCorpus, vue);
+		boolean ret = importer.process();
+		
+		if (ret) {
+			Log.info(TXMCoreMessages.bind(Messages.ImportTEIAnnotations_5, analecCorpus.getToutesUnites().size(), analecCorpus.getToutesRelations().size(), analecCorpus.getTousSchemas().size()));
+			mainCorpus.setIsModified(true);
+			CorporaView.refreshObject(mainCorpus);
+		}
+		return ret;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/ImportTEIAnnotations.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveCorpus.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveCorpus.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveCorpus.java	(revision 3653)
@@ -0,0 +1,114 @@
+package org.txm.annotation.urs.commands;
+
+import java.io.File;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.view.ElementPropertiesView;
+import org.txm.core.results.TXMResult;
+import org.txm.annotation.urs.Messages;
+import org.txm.edition.rcp.editors.SynopticEditionEditor;
+import org.txm.rcp.TXMWindows;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.fichiers.FichiersJava;
+import visuAnalec.vue.Vue;
+
+public class SaveCorpus  extends AbstractHandler {
+
+	/** The ID. */
+	public static String ID = "org.txm.annotation.urs.commands.LoadAnnotationStructure"; //$NON-NLS-1$
+	Corpus corpus;
+	/** The selection. */
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+
+		Object first = CorporaView.getFirstSelectedObject();
+		MainCorpus mainCorpus = null;
+		if (first instanceof org.txm.searchengine.cqp.corpus.MainCorpus) {
+			mainCorpus = (MainCorpus)first;
+		} else if (first instanceof TXMResult) {
+			mainCorpus = ((TXMResult)first).getFirstParent(MainCorpus.class);
+		} else {
+			Log.warning(NLS.bind(Messages.SaveCorpus_0, first));
+			return null;
+		}
+		save(mainCorpus, event);
+
+		return null;
+	}
+
+	public static boolean save(final MainCorpus mainCorpus, ExecutionEvent event) {
+		
+		if (!URSCorpora.hasCorpus(mainCorpus)) {
+			Log.warning("** No Analec corpus associated to the CQP corpus: "+mainCorpus);
+			return false;
+		}
+		
+		Corpus corpus = URSCorpora.getCorpus(mainCorpus);
+		
+		if (corpus == null) {
+			Log.warning("** No Analec corpus associated to the CQP corpus: "+mainCorpus.getCqpId());
+			return false;
+		}
+		
+		ElementPropertiesView view = ElementPropertiesView.getView();
+		if (view != null && view.getCurrentAnalecCorpus().equals(corpus)) {
+			view.applyAll();
+		}
+		
+		Vue vue = URSCorpora.getVue(corpus);
+		if (!corpus.isModifie() && !vue.isModifiee()) {
+			Log.warning("** No changes to save in "+mainCorpus.getCqpId());
+			return false;
+		}
+		
+		
+		File binaryCorpusDirectory = mainCorpus.getProjectDirectory();
+		File fichierCorpus = URSCorpora.getECFile(mainCorpus);
+		File fichierVueCorpus = URSCorpora.getECVFile(mainCorpus);
+		
+		Log.info(NLS.bind(Messages.SaveCorpus_3, fichierCorpus, fichierVueCorpus));
+		if (!URSCorpora.saveCorpus(mainCorpus)) {
+			Log.warning(Messages.SaveCorpus_5);
+			return false;
+		}
+
+		mainCorpus.setIsModified(false);
+		if (event != null) {
+			HandlerUtil.getActiveShell(event).getDisplay().syncExec(new Runnable() {
+				@Override
+				public void run() {
+					CorporaView.refreshObject(mainCorpus);
+					
+					// find out which editor is using the MainCorpus
+					for (IWorkbenchPage page : TXMWindows.getActiveWindow().getPages()) {
+						for (IEditorReference editor_ref : page.getEditorReferences()) {
+							IEditorPart editor = editor_ref.getEditor(false);
+							if (editor != null && editor instanceof SynopticEditionEditor) {
+								if (mainCorpus.equals(((SynopticEditionEditor)editor).getCorpus())) {
+									((SynopticEditionEditor) editor).fireIsDirty();
+								}
+							}
+						}
+					}
+				}
+			});
+		}
+		return true;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/commands/SaveCorpus.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/preferences/URSPreferences.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/preferences/URSPreferences.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/preferences/URSPreferences.java	(revision 3653)
@@ -0,0 +1,41 @@
+package org.txm.annotation.urs.preferences;
+
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.service.prefs.Preferences;
+import org.txm.core.preferences.TXMPreferences;
+import org.txm.rcp.preferences.RCPPreferences;
+
+public class URSPreferences extends TXMPreferences{
+	
+//	public static final String PREFERENCES_NODE = FrameworkUtil.getBundle(URSPreferences.class).getSymbolicName();
+	
+	public static final String VERSION = "urs.version"; //$NON-NLS-1$
+	public static final String COLOR_PALETTE = "color_palette";
+	public static final String PREFIX_AUTOCOMPLETION = "prefix_autocompletion"; //$NON-NLS-1$
+	public static final String ANALEC_LIMIT_CORRECTION_SCHEME = "urs_limit_correction_scheme"; //$NON-NLS-1$
+	public static final String SAVE_TIMER = "save_timer_duration"; //$NON-NLS-1$
+
+	
+	@Override
+	public void initializeDefaultPreferences() {
+		super.initializeDefaultPreferences();
+		Preferences preferences = DefaultScope.INSTANCE.getNode(getPreferencesNodeQualifier());
+		preferences.put(VERSION, "");
+		preferences.put(COLOR_PALETTE, "green");
+		preferences.putBoolean(ANALEC_LIMIT_CORRECTION_SCHEME, false);
+		preferences.putBoolean(PREFIX_AUTOCOMPLETION, false);
+		preferences.putInt(SAVE_TIMER, 0);
+	}
+	
+	/**
+	 * Gets the instance.
+	 * @return the instance
+	 */
+	public static TXMPreferences getInstance()	{
+		if (!TXMPreferences.instances.containsKey(URSPreferences.class)) {
+			new URSPreferences();
+		}
+		return TXMPreferences.instances.get(URSPreferences.class);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/preferences/URSPreferences.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/preferences/URSSearchPreferencePage.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/preferences/URSSearchPreferencePage.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/preferences/URSSearchPreferencePage.java	(revision 3653)
@@ -0,0 +1,40 @@
+package org.txm.annotation.urs.preferences;
+
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.preferences.ScopedPreferenceStore;
+import org.txm.rcp.Application;
+
+/**
+ * TODO use TXMPreferencesPage
+ * 
+ * @author mdecorde
+ *
+ */
+public class URSSearchPreferencePage extends FieldEditorPreferencePage
+		implements IWorkbenchPreferencePage {
+	
+	ScopedPreferenceStore preferences;
+	
+	
+	public URSSearchPreferencePage() {
+		super();
+		
+		preferences = new ScopedPreferenceStore(org.eclipse.core.runtime.preferences.InstanceScope.INSTANCE, Application.PLUGIN_ID);
+		setPreferenceStore(preferences);
+	}
+	
+	/**
+	 * Creates the field editors. Field editors are abstractions of the common
+	 * GUI blocks needed to manipulate various types of preferences. Each field
+	 * editor knows how to save and restore itself.
+	 */
+	@Override
+	public void createFieldEditors() {
+		
+	}
+	
+	@Override
+	public void init(IWorkbench workbench) {}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/preferences/URSSearchPreferencePage.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/preferences/URSPreferencePage.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/preferences/URSPreferencePage.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/preferences/URSPreferencePage.java	(revision 3653)
@@ -0,0 +1,76 @@
+package org.txm.annotation.urs.preferences;
+
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.IntegerFieldEditor;
+import org.eclipse.jface.preference.RadioGroupFieldEditor;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.preferences.ScopedPreferenceStore;
+import org.txm.annotation.urs.Messages;
+import org.txm.rcp.preferences.TXMPreferencePage;
+import org.txm.rcp.preferences.TXMPreferenceStore;
+
+public class URSPreferencePage extends TXMPreferencePage implements IWorkbenchPreferencePage {
+	
+	private BooleanFieldEditor analec_limit_scheme_field;
+	
+	private BooleanFieldEditor prefix_autocompletion_field;
+	
+	private IntegerFieldEditor save_timer_field;
+	
+	// public static final String SELECTED_UNIT_COLOR = "selected_unit_color";
+	// private ColorFieldEditor selected_unit_color;
+	// public static final String HIGHLIGHTED_UNIT_COLOR = "hightlighted_unit_color";
+	// private ColorFieldEditor hightlighted_unit_color;
+	
+	ScopedPreferenceStore preferences;
+	
+	public static final String COLOR_PALETTE = "color_palette"; //$NON-NLS-1$
+	
+	private RadioGroupFieldEditor color_palette;
+	
+	/**
+	 * Creates the field editors. Field editors are abstractions of the common
+	 * GUI blocks needed to manipulate various types of preferences. Each field
+	 * editor knows how to save and restore itself.
+	 */
+	@Override
+	public void createFieldEditors() {
+		analec_limit_scheme_field = new BooleanFieldEditor(
+				URSPreferences.ANALEC_LIMIT_CORRECTION_SCHEME, Messages.AnalecPreferencePage_3,
+				getFieldEditorParent());
+		addField(analec_limit_scheme_field);
+		
+		prefix_autocompletion_field = new BooleanFieldEditor(
+				URSPreferences.PREFIX_AUTOCOMPLETION, Messages.AnalecPreferencePage_4,
+				getFieldEditorParent());
+		addField(prefix_autocompletion_field);
+		
+		save_timer_field = new IntegerFieldEditor(
+				URSPreferences.SAVE_TIMER, "Delay between saves/Délai entre les sauvegardes (0 desactivate the timer)",
+				getFieldEditorParent());
+		addField(save_timer_field);
+		
+		// hightlighted_unit_color = new ColorFieldEditor(
+		// HIGHLIGHTED_UNIT_COLOR, "Highlighted units background color",
+		// getFieldEditorParent());
+		// addField(hightlighted_unit_color);
+		//
+		//
+		// selected_unit_color = new ColorFieldEditor(
+		// SELECTED_UNIT_COLOR, "Selected units background color",
+		// getFieldEditorParent());
+		// addField(selected_unit_color);
+		
+		String[][] values = { { "green", "green" }, { "yellow", "yellow" } }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+		color_palette = new RadioGroupFieldEditor(COLOR_PALETTE, Messages.AnalecPreferencePage_9, 2, values, getFieldEditorParent());
+		addField(color_palette);
+	}
+	
+	@Override
+	public void init(IWorkbench workbench) {
+		this.setPreferenceStore(new TXMPreferenceStore(URSPreferences.getInstance().getPreferencesNodeQualifier()));
+		this.setTitle("URS");
+		//this.setImageDescriptor(IndexAdapterFactory.ICON);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/preferences/URSPreferencePage.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/messages.properties
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/messages.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/messages.properties	(revision 3653)
@@ -0,0 +1,276 @@
+
+AnalecPreferencePage_3 = Use Analec scheme to fix unit limits
+
+AnalecPreferencePage_4 = Autocompletion search pattern of field is prefix (instead of infixe)
+
+AnalecPreferencePage_9 = Unit highlight color palette
+
+AnnotationToolbar_0 = No selection found. Aborting.
+
+AnnotationToolbar_6 = ** QueryResult matches size is {0}
+
+AnnotationToolbar_7 = \ query was {0}
+
+DoInstallStep_11 = Previous version of URS macros are moved to: {0}
+
+DoInstallStep_17 = ** Error while coping "org/txm/macro/urs" macro directory in {0}
+
+DoInstallStep_18 = URS post-installation done.
+
+DoInstallStep_2 = URS.DoInstallStep.install()
+
+DoInstallStep_5 = No post-installation of URS to do
+
+DoInstallStep_6 = Post-installing URS version={0}
+
+DoInstallStep_9 = URS previous macro backup directory already exists: {0}. Aborting
+
+EditStructure_0 = Selection is not a corpus: {0}
+
+ExportGlozzCorpus_0 = Selection is not a main corpus: {0}
+
+ExportGlozzCorpus_1 = {0} Glozz export
+
+ExportGlozzCorpus_2 = Canceled.
+
+ExportGlozzCorpus_3 = ** Error while exporting annotations: {0}
+
+ExportTEICorpus_0 = Selection is not a corpus: {0}
+
+ExportTEICorpus_1P0 = {0} annotations export...
+
+ExportTEICorpus_2 = ** Error while exporting corpus.
+
+ExportTEICorpus_3 = ** Error while exporting corpus to XML-URS: {0}
+
+ImportGlozzAnnotations_0 = The "aa", "aam" and "ac" files must exists.
+
+ImportGlozzAnnotations_1 = Selection is not a main corpus: {0}
+
+ImportGlozzAnnotations_10 = Done.
+
+ImportGlozzAnnotations_2 = Importing Glozz model from: {0}
+
+ImportGlozzAnnotations_3 = Error while importing Glozz model.
+
+ImportGlozzAnnotations_4 = Importing Glozz corpus from: {0}  and {1} 
+
+ImportGlozzAnnotations_6 = ** Error while importing Glozz corpus.
+
+ImportGlozzAnnotations_7 = Reindexing annotations with TXM words
+
+ImportGlozzAnnotations_8 = ** Error while re-indexing URS annotations.
+
+ImportGlozzAnnotations_9 = Saving annotations.
+
+ImportGlozzCorpus_0 = The {0} glozz directory must exists.
+
+ImportGlozzCorpus_1 = Creating source directory: {0}
+
+ImportGlozzCorpus_10 = Error in {0}: the number of aa files differs from the number of ac files.
+
+ImportGlozzCorpus_11 = Importing Glozz data from: {0}
+
+ImportGlozzCorpus_15 = ** Error while importing Glozz data.
+
+ImportGlozzCorpus_17 = ** Could not create the {0} TXT source file
+
+ImportGlozzCorpus_19 = ** Error: could not save import configuration: {0}
+
+ImportGlozzCorpus_22 = ** no {1} script found for import name {0}
+
+ImportGlozzCorpus_23 = Error during import
+
+ImportGlozzCorpus_24 = Finalizing Analec corpus import
+
+ImportGlozzCorpus_25 = Importing Glozz model from: {0}
+
+ImportGlozzCorpus_26 = Error while importing Glozz model.
+
+ImportGlozzCorpus_27 = Reindexing annotations with TXM words.
+
+ImportGlozzCorpus_28 = error while re-indexing Analec annotations.
+
+ImportGlozzCorpus_29 = Saving annotations.
+
+ImportGlozzCorpus_3 = Creating ec directory: {0}
+
+ImportGlozzCorpus_30 = Done.
+
+ImportGlozzCorpus_32 = Error while finalizing corpus import: {0}
+
+ImportGlozzCorpus_4 = Could not create the {0} source directory.
+
+ImportGlozzCorpus_5 = Could not create the {0} ec directory 
+
+ImportGlozzCorpus_8 = No .aa files found in {0}
+
+ImportGlozzCorpus_9 = No .ac files found in {0}
+
+ImportTEIAnnotations_0 = Selection is not a corpus: {0}
+
+ImportTEIAnnotations_1 = {0} annotations import...
+
+ImportTEIAnnotations_2 = Error while importing annotations.
+
+ImportTEIAnnotations_3 = Error while importing annotations: {0}
+
+ImportTEIAnnotations_5 = Done: {0} unites, {1} relations and {2} schemas.
+
+ImportTEICorpus_0 = ** The XML files must exists: {0}
+
+ImportTEICorpus_11 = ** could not save import configuration: {0}
+
+ImportTEICorpus_14 = ** no script found for import name {0}: {1}
+
+ImportTEICorpus_15 = ** Error during import
+
+ImportTEICorpus_16 = Finalize Analec corpus import
+
+ImportTEICorpus_18 = Importing TEI model from: {0}
+
+ImportTEICorpus_19 = Error while importing TEI model.
+
+ImportTEICorpus_2 = Creating source directory: {0}
+
+ImportTEICorpus_20 = Reindexing annotations with TXM words.
+
+ImportTEICorpus_21 = Error while re-indexing Analec annotations.
+
+ImportTEICorpus_22 = Saving annotations.
+
+ImportTEICorpus_23 = Done.
+
+ImportTEICorpus_24 = Error while finalizing corpus import: {0}
+
+ImportTEICorpus_3 = ** Could not create the {0} source directory 
+
+ImportTEICorpus_5 = Importing TEI data from: {0}
+
+ImportTEICorpus_7 = Error while importing TEI data.
+
+ImportTEICorpus_9 = Could not create the TXT source file {0}
+
+LoadCorpus_0 = Selection is not a main corpus: {0}
+
+LoadCorpus_1 = Loading corpus from file...
+
+LoadCorpus_2 = The EC files must exists.
+
+LoadCorpus_3 = Loading corpus from the {0} file
+
+LoadCorpus_4 = Fail to load structure.
+
+LoadCorpus_5 = Done: 
+
+LoadStructureFromGlozz_0 = Selection is not a main corpus: {0}
+
+LoadStructureFromGlozz_1 = Importing Glozz model for the {0} corpus
+
+LoadStructureFromGlozz_2 = The AAM file must exists.
+
+LoadStructureFromGlozz_3 = Fail to load structure from Glozz model.
+
+LoadStructureFromGlozz_4 = Done.
+
+LoadStructure_0 = Selection is not a main corpus: {0}
+
+LoadStructure_1 = Loading structure for the {0} corpus
+
+LoadStructure_2 = Fail to load structure.
+
+LoadStructure_3 = Done: 
+
+LoadVue_0 = Selection is not a main corpus: {0}
+
+LoadVue_1 = Loading vue for the {0} corpus
+
+LoadVue_2 = Fail to load structure.
+
+LoadVue_3 = Done: 
+
+NavigationField_0 = <identifier>
+
+NavigationField_2 = Wrong unit ID: {0}
+
+NavigationField_4 = Search units by properties
+
+NavigationField_5 = <identifier>
+
+SaveCorpus_0 = Selection is not a main corpus ({0})
+
+SaveCorpus_3 = Saving the annotations ({0}, {1})
+
+SaveCorpus_5 = Error while saving the corpus.
+
+SaveStructureAsGlozzModel_0 = Selection is not a main corpus: {0}
+
+SaveStructureAsGlozzModel_1 = Saving the {0} corpus annotation structure as Glozz model
+
+SaveStructureAsGlozzModel_2 = Error while saving the structure.
+
+SaveStructureAsGlozzModel_3 = Done.
+
+SaveStructure_0 = Selection is not a main corpus: {0}
+
+SaveStructure_3 = Saving the annotation structure of the {0} corpus at {1}
+
+SaveStructure_5 = Error while saving the structure.
+
+SaveVue_0 = Selection is not a main corpus: {0}
+
+SaveVue_3 = Saving the {0} corpus vue at {1} 
+
+SaveVue_5 = Error while saving the vue.
+
+StartButton_0 = Units
+
+StartButton_1 = Schemas
+
+StartButton_11 = Save and close annotation tools: 
+
+StartButton_12 = Start URS annotation
+
+StartButton_4 = Error: corpus not saved.
+
+StartButton_5 = Done.
+
+URSCorpora_3 = Fail to open corpus file: {0}
+
+URSCorpora_4 = Fail to create corpus file: {0} 
+
+UnitToolbar_10 = Delete
+
+UnitToolbar_12 = Click to fix the left limit
+
+UnitToolbar_14 = Fix the left and right limits with a new word selection
+
+UnitToolbar_16 = Click the word to fix the right limit
+
+UnitToolbar_27 = You must select a word. Try again!
+
+UnitToolbar_28 = An error occurred when updating unit limits with the {0} id
+
+UnitToolbar_29 = Select {0}
+
+UnitToolbar_3 = ** Could not retrieve {0} size. Error: {1}
+
+UnitToolbar_32 = Select {0}...
+
+UnitToolbar_44 = Creating unit with start={0} end={0}
+
+UnitToolbar_47 = Delete unit {0}
+
+UnitToolbar_48 = Do you really want to delete unit {0} ?
+
+UnitToolbar_5 = Unit type: {0}
+
+UnitToolbar_54 = < Unit type >
+
+UnitToolbar_59 = Error no word found for the {0} identifier
+
+UnitToolbar_6 = Unit type
+
+UnitToolbar_7 = Unit type
+
+UnitToolbar_8 = Create

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/messages.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/UnitConcordanceToolbar.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/UnitConcordanceToolbar.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/UnitConcordanceToolbar.java	(revision 3653)
@@ -0,0 +1,758 @@
+package org.txm.annotation.urs.toolbar;
+
+import java.io.File;
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Vector;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.bindings.keys.KeyStroke;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.fieldassist.ComboContentAdapter;
+import org.eclipse.jface.fieldassist.TXMAutoCompleteField;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.TypedEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.txm.annotation.rcp.editor.AnnotationArea;
+import org.txm.annotation.rcp.editor.AnnotationExtension;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.concordance.core.functions.Concordance;
+import org.txm.concordance.core.functions.Line;
+import org.txm.concordance.rcp.editors.ConcordanceEditor;
+import org.txm.concordance.rcp.editors.ConcordanceEditor.ConcordanceColumnSizeControlListener;
+import org.txm.core.results.TXMResult;
+import org.txm.objects.Match;
+import org.txm.rcp.IImageKeys;
+import org.txm.rcp.editors.TXMEditor;
+import org.txm.rcp.messages.TXMUIMessages;
+import org.txm.rcp.swt.GLComposite;
+import org.txm.rcp.swt.provider.SimpleLabelProvider;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.searchengine.cqp.corpus.CQPCorpus;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.elements.Unite;
+import visuAnalec.vue.Vue;
+
+public class UnitConcordanceToolbar extends AnnotationArea {
+	
+	/**
+	 * the limit number of annotation when a confirm dialog box is shown
+	 */
+	protected static final int NALERTAFFECTANNOTATIONS = 100;
+	
+	public static final String EMPTYTEXT = ""; //$NON-NLS-1$
+	
+	protected ConcordanceEditor editor;
+	
+	/**
+	 * All available annotation types
+	 */
+	protected List<String> typeValuesList;
+	
+	/**
+	 * display the annotation values of the current shown concordance lines
+	 */
+	protected TableColumn annotationColumn;
+	
+	protected ComboViewer annotationTypesCombo;
+	
+	/** add a new type of annotation */
+	private Button addAnnotationTypeButton;
+	
+	protected Label equalLabel;
+	
+	protected Combo annotationValuesText;
+	
+	protected Button affectAnnotationButton;
+	
+	protected Button deleteAnnotationButton;
+	
+	private Button affectAllAnnotationButton;
+	
+	protected Vector<String> typesList = new Vector<>();
+	
+	protected Concordance concordance;
+	
+	private CQPCorpus corpus;
+	
+	private TableViewerColumn annotationColumnViewer;
+	
+	private Font annotationColummnFont;
+	
+	private Font defaultColummnFont;
+	
+	private Corpus annotManager;
+	
+	private HashMap<Line, ArrayList<Unite>> annotations;
+	
+	protected String unitType;
+	
+	protected String unitProperty;
+	
+	private ComboViewer annotationPropertiesCombo;
+	
+	private Vue vue;
+	
+	@Override
+	public String getName() {
+		return "Annotation d'Unité URS";
+	}
+	
+	@Override
+	public boolean allowMultipleAnnotations() {
+		return true;
+	}
+	
+	public UnitConcordanceToolbar() {}
+	
+	@Override
+	public boolean install(TXMEditor<? extends TXMResult> txmeditor, AnnotationExtension ext, Composite parent, int position) throws Exception {
+		
+		this.extension = ext;
+		this.editor = (ConcordanceEditor) txmeditor;
+		this.concordance = this.editor.getConcordance();
+		this.corpus = concordance.getCorpus();
+		this.annotations = new HashMap<>();
+		this.annotManager = URSCorpora.getCorpus(corpus);
+		this.vue = URSCorpora.getVue(corpus);
+		
+		TableViewer viewer = this.editor.getLineTableViewer();
+		
+		// RESULT
+		if (position < 0) {
+			position = 3 + extension.getNumberOfAnnotationArea(); // after keyword column and previous annotation columns
+		}
+		
+		if (annotManager.getStructure().isVide()) {
+			annotManager.ajouterType(Unite.class, "Entity");
+			annotManager.ajouterProp(Unite.class, "Entity", "Property");
+		}
+		
+		typesList.clear();
+		
+		for (String type : this.annotManager.getStructure().getUnites()) {
+			typesList.add(type);
+		}
+		if (typesList.size() > 0) {
+			this.unitType = typesList.get(0);
+		}
+		
+		annotationColumnViewer = new TableViewerColumn(viewer, SWT.CENTER, position);
+		annotationColumn = annotationColumnViewer.getColumn();
+		annotationColumn.setText("Unit");
+		annotationColumn.setToolTipText("Unit (URS)");
+		annotationColumn.setAlignment(SWT.CENTER);
+		annotationColumn.pack();
+		annotationColumn.setResizable(true);
+		annotationColumn.addControlListener(new ConcordanceColumnSizeControlListener(annotationColumn));
+		defaultColummnFont = editor.getContainer().getFont();
+		FontData fdata = defaultColummnFont.getFontData()[0];
+		annotationColummnFont = new Font(Display.getCurrent(), fdata.getName(), fdata.getHeight(), SWT.ITALIC);
+		annotationColumnViewer.setLabelProvider(new ColumnLabelProvider() {
+			
+			@Override
+			public String getText(Object element) {
+				Line line = (Line) element;
+				ArrayList<Unite> a = annotations.get(line);
+				if (a == null || a.size() == 0) return "<none>";
+				
+				StringBuffer buffer = new StringBuffer();
+				for (Unite unite : a) {
+					if (unitProperty.length() > 0) {
+						String value = unite.getProp(unitProperty);
+						
+						if (value != null) {
+							if (unite.getDeb() < line.matchGetStart() - line.getLeftContextSize()) {
+								value = "… " + value; //$NON-NLS-1$
+							}
+							
+							if (unite.getFin() > line.matchGetEnd() + line.getRightContextSize()) {
+								value = value + " …"; //$NON-NLS-1$
+							}
+							if (buffer.length() > 0) buffer.append(", ");
+							buffer.append(value);
+						}
+					}
+					else {
+						buffer.append(unite.getProps().toString());
+					}
+				}
+				return buffer.toString();
+			}
+		});
+		
+		annotationArea = new GLComposite(parent, SWT.NONE, "Unit URS");
+		annotationArea.getLayout().numColumns = 12;
+		annotationArea.getLayout().horizontalSpacing = 2;
+		annotationArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+		
+		GridData gdata = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+		gdata.widthHint = 90;
+		
+		Label typeLabel = new Label(annotationArea, SWT.NONE);
+		typeLabel.setText("Type"); //$NON-NLS-1$
+		typeLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		
+		
+		// UNIT TYPE
+		annotationTypesCombo = new ComboViewer(annotationArea, SWT.SINGLE);
+		annotationTypesCombo.setContentProvider(new ArrayContentProvider());
+		annotationTypesCombo.setLabelProvider(new SimpleLabelProvider());
+		annotationTypesCombo.getCombo().addKeyListener(new KeyListener() {
+			
+			@Override
+			public void keyReleased(KeyEvent e) {
+				if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+					String name = annotationTypesCombo.getCombo().getText();
+					if (typesList.contains(name)) {
+						StructuredSelection selection = new StructuredSelection(name);
+						annotationTypesCombo.setSelection(selection, true);
+					}
+					else {
+						createNewType(e, name);
+					}
+				}
+			}
+			
+			@Override
+			public void keyPressed(KeyEvent e) {}
+		});
+		
+		gdata = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+		gdata.widthHint = 200;
+		
+		annotationTypesCombo.getCombo().setLayoutData(gdata);
+		annotationTypesCombo.setInput(typesList);
+		annotationTypesCombo.getCombo().select(0);
+		
+		annotationTypesCombo.addSelectionChangedListener(new ISelectionChangedListener() {
+			
+			@Override
+			public void selectionChanged(SelectionChangedEvent event) {
+				onAnnotationTypeSelected(event);
+			}
+		});
+		
+		// WITH
+		
+		equalLabel = new Label(annotationArea, SWT.NONE);
+		equalLabel.setText("with"); //$NON-NLS-1$
+		equalLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		
+		// PROPERTY
+		annotationPropertiesCombo = new ComboViewer(annotationArea, SWT.SINGLE|SWT.READ_ONLY);
+		annotationPropertiesCombo.setContentProvider(new ArrayContentProvider());
+		annotationPropertiesCombo.setLabelProvider(new SimpleLabelProvider());
+		annotationPropertiesCombo.getCombo().addKeyListener(new KeyListener() {
+			
+			@Override
+			public void keyReleased(KeyEvent e) {
+				if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+					String name = annotationTypesCombo.getCombo().getText();
+					if (typesList.contains(name)) {
+						StructuredSelection selection = new StructuredSelection(name);
+						annotationTypesCombo.setSelection(selection, true);
+					}
+					else {
+						createNewType(e, name);
+					}
+				}
+			}
+			
+			@Override
+			public void keyPressed(KeyEvent e) {}
+		});
+		
+		gdata = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+		gdata.widthHint = 200;
+		
+		annotationPropertiesCombo.getCombo().setLayoutData(gdata);
+		ArrayList<String> properties = new ArrayList<>();
+		properties.add(""); // to manage the unit itself
+		properties.addAll(annotManager.getStructure().getNomsProps(Unite.class, unitType));
+		annotationPropertiesCombo.setInput(properties);
+		annotationPropertiesCombo.getCombo().select(0);
+		
+		annotationPropertiesCombo.addSelectionChangedListener(new ISelectionChangedListener() {
+			
+			@Override
+			public void selectionChanged(SelectionChangedEvent event) {
+				onAnnotationPropertySelected(event);
+			}
+		});
+		
+		equalLabel = new Label(annotationArea, SWT.NONE);
+		equalLabel.setText("="); //$NON-NLS-1$
+		equalLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		
+		annotationValuesText = new Combo(annotationArea, SWT.BORDER);
+		annotationValuesText.setToolTipText("available values");
+		GridData gdata2 = new GridData(SWT.FILL, SWT.CENTER, false, false);
+		gdata2.widthHint = 200;
+		annotationValuesText.setLayoutData(gdata2);
+		annotationValuesText.addKeyListener(new KeyListener() {
+			
+			@Override
+			public void keyReleased(KeyEvent e) {
+				if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+					affectAnnotationToSelection(editor.getLineTableViewer().getSelection());
+				}
+			}
+			
+			@Override
+			public void keyPressed(KeyEvent e) {}
+		});
+		
+		
+		affectAnnotationButton = new Button(annotationArea, SWT.PUSH);
+		affectAnnotationButton.setText("OK");
+		affectAnnotationButton.setToolTipText("Create unit for each selected line.");
+		affectAnnotationButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		affectAnnotationButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				affectAnnotationToSelection(editor.getLineTableViewer().getSelection());
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		affectAllAnnotationButton = new Button(annotationArea, SWT.PUSH);
+		affectAllAnnotationButton.setText("All");
+		affectAllAnnotationButton.setToolTipText("Create unit for all lines.");
+		affectAllAnnotationButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		affectAllAnnotationButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				try {
+					affectMatchesToLines(concordance.getLines());
+				}
+				catch (Exception e1) {
+					// TODO Auto-generated catch block
+					e1.printStackTrace();
+				}
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		deleteAnnotationButton = new Button(annotationArea, SWT.PUSH);
+		deleteAnnotationButton.setText("Delete");
+		deleteAnnotationButton.setToolTipText("Delete unit for each selected line.");
+		deleteAnnotationButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		deleteAnnotationButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				deleteAnnotationValues(editor.getLineTableViewer().getSelection());
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		// affectAllAnnotationButton = new Button(annotationArea, SWT.PUSH);
+		// affectAllAnnotationButton.setText("All");
+		// affectAllAnnotationButton.setToolTipText("Create unit for all lines");
+		// affectAllAnnotationButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		// affectAllAnnotationButton.addSelectionListener(new SelectionListener() {
+		//
+		// @Override
+		// public void widgetSelected(SelectionEvent e) {
+		//
+		// try {
+		// // List<? extends Match> matches = concordance.getMatches();
+		// affectMatchesToLines(concordance.getLines());
+		// }
+		// catch (Exception e1) {
+		// Log.severe(NLS.bind("** Error: {0}", e1.getLocalizedMessage()));
+		// Log.printStackTrace(e1);
+		// return;
+		// }
+		// }
+		//
+		// @Override
+		// public void widgetDefaultSelected(SelectionEvent e) {}
+		// });
+		
+		Button closeButton = new Button(annotationArea, SWT.PUSH);
+		closeButton.setToolTipText("End URS annotation");
+		closeButton.setLayoutData(new GridData(GridData.END, GridData.CENTER, true, false));
+		closeButton.setImage(IImageKeys.getImage(IImageKeys.ACTION_DELETE));
+		
+		closeButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				extension.closeArea(UnitConcordanceToolbar.this, true);
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		onAnnotationTypeSelected(null);
+		
+		editor.layout(true);
+//		ext.getSaveButton().setEnabled(true);
+		return true;
+	}
+	
+	private void updateAnnotationWidgetStates() {
+		annotationValuesText.setEnabled(unitProperty.length() > 0);
+	}
+	
+	protected void affectMatchesToLines(final List<Line> lines) {
+		
+		final String value = annotationValuesText.getText();
+		
+		JobHandler job = new JobHandler("Creating units...", true) {
+			
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				this.runInit(monitor);
+				try {
+					if (lines.size() == 0) return Status.CANCEL_STATUS;
+					
+					for (Line l : lines) {
+						
+						Match m = l.getMatch();
+						if (annotations.containsKey(l)) { // update existing unites
+							
+							if (unitProperty.length() > 0) {
+								ArrayList<Unite> unites = annotations.get(l);
+								for (Unite u : unites) {
+									u.getProps().put(unitProperty, value);
+								}
+							}
+						}
+						else {
+							ArrayList<Unite> lineUnites = new ArrayList<>();
+							annotations.put(l, lineUnites);
+							
+							HashMap<String, String> props = new HashMap<>();
+							if (unitProperty.length() > 0) {
+								props.put(unitProperty, value);
+							}
+							
+							lineUnites.add(annotManager.addUniteSaisie(unitType, m.getStart(), m.getEnd(), props));
+						}
+					}
+					
+					editor.getLineTableViewer().getTable().getDisplay().syncExec(new Runnable() {
+						
+						@Override
+						public void run() {
+							editor.getLineTableViewer().refresh();
+						}
+					});
+					
+				}
+				catch (Exception e) {
+					Log.severe(NLS.bind("** Error: {0}", e));
+					Log.printStackTrace(e);
+					return Status.CANCEL_STATUS;
+				}
+				catch(ThreadDeath ex) {
+					Log.info(TXMUIMessages.executionCanceled);
+					return Status.CANCEL_STATUS;
+				}
+				
+				return Status.OK_STATUS;
+			}
+		};
+		job.startJob(true);
+	}
+	
+	protected void deleteAnnotationValues(ISelection selection) {
+		final IStructuredSelection lineSelection = (IStructuredSelection) selection;
+		List<Line> lines = lineSelection.toList();
+		if (lines.size() == 0) return;
+		
+		if (unitProperty.length() > 0) {
+			for (Line l : lines) {
+				if (!annotations.containsKey(l)) continue;
+				
+				for (Unite u : annotations.get(l)) {
+					u.getProps().remove(unitProperty);
+				}
+			}
+		}
+		else { // remove the units
+			for (Line l : lines) {
+				if (!annotations.containsKey(l)) continue;
+				for (Unite u : annotations.get(l)) {
+					annotManager.supUnite(u);
+				}
+				
+				annotations.remove(l);
+			}
+		}
+		
+		editor.getLineTableViewer().refresh();
+	}
+	
+	protected void affectAnnotationToSelection(ISelection selection) {
+		
+		final IStructuredSelection lineSelection = (IStructuredSelection) selection;
+		List<Line> lines = lineSelection.toList();
+		// ArrayList<Match> matches = new ArrayList<>();
+		// for (Line l : lines) {
+		// matches.add(l.getMatch());
+		// }
+		
+		affectMatchesToLines(lines);
+	}
+	
+	protected void onAnnotationPropertySelected(SelectionChangedEvent event) {
+		
+		IStructuredSelection sel = (IStructuredSelection) annotationPropertiesCombo.getSelection();
+		String type = (String) sel.getFirstElement();
+		if (type == null) return;
+		
+		unitProperty = type;
+		
+		if (unitProperty.length() > 0) {
+			annotationColumn.setText(unitType + "@" + unitProperty);
+		}
+		else {
+			annotationColumn.setText(unitType);
+		}
+		
+		setAvailableValues();
+		
+		try {
+			editor.refresh(false);
+		}
+		catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+		updateAnnotationWidgetStates();
+	}
+	
+	private void setAvailableValues() {
+		if (unitType.length() == 0) {
+			annotationValuesText.setItems(new String[0]);
+		}
+		else {
+			String[] items = vue.getValeursChamp(Unite.class, unitType, unitProperty);
+			Arrays.sort(items, Collator.getInstance(Locale.getDefault()));
+			annotationValuesText.setItems(items);
+			KeyStroke keys = KeyStroke.getInstance(SWT.CONTROL, SWT.SPACE);
+			new TXMAutoCompleteField(annotationValuesText, new ComboContentAdapter(), items, keys);
+		}
+	}
+	
+	protected void onAnnotationTypeSelected(SelectionChangedEvent event) {
+		IStructuredSelection sel = (IStructuredSelection) annotationTypesCombo.getSelection();
+		String type = (String) sel.getFirstElement();
+		if (type == null) return;
+		
+		unitType = type;
+		annotationColumn.setText(type);
+		
+		ArrayList<String> properties = new ArrayList<>();
+		properties.add(""); // to mange the unit itself
+		properties.addAll(annotManager.getStructure().getNomsProps(Unite.class, unitType));
+		annotationPropertiesCombo.setInput(properties);
+		annotationPropertiesCombo.getCombo().select(0);
+		
+		onAnnotationPropertySelected(event);
+	}
+	
+	protected void createNewType(TypedEvent e, String typeName) {
+		
+		if (typeName == null) typeName = ""; //$NON-NLS-1$
+		if (typesList.contains(typeName)) return;
+		
+		InputDialog dialog = new InputDialog(e.widget.getDisplay().getActiveShell(), "Nouveau type d'unite", "avec le nom", typeName, null);
+		if (dialog.open() == InputDialog.OK) {
+			String name = dialog.getValue();
+			if (name.trim().length() == 0) return;
+			
+			annotManager.getStructure().ajouterType(Unite.class, name);
+			typesList.add(name);
+			annotationTypesCombo.refresh();
+			StructuredSelection selection = new StructuredSelection(name);
+			annotationTypesCombo.setSelection(selection, true);
+			
+		}
+		else {
+			Log.info("Creation aborted.");
+		}
+	}
+	
+	
+	@Override
+	public boolean save() {
+		// System.out.println();
+		Log.info("Saving URS annotation...");
+		if (URSCorpora.saveCorpus(corpus)) {
+			Log.info("Done in ("+new File(corpus.getProjectDirectory(), "analec/"+corpus.getName()+".ec")+")");
+			return true;
+		} else {
+			Log.warning("Error: URS annotation not saved.");
+			return false;
+		}
+	}
+	
+	@Override
+	public boolean hasChanges() {
+		return annotManager.isModifie();
+	}
+	
+	@Override
+	public boolean notifyEndOfCompute() throws Exception {
+		return true;
+	}
+	
+	@Override
+	public boolean isAnnotationEnable() {
+		return annotationArea != null;
+	}
+	
+	@Override
+	public void notifyStartOfRefresh() throws Exception {
+		List<Line> lines = concordance.getLines(concordance.getTopIndex(), concordance.getTopIndex() + concordance.getNLinePerPage());
+		annotations.clear();
+		
+		ArrayList<Unite> units = annotManager.getUnites(unitType);
+		
+		// int iUnit = 0;
+		// int iLine = 0;
+		// for (; iUnit < units.size() && iLine < lines.size();) {
+		// Line line = lines.get(iLine);
+		// Unite unite = units.get(iUnit);
+		// if (unite.getFin() < line.getMatch().getStart()) {
+		// iUnit++;
+		// } else if (line.getMatch().getEnd() < unite.getDeb()) {
+		// iLine++;
+		// } else {
+		// annotations.put(line, unite);
+		// iLine++;
+		// }
+		// }
+		for (Line line : lines) {
+			ArrayList<Unite> lineUnites = new ArrayList<>();
+			
+			for (int iUnit = 0; iUnit < units.size(); iUnit++) {
+				
+				Unite unite = units.get(iUnit);
+				if (unite.getFin() < line.getMatch().getStart()) {
+					continue;
+				}
+				else if (line.getMatch().getEnd() < unite.getDeb()) {
+					break; // no need to go further
+				}
+				else {
+					lineUnites.add(unite);
+				}
+			}
+			if (lineUnites.size() > 0) {
+				annotations.put(line, lineUnites);
+			}
+		}
+		
+		updateAnnotationWidgetStates();
+		
+		// update annotation column width
+		if (annotationArea != null) {
+			annotationColumn.pack();
+			
+			annotationColumn.setResizable(true);
+		}
+		else {
+			annotationColumn.setWidth(0);
+		}
+	}
+	
+	@Override
+	protected void _close() {
+		if (!annotationColumn.isDisposed()) annotationColumn.dispose();
+		if (!annotationArea.isDisposed()) annotationArea.dispose();
+		extension.layout();
+	}
+	
+	@Override
+	public void notifyEndOfRefresh() throws Exception {
+		// TODO Auto-generated method stub
+	}
+	
+	@Override
+	public void notifyStartOfCreatePartControl() throws Exception {
+		// TODO Auto-generated method stub
+	}
+	
+	public void notifyEndOfCreatePartControl() throws Exception {
+		// TODO Auto-generated method stub
+	}
+	
+	@Override
+	public Class<? extends TXMResult> getAnnotatedTXMResultClass() {
+		return Concordance.class;
+	}
+	
+	@Override
+	public boolean isDirty() {
+		return annotManager.isModifie();
+	}
+	
+	@Override
+	public boolean discardChanges() {
+		return false;
+	}
+	
+	@Override
+	public boolean needToUpdateIndexes() {
+		return false;
+	}
+	
+	@Override
+	public boolean notifyStartOfCompute() throws Exception {
+		return true;
+	}
+
+	@Override
+	public boolean needToUpdateEditions() {
+		
+		return false;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/UnitConcordanceToolbar.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/UnitToolbar.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/UnitToolbar.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/UnitToolbar.java	(revision 3653)
@@ -0,0 +1,1279 @@
+package org.txm.annotation.urs.toolbar;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.eclipse.jface.util.Util;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.ProgressEvent;
+import org.eclipse.swt.browser.ProgressListener;
+import org.eclipse.swt.events.DragDetectListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MenuEvent;
+import org.eclipse.swt.events.MenuListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.txm.annotation.rcp.editor.AnnotationExtension;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.annotation.urs.preferences.URSPreferences;
+import org.txm.annotation.urs.view.ElementPropertiesView;
+import org.txm.annotation.urs.widgets.NavigationField;
+import org.txm.core.messages.TXMCoreMessages;
+import org.txm.core.preferences.TXMPreferences;
+import org.txm.core.results.TXMResult;
+import org.txm.edition.rcp.editors.EditionPanel;
+import org.txm.edition.rcp.editors.RGBA;
+import org.txm.objects.Edition;
+import org.txm.objects.Page;
+import org.txm.objects.Project;
+import org.txm.objects.Text;
+import org.txm.rcp.IImageKeys;
+import org.txm.rcp.editors.TXMEditor;
+import org.txm.rcp.swt.dialog.ConfirmDialog;
+import org.txm.searchengine.cqp.AbstractCqiClient;
+import org.txm.searchengine.cqp.CQPSearchEngine;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.corpus.Property;
+import org.txm.searchengine.cqp.corpus.QueryResult;
+import org.txm.searchengine.cqp.corpus.query.Match;
+import org.txm.searchengine.cqp.corpus.query.CQLQuery;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.Message;
+import visuAnalec.Message.TypeMessage;
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.Element;
+import visuAnalec.elements.Unite;
+
+public class UnitToolbar extends URSAnnotationToolbar {
+	
+	// boolean AnalecUnitLimitCorrectionScheme = TxmPreferences.getBoolean(AnalecPreferencePage.ANALEC_LIMIT_CORRECTION_SCHEME); // use Analec scheme to fix unit limits or TXM's
+	
+	public RGBA highlighted_unit_color = new RGBA(183, 191, 237, 0.7f);
+	
+	public RGBA selected_unit_color = new RGBA(255, 255, 0, 0.5f);
+	
+	private Button createButton;
+	
+	private Button deleteButton;
+	
+	private Button editButton;
+	
+	private KeyListener editorKeyListener;
+	
+	private MouseListener editorMouseListener;
+	
+	private int fixingAnnotationLimits = 0;
+	
+	private NavigationField navigationField;
+	
+	private Label l;
+	
+	private MenuListener menuListener;
+	
+	private List<String> previousSelectedTypeUnitIDS;
+	
+	private List<String> previousSelectedUnitIDS;
+	
+	protected boolean startFixingUnitLimit;
+	
+	private Combo typeCombo;
+	
+	private Unite[] unites;
+	
+	private String[] typesUnitesAVoir;
+	
+	private int maxCorpusPosition;
+	
+	private DragDetectListener dragDetectListener;
+	
+	private Button drop_b;
+	
+	private Button editLeftButton;
+	
+	private Button editRightButton;
+	
+	public UnitToolbar() {}
+	
+	@Override
+	protected boolean _install(TXMEditor<? extends TXMResult> txmeditor, AnnotationExtension extension, Composite parent, int position) throws Exception {
+		
+		annotationArea.getLayout().numColumns = 11;
+		annotationArea.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+		
+		String color_palette = URSPreferences.getInstance().getString(URSPreferences.COLOR_PALETTE);
+		if ("yellow".equals(color_palette)) { //$NON-NLS-1$
+			this.highlighted_unit_color = URSAnnotationToolbar.lightyellow;
+			this.selected_unit_color = URSAnnotationToolbar.yellow;
+		}
+		else if ("green".equals(color_palette)) { //$NON-NLS-1$
+			this.highlighted_unit_color = URSAnnotationToolbar.lightgreen;
+			this.selected_unit_color = URSAnnotationToolbar.green;
+		}
+		else { // custom palette
+			// String highlighted_unit_color_pref = TxmPreferences.get(AnalecPreferencePage.HIGHLIGHTED_UNIT_COLOR, "255,255,176");
+			// String selected_unit_color_pref = TxmPreferences.get(AnalecPreferencePage.SELECTED_UNIT_COLOR, "255,255,96");
+			// this.highlighted_unit_color = new RGBA(highlighted_unit_color_pref, 0.7f);
+			// this.selected_unit_color = new RGBA(selected_unit_color_pref, 1f);
+		}
+		
+		//		this.button = extension.getSaveButton();
+		this.maincorpus = this.editor.getCorpus().getMainCorpus();
+		try {
+			maxCorpusPosition = maincorpus.getSize();
+		}
+		catch (Exception e) {
+			Log.warning(NLS.bind(Messages.UnitToolbar_3, maincorpus, e.getLocalizedMessage()));
+			Log.printStackTrace(e);
+		}
+		analecCorpus.addEventListener(this);
+		
+		
+		l = new Label(annotationArea, SWT.NONE);
+		l.setText(Messages.UnitToolbar_6);
+		l.setToolTipText(Messages.UnitToolbar_6);
+		l.setLayoutData(new GridData(GridData.CENTER, GridData.CENTER, false, false));
+		
+		typeCombo = new Combo(annotationArea, SWT.NONE | SWT.READ_ONLY);
+		typeCombo.setToolTipText(Messages.UnitToolbar_7);
+		GridData gdata = new GridData(GridData.CENTER, GridData.CENTER, false, false);
+		gdata.minimumWidth = 150;
+		//gdata.widthHint = 100;
+		typeCombo.setSize(150, SWT.DEFAULT);
+		typeCombo.setLayoutData(gdata);
+		typeCombo.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				onTypecomboSelected(e);
+			}
+		});
+		
+		navigationField = new NavigationField(this, SWT.NONE);
+		gdata = new GridData(GridData.FILL, GridData.CENTER, true, false);
+		navigationField.setLayoutData(gdata);
+		navigationField.addListener(SWT.Selection, new Listener() {
+			
+			@Override
+			public void handleEvent(Event event) {
+				onIdentifiantComboSelected(event);
+			}
+		});
+		
+		// l = new Label(this, SWT.NONE);
+		
+		createButton = new Button(annotationArea, SWT.PUSH);
+		createButton.setText(Messages.UnitToolbar_8);
+		gdata = new GridData(GridData.CENTER, GridData.CENTER, false, false);
+		createButton.setLayoutData(gdata);
+		createButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				onCreateButtonSelected(e);
+			}
+		});
+		
+		deleteButton = new Button(annotationArea, SWT.PUSH);
+		gdata = new GridData(GridData.CENTER, GridData.CENTER, false, false);
+		deleteButton.setLayoutData(gdata);
+		deleteButton.setImage(IImageKeys.getImage("platform:/plugin/org.txm.rcp/icons/cross.png")); //$NON-NLS-1$
+		deleteButton.setToolTipText(Messages.UnitToolbar_10);
+		deleteButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				onDeleteComboSelected(e);
+			}
+		});
+		
+		l = new Label(annotationArea, SWT.NONE);
+		
+		editLeftButton = new Button(annotationArea, SWT.TOGGLE);
+		gdata = new GridData(GridData.CENTER, GridData.CENTER, false, false);
+		editLeftButton.setLayoutData(gdata);
+		editLeftButton.setText("[ ↔"); //$NON-NLS-1$
+		editLeftButton.setToolTipText(Messages.UnitToolbar_12);
+		editLeftButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				onEditButtonSelected(e, 1);
+			}
+		});
+		
+		editButton = new Button(annotationArea, SWT.TOGGLE);
+		editButton.setText("[↔]"); //$NON-NLS-1$
+		editButton.setToolTipText(Messages.UnitToolbar_14);
+		editButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				onEditButtonSelected(e);
+			}
+		});
+		
+		editRightButton = new Button(annotationArea, SWT.TOGGLE);
+		editRightButton.setText("↔ ]"); //$NON-NLS-1$
+		editRightButton.setToolTipText(Messages.UnitToolbar_16);
+		editRightButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				onEditButtonSelected(e, 2);
+			}
+		});
+		
+		annotationArea.layout();
+		annotationArea.getParent().layout(true);
+		editor.layout(true);
+		
+		reloadUnits(); // reloads types
+		reloadIdentifiants();
+		
+		createButton.setEnabled(false);
+		deleteButton.setEnabled(false);
+		editButton.setEnabled(false);
+		editLeftButton.setEnabled(false);
+		editRightButton.setEnabled(false);
+		
+		// drop_b.setEnabled(false);
+		if (typesUnitesAVoir.length > 0) {
+			typeCombo.select(1);
+			onTypecomboSelected(null);
+			
+			testIfAwordSpanIsSelected();
+		}
+		
+		ElementPropertiesView.openView();
+		editor.updateWordStyles();
+		annotationArea.layout();
+		return true;
+	}
+	
+	@Override
+	public void clearHighlight() {
+		if (previousSelectedUnitIDS != null) {
+			if (editor.isDisposed()) {
+				editor.removeHighlightWordsById(selected_unit_color, previousSelectedUnitIDS);
+				editor.removeFontWeightWordsById(previousSelectedUnitIDS);
+			}
+			previousSelectedUnitIDS = null; // release memory
+		}
+		if (previousSelectedTypeUnitIDS != null) {
+			editor.removeHighlightWordsById(highlighted_unit_color, previousSelectedTypeUnitIDS);
+			previousSelectedTypeUnitIDS = null; // release memory
+		}
+		
+		if (!createButton.isDisposed()) createButton.setEnabled(false);
+		if (!deleteButton.isDisposed()) deleteButton.setEnabled(false);
+		if (!editButton.isDisposed()) editButton.setEnabled(false);
+		// drop_b.setEnabled(false);
+	}
+	
+	@Override
+	public MouseListener getEditorClickListener() {
+		if (editorMouseListener != null) return editorMouseListener;
+		editorMouseListener = new MouseListener() {
+			
+			boolean dblClick = false;
+			
+			boolean debug = Log.isLoggingFineLevel();
+			
+			private int t, x, y;
+			
+			@Override
+			public void mouseDoubleClick(MouseEvent e) {
+				if (debug) Log.finer("DOUBLE CLICK"); //$NON-NLS-1$
+				dblClick = true;
+				
+				EditionPanel panel = editor.getEditionPanel(0);
+				if (panel == null) return;
+				String[] ids = panel.getWordSelection(); // may be null
+				// System.out.println("word id="+id);
+				// if (id != null) {
+				// org.txm.searchengine.cqp.corpus.Corpus c = UnitToolbar.this.editor.getCorpus();
+				// try {
+				// if (debug) System.out.println(" HIGHLIGHTING ANNOT IF ANY AT "+id);
+				// tryHighlightingWord(id,c );
+				// } catch (Exception ex) {
+				// ex.printStackTrace();
+				// }
+				// }
+				
+				if (ids != null && typeCombo.getSelectionIndex() > 0 && typeCombo.getEnabled()) {
+					createButton.setEnabled(true); // there is a text selection in the browser
+				}
+			}
+			
+			@Override
+			public void mouseDown(MouseEvent e) {
+				if (debug) Log.finer("MOUSE DOWN"); //$NON-NLS-1$
+				dblClick = false;
+				t = e.time;
+				x = e.x;
+				y = e.y;
+			}
+			
+			@Override
+			public void mouseUp(MouseEvent e) {
+				if (dblClick) { // doucle click raised by mouseDoubleClick
+					dblClick = false;
+					return; // stop right now ! :-o
+				}
+				if (debug) Log.finer("MOUSE UP"); //$NON-NLS-1$
+				EditionPanel panel = editor.getEditionPanel(0);
+				if (panel == null) return;
+				
+				if (typeCombo.getSelectionIndex() <= 0) {
+					createButton.setEnabled(false);
+					deleteButton.setEnabled(false);
+					editLeftButton.setEnabled(false);
+					editButton.setEnabled(false);
+					editRightButton.setEnabled(false);
+					// drop_b.setEnabled(false);
+					return; // nothing to do with annotations
+				}
+				
+				// filter click that are not a left simple click (no drag)
+				// System.out.println("click count="+e.count+" button="+e.button+" time="+e.time+" diff="+(e.time-t)+" dist="+(Math.abs(e.x - x) + Math.abs(e.y - y)));
+				if (e.count > 1) {
+					if (debug) Log.finer(" DOUBLE CLICK"); //$NON-NLS-1$
+					// System.out.println("not a simple click");
+					return;
+				}
+				
+				int dist = Math.abs(e.x - x) + Math.abs(e.y - y);
+				int deltat = (e.time - t);
+				// System.out.println("deltat ="+deltat);
+				if (dist != 0 && (deltat > 120 || dist > 4)) {
+					// System.out.println(" DRAG dist="+dist+" deltat="+deltat);
+					
+					String[] ids = panel.getWordSelection(); // may be null
+					
+					if (fixingAnnotationLimits == 3) { // fixing limit with a mouse drag an drop
+						if (debug) Log.finer(" EDITING ANNOTATION POSITION mode=" + fixingAnnotationLimits); //$NON-NLS-1$
+						onFixingAnnotationLimits(ids);
+						return;
+					}
+					else {
+						
+						testIfAwordSpanIsSelected(ids);
+						
+						// panel.expandSelectionTo(ids);
+						return;
+					}
+				}
+				
+				if (e.button != 1) {
+					if (debug) Log.finer(" NO LEFT"); //$NON-NLS-1$
+					// System.out.println("not a left click");
+					return;
+				}
+				if ((e.time - t) > 200) {
+					if (debug) Log.finer(" LONG"); //$NON-NLS-1$
+					// System.out.println("not a short click");
+					return;
+				}
+				
+				String[] ids = panel.getWordSelection(); // may be null
+				
+				if (fixingAnnotationLimits > 0) {
+					if (debug) Log.finer(" EDITING ANNOTATION POSITION mode=" + fixingAnnotationLimits); //$NON-NLS-1$
+					onFixingAnnotationLimits(ids);
+					return;
+				}
+				
+				if (ids == null) { // clear selection
+					if (debug) Log.finer(" NO WORD SELECTION"); //$NON-NLS-1$
+					navigationField.setSelectionIndex(0); // clear selection
+					
+					return;
+				}
+				
+				org.txm.searchengine.cqp.corpus.CQPCorpus c = UnitToolbar.this.editor.getCorpus();
+				
+				try {
+					if (debug) Log.finer(" HIGHLIGHTING ANNOT IF ANY AT " + ids[0]); //$NON-NLS-1$
+					if (tryHighlightingUnitsWord(ids[0], c)) {
+						editor.updateWordStyles();
+					}
+					else { // a word have been clicked
+						testIfAwordSpanIsSelected(ids);
+						//panel.expandSelectionTo(ids);
+					}
+				}
+				catch (Exception ex) {
+					ex.printStackTrace();
+				}
+			}
+		};
+		return editorMouseListener;
+	}
+	
+	protected void testIfAwordSpanIsSelected() {
+		EditionPanel panel = editor.getEditionPanel(0);
+		if (panel == null) return;
+		String[] ids = panel.getWordSelection(); // may be null
+		testIfAwordSpanIsSelected(ids);
+	}
+	
+	protected void testIfAwordSpanIsSelected(String[] ids) {
+		if (ids != null && typeCombo.getItemCount() > 1 && typeCombo.getEnabled()) {
+			// System.out.println("ids:"+Arrays.toString(ids));
+			if (navigationField.getSelectionIndex() > 0) {
+				deleteButton.setEnabled(true);
+				editLeftButton.setEnabled(true);
+				editButton.setEnabled(true);
+				editRightButton.setEnabled(true);
+				// drop_b.setEnabled(true);
+			}
+			
+			createButton.setEnabled(ids != null);
+		}
+	}
+	
+	
+	
+	protected void onFixingAnnotationLimits(String[] ids) {
+		
+		if (ids == null || ids.length == 0) {
+			Log.info(Messages.UnitToolbar_27);
+			return;
+		}
+		
+		boolean uniteFixed = false;
+		int i = navigationField.getSelectionIndex();
+		if (i > 0) {
+			Unite unite = unites[i - 1];
+			
+			try {
+				uniteFixed = updateUniteLimits(unite, ids, fixingAnnotationLimits);
+			}
+			catch (CqiClientException e1) {
+				Log.warning(NLS.bind(Messages.UnitToolbar_28, ids[0]));
+				Log.printStackTrace(e1);
+			}
+			
+			editButton.setSelection(false);
+			editLeftButton.setSelection(false);
+			editRightButton.setSelection(false);
+			fixingAnnotationLimits = 0;
+			typeCombo.setEnabled(true);
+			
+			navigationField.setEnabled(true);
+			createButton.setEnabled(true);
+			deleteButton.setEnabled(true);
+			
+			if (uniteFixed) {
+				// button.setEnabled(analecCorpus.isModifie());
+				reloadIdentifiants();
+				highlightType();
+				// highlightUnite(unite, true);
+				navigationField.setSelectionIndex(i);
+				// updatePropertiesView(unite); // start-end may have changed
+				return;
+			}
+		}
+	}
+	
+	
+	
+	@Override
+	public KeyListener getEditorKeyListener() {
+		if (editorKeyListener != null) return editorKeyListener;
+		editorKeyListener = new KeyListener() {
+			
+			@Override
+			public void keyPressed(KeyEvent e) {}
+			
+			@Override
+			public void keyReleased(KeyEvent e) {
+				int mask = SWT.CTRL;
+				if (Util.isMac()) mask = SWT.COMMAND;
+				
+				if (((e.stateMask & mask) == mask)) {
+					if (e.keyCode == SWT.SPACE) {
+						int i = navigationField.getSelectionIndex();
+						if (i > 0) {
+							onEditButtonSelected(null);
+						}
+					}
+					else if (e.keyCode == SWT.ARROW_LEFT) {
+						selectPrevious();
+					}
+					else if (e.keyCode == SWT.ARROW_RIGHT) {
+						selectNext();
+						// } else if (e.keyCode == SWT.PAGE_UP) { // clash with Eclipse CTRL+PAGE_UP binding
+						// select10Previous();
+						// } else if (e.keyCode == SWT.PAGE_DOWN) { // clash with Eclipse CTRL+PAGE_DOWN binding
+						// select10Next();
+					}
+					else if (e.keyCode == SWT.END) {
+						selectLast();
+					}
+					else if (e.keyCode == SWT.HOME) {
+						selectFirst();
+					}
+				}
+				else {
+					if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+						onCreateButtonSelected(null);
+					}
+					else if (e.keyCode == SWT.DEL) {
+						int i = navigationField.getSelectionIndex();
+						if (i > 0) {
+							onDeleteComboSelected(e);
+						}
+					}
+				}
+			}
+		};
+		return editorKeyListener;
+	}
+	
+	@Override
+	public MenuListener getMenuListener() {
+		
+		if (menuListener != null) return menuListener;
+		
+		this.menuListener = new MenuListener() {
+			
+			HashSet<MenuItem> entries = new HashSet<>();
+			
+			@Override
+			public void menuHidden(MenuEvent e) {}
+			
+			@Override
+			public void menuShown(MenuEvent e) {
+				
+				EditionPanel panel = editor.getEditionPanel(0);
+				if (panel == null) return;
+				Menu menu = panel.getBrowser().getMenu();
+				
+				for (MenuItem item : entries)
+					item.dispose();
+				
+				String[] ids = panel.getWordSelection();
+				// System.out.println("Word under mouse: "+id);
+				if (ids != null && ids.length > 0) {
+					int[] startend = getSelectionStartEndWordPositions(); // get the word start end positions
+					ArrayList<Unite> unitEntries = new ArrayList<>(); // stores units covering the word
+					ArrayList<Integer> noEntries = new ArrayList<>(); // stores units covering the word
+					int i = 1;
+					for (Unite unit : unites) {
+						if (unit.getDeb() > startend[0]) break; // don't go further
+						if (unit.getFin() < startend[0]) continue;
+						unitEntries.add(unit);
+						noEntries.add(i);
+						i++;
+					}
+					
+					if (unitEntries.size() > 0) {
+						MenuItem item = new MenuItem(menu, SWT.SEPARATOR);
+						entries.add(item);
+					}
+					
+					for (i = 0; i < unitEntries.size(); i++) {
+						final Unite unit = unitEntries.get(i);
+						final Integer unitNo = Arrays.binarySearch(unites, unit) + 1;
+						
+						MenuItem item = new MenuItem(menu, SWT.NONE);
+						AbstractCqiClient CQI = CQPSearchEngine.getCqiClient();
+						try {
+							if (unit.getDeb() == unit.getFin()) {
+								String[] firstWords = CQI.cpos2Str(maincorpus.getWordProperty().getQualifiedName(), new int[] { unit.getDeb() });
+								item.setText(NLS.bind(Messages.UnitToolbar_29, unit.getType() + "-" + unitNo + ":" + firstWords[0])); //$NON-NLS-2$
+							}
+							else {
+								String[] firstWords = CQI.cpos2Str(maincorpus.getWordProperty().getQualifiedName(), new int[] { unit.getDeb(), unit.getDeb() + 1 });
+								item.setText(NLS.bind(Messages.UnitToolbar_32, unit.getType() + "-" + unitNo + "=" + firstWords[0] + " " + firstWords[1])); //$NON-NLS-2$ //$NON-NLS-3$
+							}
+						}
+						catch (Exception e1) {
+							e1.printStackTrace();
+						}
+						item.addSelectionListener(new SelectionListener() {
+							
+							@Override
+							public void widgetDefaultSelected(SelectionEvent e) {}
+							
+							@Override
+							public void widgetSelected(SelectionEvent e) {
+								selectUniteInIdentifants(unit);
+							}
+						});
+						entries.add(item);
+					}
+				}
+			}
+		};
+		
+		return menuListener;
+	}
+	
+	public String uniteToWords(Unite unit) {
+		
+		AbstractCqiClient CQI = CQPSearchEngine.getCqiClient();
+		String[] firstWords = null;
+		try {
+			if (unit.getDeb() == unit.getFin()) {
+				firstWords = CQI.cpos2Str(maincorpus.getWordProperty().getQualifiedName(), new int[] { unit.getDeb() });
+			}
+			else {
+				firstWords = CQI.cpos2Str(maincorpus.getWordProperty().getQualifiedName(), new int[] { unit.getDeb(), unit.getDeb() + 1 });
+			}
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+		}
+		return StringUtils.join(firstWords, " "); //$NON-NLS-1$
+	}
+	
+	/**
+	 * Highlight units of the current page
+	 */
+	protected synchronized void highlightType() {
+		
+		if (unites == null) return;
+		if (editor.getEditionPanels().size() == 0) return;
+		
+		try {
+			Page page = editor.getEditionPanel(0).getCurrentPage();
+			Edition e = page.getEdition();
+			Page next = e.getNextPage(page);
+			String currentPageWordID = page.getWordId();
+			if (currentPageWordID == null || currentPageWordID.length() == 0) return;
+			
+			String qid = maincorpus.getProperty("id").getQualifiedName();
+			int first_ids[] = CQPSearchEngine.getCqiClient().str2Id(qid, new String[] { currentPageWordID });
+			
+			if (first_ids.length == 0) return;
+			
+			int first_id = first_ids[0];
+			if (first_id < 0) return;
+			
+			int last_ids[] = null;
+			if (next != null && next != page) {
+				String nextPageWordID = next.getWordId();
+				if (!("w_0".equals(nextPageWordID))) {
+					last_ids = CQPSearchEngine.getCqiClient().str2Id(qid, new String[] { nextPageWordID });
+					if (last_ids.length == 0 || last_ids[0] == -1) {
+						Log.warning("No CQP id for word id="+nextPageWordID);
+					}
+				}
+			}
+			
+			int first_pos = CQPSearchEngine.getCqiClient().id2Cpos(qid, first_id)[0];
+			int last_pos = Integer.MAX_VALUE;
+			if (last_ids != null && last_ids.length > 0 && last_ids[0] != -1) {
+				int[] v = CQPSearchEngine.getCqiClient().id2Cpos(qid, last_ids[0]);
+				if (v.length == 0) {
+					Log.warning("No position found for CQP id="+last_ids[0]);
+				} else {
+					last_pos = v[0];
+				}
+			}
+			
+			int n2 = 0; // first loop to determine the allpositions array length
+			for (int i = 0; i < unites.length; i++) {
+				for (int p = unites[i].getDeb(); p <= unites[i].getFin(); p++) {
+					if (p >= first_pos && p <= last_pos) {
+						n2++;
+					}
+				}
+			}
+			
+			int allpositions[] = new int[n2];
+			n2 = 0;
+			for (int i = 0; i < unites.length; i++) {
+				for (int p = unites[i].getDeb(); p <= unites[i].getFin(); p++) {
+					if (p >= first_pos && p <= last_pos) {
+						allpositions[n2++] = p;
+					}
+				}
+			}
+			
+			if (previousSelectedTypeUnitIDS != null) {
+				editor.removeHighlightWordsById(highlighted_unit_color, previousSelectedTypeUnitIDS);
+				editor.removeFontWeightWordsById(previousSelectedTypeUnitIDS);
+				previousSelectedTypeUnitIDS = null; // release memory
+			}
+			String ids2[] = CQPSearchEngine.getCqiClient().cpos2Str(maincorpus.getProperty("id").getQualifiedName(), allpositions); //$NON-NLS-1$
+			previousSelectedTypeUnitIDS = Arrays.asList(ids2);
+			
+			editor.addHighlightWordsById(highlighted_unit_color, previousSelectedTypeUnitIDS);
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+	
+	/**
+	 * Highlight a unit and don't focus it
+	 * 
+	 * @param unite
+	 * @param focus if set the edition will focus ONE TIME on the unit
+	 * 
+	 * @return true if the page is changed
+	 */
+	private synchronized boolean highlightUnite(Unite unite, boolean focus, int clickedWordPosition) {
+		int start = unite.getDeb();
+		int end = unite.getFin();
+		// System.out.println("HU: start="+start+" end="+end+" -> "+(end-start+1));
+		int len = end - start + 1;
+		if (len < 0) {
+			Log.warning("Error: can not highlight unit=" + unite + ": start > end."); //$NON-NLS-1$ //$NON-NLS-2$
+			return false;
+		}
+		int positions[] = new int[len]; // build the positions array for CQP
+		int n = 0;
+		for (int p = start; p <= end; p++) {
+			positions[n++] = p;
+		}
+		
+		try {
+			if (previousSelectedUnitIDS != null) { // remove previous highlighted words
+				editor.removeHighlightWordsById(selected_unit_color, previousSelectedUnitIDS);
+				editor.removeFontWeightWordsById(previousSelectedUnitIDS);
+				previousSelectedUnitIDS = null; // release memory
+			}
+			
+			String ids[] = CQPSearchEngine.getCqiClient().cpos2Str(maincorpus.getProperty("id").getQualifiedName(), positions); //$NON-NLS-1$
+			// System.out.println("Highlight words with ids="+Arrays.toString(ids));
+			
+			// positions = new int[]{positions[0]};
+			Property text_id = maincorpus.getStructuralUnit("text").getProperty("id"); //$NON-NLS-1$ //$NON-NLS-2$
+			int[] text_strucs = CQPSearchEngine.getCqiClient().cpos2Struc(text_id.getQualifiedName(), positions);
+			String[] text_ids = CQPSearchEngine.getCqiClient().struc2Str(text_id.getQualifiedName(), text_strucs);
+			
+			String firstWordId = ids[0];
+			String firstWordTextId = text_ids[0];
+			if (clickedWordPosition >= 0 && clickedWordPosition < ids.length) {
+				firstWordId = ids[clickedWordPosition];
+				firstWordTextId = text_ids[clickedWordPosition];
+			}
+			
+			
+			EditionPanel panel = editor.getEditionPanel(0);
+			Edition e = panel.getEdition();
+			Project corpus = e.getText().getProject();
+			// System.out.println("firstWordTextId="+firstWordTextId);
+			Text newText = corpus.getText(firstWordTextId); // get the new text
+			// System.out.println("positions="+Arrays.toString(positions));
+			// System.out.println("firstWordId="+firstWordId);
+			// System.out.println("firstWordTextId="+firstWordTextId);
+			// System.out.println("newText="+newText+" e="+e);
+			Edition newEdition = newText.getEdition(e.getName()); // get the edition of the new text
+			Page newPage = newEdition.getPageForWordId(firstWordId); // find out the page containing the word
+			// System.out.println("page="+p+" current page="+panel.getCurrentPage());
+			
+			previousSelectedUnitIDS = Arrays.asList(ids);
+			editor.addHighlightWordsById(selected_unit_color, previousSelectedUnitIDS);
+			editor.addFontWeightWordsById(EditionPanel.WEIGHT_BOLD, previousSelectedUnitIDS);
+			
+			if (previousSelectedUnitIDS.size() > 0 && focus) {
+				editor.setFocusedWordID(previousSelectedUnitIDS.get(0));
+			}
+			Page cp = panel.getCurrentPage();
+			// System.out.println("Word page= "+p+" current="+panel.getCurrentPage());
+			if (!cp.equals(newPage) || !panel.getCurrentText().equals(newText)) { // do we need to change page ?
+				editor.goToPage(newText.getName(), newPage.getName());
+				return true;
+			}
+		}
+		catch (Exception e1) {
+			e1.printStackTrace();
+		}
+		return false;
+	}
+	
+	protected void onCreateButtonSelected(SelectionEvent e) {
+		// System.out.println("onCreateButtonSelected");
+		int[] startend = getSelectionStartEndWordPositions();
+		if (startend != null) {
+			Log.info(NLS.bind(Messages.UnitToolbar_44, startend[0], startend[1]));
+			Unite unite = UnitToolbar.this.vue.getCorpus().addUniteSaisie(typeCombo.getText(), startend[0], startend[1]);
+			Structure structure = UnitToolbar.this.analecCorpus.getStructure();
+			for (String prop : unite.getProps().keySet())
+				unite.getProps().put(prop, structure.getValeurParDefaut(unite.getClass(), unite.getType(), prop));
+			
+			reloadIdentifiants();
+			selectUniteInIdentifants(unite);
+			// highlightUnite(unite, true, -1);
+			
+			deleteButton.setEnabled(true);
+			editLeftButton.setEnabled(true);
+			editButton.setEnabled(true);
+			editRightButton.setEnabled(true);
+			// drop_b.setEnabled(true);
+			// updatePropertiesView(unite, true);
+			setFocusInPropertiesView();
+			fireIsDirty();
+		}
+		
+		if (e != null) editor.updateWordStyles();
+	}
+	
+	protected void onDeleteComboSelected(Object e) {
+		int i = navigationField.getSelectionIndex();
+		if (i <= 0) return;
+		// System.out.println("Delete unite at i="+i);
+		Unite unite = unites[i - 1];
+		
+		String id = navigationField.getText();
+		
+		ConfirmDialog dialog = new ConfirmDialog(Display.getCurrent().getActiveShell(),
+				"org.txm.annotation.urs.delete",
+				NLS.bind(Messages.UnitToolbar_47, id),
+				NLS.bind(Messages.UnitToolbar_48, id));
+		if (dialog.open() == ConfirmDialog.CANCEL) return;
+		
+		// System.out.println("unite "+unite.toString());
+		UnitToolbar.this.vue.getCorpus().supUnite(unite);
+		reloadIdentifiants();
+		
+		i = typeCombo.getSelectionIndex();
+		if (i > 0) {
+			highlightType();
+		}
+		fireIsDirty();
+		
+		if (e != null) editor.updateWordStyles();
+	}
+	
+	protected void onEditButtonSelected(SelectionEvent e) {
+		onEditButtonSelected(e, 3);
+	}
+	
+	protected void onEditButtonSelected(SelectionEvent e, int mode) {
+		if (mode == 0) { // select unit, select words, click the edit button -> deprecated
+			int i = navigationField.getSelectionIndex();
+			if (i == -1) return;
+			// System.out.println("Delete unite at i="+i);
+			Unite unite = unites[i - 1];
+			int[] startend = getSelectionStartEndWordPositions();
+			if (startend != null) {
+				analecCorpus.modifBornesUnite(unite, startend[0], startend[1]);
+				reloadIdentifiants();
+				highlightUnite(unite, false, -1);
+				updatePropertiesView(unite);
+			}
+		}
+		else {
+			if (fixingAnnotationLimits > 0) {
+				typeCombo.setEnabled(true);
+				navigationField.setEnabled(true);
+				createButton.setEnabled(true);
+				deleteButton.setEnabled(true);
+				fixingAnnotationLimits = 0;
+			}
+			else {
+				typeCombo.setEnabled(false);
+				navigationField.setEnabled(false);
+				createButton.setEnabled(false);
+				deleteButton.setEnabled(false);
+				fixingAnnotationLimits = mode;
+			}
+		}
+		fireIsDirty();
+		if (e != null) editor.updateWordStyles();
+	}
+	
+	/**
+	 * called when the NavigationField changed its selection
+	 * 
+	 * @param e
+	 */
+	public void onIdentifiantComboSelected(Object e) {
+		int i = navigationField.getSelectionIndex();
+		boolean pageChanged = false;
+		if (i <= 0) {
+			if (previousSelectedUnitIDS != null) {
+				editor.removeHighlightWordsById(selected_unit_color, previousSelectedUnitIDS);
+				editor.removeFontWeightWordsById(previousSelectedUnitIDS);
+				previousSelectedUnitIDS = null; // release memory
+			}
+			highlightType();
+			
+			clearPropertiesView(); // unload the selected element if any
+			createButton.setEnabled(false);
+			deleteButton.setEnabled(false);
+			editLeftButton.setEnabled(false);
+			editButton.setEnabled(false);
+			editRightButton.setEnabled(false);
+			// drop_b.setEnabled(false);
+			// navigationField.setSelectionIndex(i);
+		}
+		else {
+			createButton.setEnabled(false);
+			deleteButton.setEnabled(true);
+			editLeftButton.setEnabled(true);
+			editButton.setEnabled(true);
+			editRightButton.setEnabled(true);
+			// drop_b.setEnabled(true);
+			// System.out.println("i="+i);
+			Unite unite = unites[i - 1];
+			// System.out.println("unite="+unite);
+			// System.out.println("unite str="+uniteToWords(unite));
+			pageChanged = highlightUnite(unite, true, -1);
+			
+			updatePropertiesView(unite);
+			deleteButton.setEnabled(true);
+			editLeftButton.setEnabled(true);
+			editButton.setEnabled(true);
+			editRightButton.setEnabled(true);
+			// drop_b.setEnabled(true);
+		}
+		
+		if (e != null && !pageChanged) editor.updateWordStyles();
+	}
+	
+	protected void onTypecomboSelected(SelectionEvent e) {
+		reloadIdentifiants();
+		
+		if (typeCombo.getSelectionIndex() > 0) {
+			// String type = unitesAVoir[typeCombo.getSelectionIndex()-1];
+			highlightType();
+			navigationField.setEnabled(true);
+		}
+		else {
+			clearHighlight();
+			navigationField.setEnabled(false);
+		}
+		
+		createButton.setEnabled(false);
+		deleteButton.setEnabled(false);
+		editButton.setEnabled(false);
+		// drop_b.setEnabled(false);
+		if (e != null) editor.updateWordStyles();
+	}
+	
+	/**
+	 * reload the identifiants combo
+	 * 
+	 * @param unite the unite to select, may be null
+	 */
+	public void reloadIdentifiants() {
+		String type0 = typeCombo.getText();
+		unites = vue.getUnitesAVoir(type0);
+		String[] identifiants = vue.getIdUnites(type0, unites);
+		navigationField.setIdentifiants(identifiants, type0, Unite.class);
+		navigationField.setSelectionIndex(0);
+	}
+	
+	public void reloadUnits() {
+		
+		typesUnitesAVoir = vue.getTypesUnitesAVoir();
+		String[] items = new String[typesUnitesAVoir.length + 1];
+		System.arraycopy(typesUnitesAVoir, 0, items, 1, typesUnitesAVoir.length);
+		items[0] = Messages.UnitToolbar_54;
+		typeCombo.setItems(items);
+		if (items.length > 0) {
+			typeCombo.select(0);
+		}
+		typeCombo.layout();
+		
+		onTypecomboSelected(null);
+	}
+	
+	protected void selectUniteInIdentifants(Unite unite) {
+		for (int i = 0; i < unites.length; i++) {
+			// System.out.println("VS "+unites[i]);
+			if (unites[i] == unite) {
+				navigationField.setSelectionIndex(i + 1);
+				return; // no need to go further
+			}
+		}
+	}
+	
+	public void setEnable(boolean enable) {
+		l.setEnabled(enable);
+		typeCombo.setEnabled(enable);
+		navigationField.setEnabled(enable);
+		createButton.setEnabled(enable);
+		deleteButton.setEnabled(enable);
+		editButton.setEnabled(enable);
+		editLeftButton.setEnabled(enable);
+		editRightButton.setEnabled(enable);
+		// drop_b.setEnabled(enable);
+	}
+	
+	@Override
+	public void traiterEvent(Message e) {
+		if (annotationArea.isDisposed()) return;
+		
+		if (e.getType().equals(TypeMessage.MODIF_STRUCTURE)) {
+			// System.out.println("UnitToolbar.traiterEvent: Update toolbar ");
+			UnitToolbar.this.annotationArea.getDisplay().syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					setEnable(!analecCorpus.isVide());
+					// reloadUnits();
+				}
+			});
+		}
+		else if (e.getType().equals(TypeMessage.MODIF_ELEMENT)) {
+			// System.out.println("UnitToolbar.traiterEvent: Update toolbar ");
+			UnitToolbar.this.annotationArea.getDisplay().syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					// reloadUnits();
+				}
+			});
+		}
+	}
+	
+	protected synchronized boolean tryHighlightingUnitsWord(String id, org.txm.searchengine.cqp.corpus.CQPCorpus c) throws CqiClientException {
+		EditionPanel panel = editor.getEditionPanel(0);
+		if (panel == null) return false;
+		if (id != null) {
+			
+		}
+		QueryResult r = c.query(new CQLQuery("[_.text_id=\"" + panel.getEdition().getText().getName() + "\" & id=\"" + id + "\"]"), "TMP", false); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+		List<Match> matches = r.getMatches();
+		if (matches.size() == 0) {
+			System.out.println(NLS.bind(Messages.UnitToolbar_59, id));
+			return false;
+		}
+		int start = matches.get(0).getStart();
+		// System.out.println("start="+start);
+		r.drop();
+		int i = 0;
+		ArrayList<Integer> matching_units = new ArrayList<>();
+		for (Unite u : unites) {
+			if (u.getDeb() <= start && start <= u.getFin()) {
+				matching_units.add(i);
+			}
+			else if (u.getDeb() > start) { // no need to search further
+				continue;
+			}
+			i++;
+		}
+		
+		if (matching_units.size() > 0) {
+			// get index in matching_units of the current unit if any
+			int iUnite = matching_units.indexOf(navigationField.getSelectionIndex() - 1);
+			
+			if (iUnite == -1) iUnite = 0; // current unit is not present, take the first in matching_units
+			else iUnite = (iUnite + 1) % matching_units.size(); // take the next unit in matching_units
+			
+			iUnite = matching_units.get(iUnite); // get the real unit position in 'unites'
+			navigationField.setSelectionIndex(iUnite + 1, false); // call onIndentifiantComboChanged(...)
+			
+			createButton.setEnabled(false);
+			deleteButton.setEnabled(true);
+			editLeftButton.setEnabled(true);
+			editButton.setEnabled(true);
+			editRightButton.setEnabled(true);
+			
+			Unite unite = unites[iUnite];
+			int offset = start - unite.getDeb(); // to select the right page when the unit words overlap with 2 pages
+			highlightUnite(unite, false, offset);
+			
+			updatePropertiesView(unite);
+			
+			return true;
+		}
+		
+		if (navigationField.getSelectionIndex() != 0) { // is the navigationField already at 0 ?
+			navigationField.setSelectionIndex(0);
+		}
+		
+		return false;
+	}
+	
+	protected boolean updateUniteLimits(Unite unite, String[] ids, int mode) throws CqiClientException {
+		
+		EditionPanel panel = UnitToolbar.this.editor.getEditionPanel(0);
+		String text_name = panel.getEdition().getText().getName();
+		
+		int[] startend = getStartEndWordPositions(maincorpus, ids, text_name);
+		if (startend == null) return false;
+		
+		int pos = startend[0];
+		
+		if (mode == 1) { // left
+			analecCorpus.modifBornesUnite(unite, pos, unite.getFin());
+		}
+		else if (mode == 2) { // right
+			analecCorpus.modifBornesUnite(unite, unite.getDeb(), pos);
+		}
+		else if (mode == 3) { // choose using distance
+			analecCorpus.modifBornesUnite(unite, startend[0], startend[1]);
+		}
+		
+		return true;
+	}
+	
+	@Override
+	public void selectNext() {
+		int i = navigationField.selectNext();
+	}
+	
+	@Override
+	public void selectPrevious() {
+		int i = navigationField.selectPrevious();
+	}
+	
+	@Override
+	public void selectFirst() {
+		int i = navigationField.selectFirst();
+	}
+	
+	@Override
+	public void select10Previous() {
+		int i = navigationField.select10Previous();
+	}
+	
+	@Override
+	public void select10Next() {
+		int i = navigationField.select10Next();
+	}
+	
+	@Override
+	public void selectLast() {
+		int i = navigationField.selectLast();
+	}
+	
+	@Override
+	public void select(Element currentElement) {
+		if (currentElement.getClass() == Unite.class) {
+			int i = Arrays.binarySearch(unites, currentElement);
+			if (i >= 0) navigationField.setSelectionIndex(i + 1);
+		}
+	}
+	
+	@Override
+	public String getElementType() {
+		if (typeCombo.isDisposed()) return ""; //$NON-NLS-1$
+		return typeCombo.getText();
+	}
+	
+	@Override
+	public void onBackToText(Text text, String id) {
+		if (id.length() > 0) {
+			try {
+				tryHighlightingUnitsWord(id, this.getCQPCorpus());
+			}
+			catch (CqiClientException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+	}
+	
+	@Override
+	public Class<? extends TXMResult> getAnnotatedTXMResultClass() {
+		return Text.class;
+	}
+	
+	@Override
+	public String getName() {
+		return "Unit";
+	}
+	
+	@Override
+	public boolean notifyStartOfCompute() throws Exception {
+		// TODO Auto-generated method stub
+		return false;
+	}
+	
+	@Override
+	public boolean notifyEndOfCompute() throws Exception {
+		// TODO Auto-generated method stub
+		return false;
+	}
+	
+	@Override
+	public void notifyEndOfRefresh() throws Exception {
+		// TODO Auto-generated method stub
+	}
+	
+	@Override
+	public void notifyStartOfCreatePartControl() throws Exception {
+		// TODO Auto-generated method stub
+	}
+	
+	@Override
+	public void notifyStartOfRefresh() throws Exception {
+		// TODO Auto-generated method stub
+	}
+	
+	ProgressListener pageProgressListener = null;
+	
+	@Override
+	protected ProgressListener getPageReloadListener() {
+		if (pageProgressListener != null) {
+			return pageProgressListener;
+		}
+		
+		pageProgressListener = new ProgressListener() {
+			
+			@Override
+			public void completed(ProgressEvent event) {
+				if (typeCombo.getSelectionIndex() >= 0) {
+					highlightType();
+				}
+			}
+			
+			@Override
+			public void changed(ProgressEvent event) {}
+		};
+		return pageProgressListener;
+	}
+	
+	@Override
+	public boolean needToUpdateIndexes() {
+		return false;
+	}
+	
+	@Override
+	public boolean hasChanges() {
+		return analecCorpus.isModifie();
+	}
+	
+	@Override
+	public boolean needToUpdateEditions() {
+		
+		return false;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/UnitToolbar.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/SchemaToolbar.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/SchemaToolbar.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/SchemaToolbar.java	(revision 3653)
@@ -0,0 +1,1012 @@
+package org.txm.annotation.urs.toolbar;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+import org.eclipse.jface.util.Util;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.ProgressEvent;
+import org.eclipse.swt.browser.ProgressListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MenuEvent;
+import org.eclipse.swt.events.MenuListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.txm.annotation.rcp.editor.AnnotationExtension;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.preferences.URSPreferences;
+import org.txm.annotation.urs.view.ElementPropertiesView;
+import org.txm.annotation.urs.widgets.NavigationField;
+import org.txm.core.preferences.TXMPreferences;
+import org.txm.core.results.TXMResult;
+import org.txm.edition.rcp.editors.EditionPanel;
+import org.txm.edition.rcp.editors.RGBA;
+import org.txm.edition.rcp.editors.SynopticEditionEditor;
+import org.txm.objects.Edition;
+import org.txm.objects.Page;
+import org.txm.objects.Project;
+import org.txm.objects.Text;
+import org.txm.rcp.IImageKeys;
+import org.txm.rcp.editors.TXMEditor;
+import org.txm.rcp.swt.dialog.ConfirmDialog;
+import org.txm.searchengine.cqp.CQPSearchEngine;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.corpus.Property;
+import org.txm.searchengine.cqp.corpus.QueryResult;
+import org.txm.searchengine.cqp.corpus.query.Match;
+import org.txm.searchengine.cqp.corpus.query.CQLQuery;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.Message;
+import visuAnalec.Message.TypeMessage;
+import visuAnalec.elements.Element;
+import visuAnalec.elements.Schema;
+import visuAnalec.elements.Unite;
+
+public class SchemaToolbar extends URSAnnotationToolbar {
+
+	public RGBA highlighted_unit_color = new RGBA(183, 191, 237, 0.7f);
+	public RGBA selected_unit_color = new RGBA(255, 255, 0, 0.5f);
+	
+	//	private Button createButton;
+	private Button deleteSchemaButton;
+	private Button deleteUniteButton;
+	//	private Button editButton;
+	private KeyListener editorKeyListener;
+	private MouseListener editorMouseListener;
+	private Label l;
+	private MenuListener menuListener;
+
+//	private List<String> previousSelectedTypeSchemaIDS;
+	private List<String> previousSelectedSchemaIDS;
+	private List<String> previousSelectedUniteIDS;
+
+	protected boolean startFixingUnitLimit;
+
+	private Schema[] schemas;
+	private Unite[] unites;
+	private String[] schemasAVoir;
+	private Combo typeCombo;
+	private NavigationField navigationField;
+	//	private Combo unitTypeCombo;
+	private NavigationField subNavigationField;
+
+	public SchemaToolbar() { }
+
+	@Override
+	protected boolean _install(TXMEditor<? extends TXMResult> txmeditor, AnnotationExtension extension, Composite parent, int position) throws Exception {
+		
+		annotationArea.getLayout().numColumns = 8;
+		annotationArea.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+		
+		String color_palette = URSPreferences.getInstance().getString(URSPreferences.COLOR_PALETTE);
+		if ("yellow".equals(color_palette)) { //$NON-NLS-1$
+			this.highlighted_unit_color = URSAnnotationToolbar.lightyellow;
+			this.selected_unit_color = URSAnnotationToolbar.yellow;
+		} else if ("green".equals(color_palette)) { //$NON-NLS-1$
+			this.highlighted_unit_color = URSAnnotationToolbar.lightgreen;
+			this.selected_unit_color = URSAnnotationToolbar.green;
+		} else { // custom palette
+			//		String highlighted_unit_color_pref = TxmPreferences.get(AnalecPreferencePage.HIGHLIGHTED_UNIT_COLOR, "255,255,176");
+			//		String selected_unit_color_pref = TxmPreferences.get(AnalecPreferencePage.SELECTED_UNIT_COLOR, "255,255,96");
+			//		this.highlighted_unit_color = new RGBA(highlighted_unit_color_pref, 0.7f);
+			//		this.selected_unit_color = new RGBA(selected_unit_color_pref, 1f);
+		}
+		
+		this.editor = (SynopticEditionEditor) txmeditor;
+		analecCorpus.addEventListener(this);
+
+		l = new Label(annotationArea, SWT.NONE);
+		l.setText("Type de schéma : ");
+		l.setToolTipText("Type de schéma");
+
+		this.maincorpus = this.editor.getCorpus().getMainCorpus();
+		typeCombo = new Combo(annotationArea, SWT.NONE|SWT.READ_ONLY);
+		typeCombo.setToolTipText("Type de schéma");
+		GridData gdata = new GridData(GridData.FILL, GridData.CENTER, false, false);
+		gdata.minimumWidth = 100;
+		gdata.widthHint = 100;
+		typeCombo.setLayoutData(gdata);
+		typeCombo.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				onTypeComboSelected(e);
+			}
+		});
+
+		navigationField = new NavigationField(this, SWT.NONE);
+		gdata = new GridData(GridData.FILL, GridData.FILL, true, false);
+		navigationField.setLayoutData(gdata);
+		navigationField.addListener(SWT.Selection, new Listener() {
+			@Override
+			public void handleEvent(Event event) {
+				onIdentifiantComboSelected(null);
+			}
+		});
+
+		deleteSchemaButton = new Button(annotationArea, SWT.PUSH);
+		deleteSchemaButton.setImage(IImageKeys.getImage("platform:/plugin/org.txm.rcp/icons/cross.png")); //$NON-NLS-1$
+		deleteSchemaButton.setToolTipText("Supprimer le schéma");
+		deleteSchemaButton.setEnabled(false);
+		deleteSchemaButton.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				onDeleteSchemaComboSelected(e);
+			}
+		});
+
+		l = new Label(annotationArea, SWT.NONE);
+		l.setText("Unités :");
+		subNavigationField = new NavigationField(this, SWT.NONE);
+		gdata = new GridData(GridData.FILL, GridData.FILL, true, false);
+		subNavigationField.setLayoutData(gdata);
+		subNavigationField.addListener(SWT.Selection, new Listener() {
+			@Override
+			public void handleEvent(Event event) {
+				onIdentifiantUniteComboSelected(event);
+			}
+		});
+
+		deleteUniteButton = new Button(annotationArea, SWT.PUSH);
+		deleteUniteButton.setImage(IImageKeys.getImage("platform:/plugin/org.txm.rcp/icons/cross.png")); //$NON-NLS-1$
+		deleteUniteButton.setToolTipText("Supprimer l'unité de la chaîne");
+		deleteUniteButton.setEnabled(false);
+		deleteUniteButton.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				onDeleteUniteComboSelected(e);
+			}
+		});
+
+		annotationArea.layout();
+		annotationArea.getParent().layout(true);
+		editor.getEditionArea().layout();
+
+		reloadTypeSchemas(); // reloads ids also
+		reloadIdentifiants();
+		
+		if (schemasAVoir.length > 0) {
+			typeCombo.select(1);
+			onTypeComboSelected(null);
+
+			//testIfAwordSpanIsSelected();
+			
+//			if (schemas.length > 0) {
+//				navigationField.selectFirst();
+//				onIdentifiantComboSelected(null);
+//			}
+		}
+
+		//		createButton.setEnabled(false);
+		//deleteSchemaButton.setEnabled(false);
+		//		editButton.setEnabled(false);
+		editor.updateWordStyles();
+		ElementPropertiesView.openView();
+		
+		return true;
+	}
+	
+	protected void testIfAwordSpanIsSelected() {
+		EditionPanel panel = editor.getEditionPanel(0);
+		if (panel == null) return;
+		String[] ids = panel.getWordSelection(); // may be null
+		testIfAwordSpanIsSelected(ids);
+	}
+
+	protected void testIfAwordSpanIsSelected(String[] ids) {
+		if (ids != null && typeCombo.getItemCount() > 1  && typeCombo.getEnabled() ) {
+			//System.out.println("ids:"+Arrays.toString(ids));
+			if (navigationField.getSelectionIndex() > 0) {
+				deleteSchemaButton.setEnabled(true);
+			}
+		}	
+	}
+
+	public void clearSchemasHighlight() {
+		//System.out.println("clear: "+previousSelectedSchemaIDS);
+		if (previousSelectedSchemaIDS != null) {
+			editor.removeHighlightWordsById(highlighted_unit_color, previousSelectedSchemaIDS);
+			editor.removeFontWeightWordsById(previousSelectedSchemaIDS);
+			previousSelectedSchemaIDS = null; // release memory
+		}
+//		if (previousSelectedTypeSchemaIDS != null) {
+//			editor.removeHighlightWordsById(lightblue, previousSelectedTypeSchemaIDS);
+//			previousSelectedTypeSchemaIDS = null; // release memory
+//		}
+	}
+
+
+	public void clearUnitesHighlight() {
+		if (previousSelectedUniteIDS != null) {
+			editor.removeHighlightWordsById(selected_unit_color, previousSelectedUniteIDS);
+			editor.removeFontWeightWordsById(previousSelectedUniteIDS);
+			previousSelectedUniteIDS = null; // release memory
+		}
+
+		if (!deleteUniteButton.isDisposed()) deleteUniteButton.setEnabled(false);
+	}
+
+	public MouseListener getEditorClickListener() {
+
+		if (editorMouseListener != null) return editorMouseListener;
+		
+		editorMouseListener = new MouseListener() {
+
+			boolean dblClick = false;
+			boolean debug = false;
+			private int t,x,y;
+
+			@Override
+			public void mouseDoubleClick(MouseEvent e) {
+				if (debug) Log.finer("DOUBLE CLICK"); //$NON-NLS-1$
+				dblClick= true;
+
+				EditionPanel panel = editor.getEditionPanel(0);
+				if (panel == null) return;
+				String[] ids = panel.getWordSelection(); // may be null
+				//System.out.println("word id="+id);
+				//				if (id != null) {
+				//					org.txm.searchengine.cqp.corpus.Corpus c = SchemaToolbar.this.editor.getCorpus();
+				//					try {
+				//						if (debug)  System.out.println(" HIGHLIGHTING ANNOT IF ANY AT "+id);
+				//						tryHighlightingWord(id,c );
+				//					} catch (Exception ex) {
+				//						ex.printStackTrace();
+				//					}
+				//				}
+
+				//				if (id != null && typeCombo.getSelectionIndex() > 0 && typeCombo.getEnabled())
+				//					createButton.setEnabled(true); // there is a text selection in the browser
+			}
+
+			@Override
+			public void mouseDown(MouseEvent e) {
+				if (debug) Log.finer("MOUSE DOWN"); //$NON-NLS-1$
+				dblClick = false;
+				t = e.time;
+				x = e.x;
+				y = e.y;
+			}
+
+			@Override
+			public void mouseUp(MouseEvent e) {
+				if (dblClick) { // doucle click raised by mouseDoubleClick
+					dblClick = false;
+					return; // stop right now ! :-o
+				}
+				if (debug) Log.finer("MOUSE UP"); //$NON-NLS-1$
+				EditionPanel panel = editor.getEditionPanel(0);
+				if (panel == null) return;
+
+				if (typeCombo.getSelectionIndex() <= 0) {
+					//					createButton.setEnabled(false);
+					deleteSchemaButton.setEnabled(false);
+					//					editButton.setEnabled(false);
+					return; // nothing to do with annotations
+				}
+
+				// filter click that are not a left simple click (no drag)
+				//System.out.println("click count="+e.count+" button="+e.button+" time="+e.time+" diff="+(e.time-t)+" dist="+(Math.abs(e.x - x) + Math.abs(e.y - y)));
+				if (e.count > 1) {
+					if (debug) Log.finer(" DOUBLE CLICK"); //$NON-NLS-1$
+					//System.out.println("not a simple click");
+					return;
+				}
+
+				if (Math.abs(e.x - x) + Math.abs(e.y - y) > 7) {
+					if (debug) Log.finer(" DRAG"); //$NON-NLS-1$
+
+					String[] ids = panel.getWordSelection(); // may be null
+					if (ids != null && ids.length > 0 && typeCombo.getItemCount() > 1  && typeCombo.getEnabled() ) {
+
+						if (navigationField.getSelectionIndex() > 0 && ids[0] != null) {
+							deleteSchemaButton.setEnabled(true);
+							//							editButton.setEnabled(true);
+						}
+						//						
+						//						createButton.setEnabled(id != null);
+					}
+					//panel.getBrowser().forceFocus();
+					// extend selection to word boundaries
+					//					String id = panel.getWordSelection(); // may be null
+					//					if (id != null) {
+					//						panel.expandSelectionTo(id);
+					//					}
+					return;
+				}
+				if (e.button != 1) {
+					if (debug) Log.finer(" NO LEFT"); //$NON-NLS-1$
+					//System.out.println("not a left click");
+					return;
+				}
+				if ((e.time-t) > 150) {
+					if (debug) Log.finer(" LONG"); //$NON-NLS-1$
+					//System.out.println("not a short click");
+					return;
+				}
+
+				String[] ids = panel.getWordSelection(); // may be null
+
+				if (ids == null) { // clear selection
+					if (debug)  Log.finer(" NO WORD SELECTION"); //$NON-NLS-1$
+					//					navigationField.setSelectionIndex(0); // clear selection
+					//					onIdentifiantComboSelected(null);
+					return;
+				}
+
+				org.txm.searchengine.cqp.corpus.CQPCorpus c = SchemaToolbar.this.editor.getCorpus();
+
+				try {
+					if (debug)  Log.finer(" HIGHLIGHTING ANNOT IF ANY AT "+ids[0]); //$NON-NLS-1$
+					tryHighlightingWord(ids[0],c );
+				} catch (Exception ex) {
+					ex.printStackTrace();
+				}
+			}
+		};
+		return editorMouseListener;
+	}
+
+	public KeyListener getEditorKeyListener() {
+		if (editorKeyListener != null) return editorKeyListener;
+		editorKeyListener = new KeyListener() {
+
+			@Override
+			public void keyPressed(KeyEvent e) { }
+
+			@Override
+			public void keyReleased(KeyEvent e) {
+				//System.out.println("Key: "+e.keyCode);
+				int mask = SWT.CTRL;
+				if (Util.isMac()) mask = SWT.COMMAND;
+
+				//				if ((e.stateMask & SWT.ALT) == SWT.ALT) {
+				//					if (e.keyCode == SWT.ARROW_UP) {
+				//						selectPreviousUnite();
+				//					} else if (e.keyCode == SWT.ARROW_DOWN) {
+				//						selectNextUnite();
+				//					} else if (e.keyCode == SWT.HOME) {
+				//						selectFirstUnite();
+				//					} else if (e.keyCode == SWT.END) {
+				//						selectLastUnite();
+				//					}
+				//				} else 
+				if (((e.stateMask & mask) == mask)) {
+					if (e.keyCode == SWT.ARROW_UP) {
+						selectPrevious();
+					} else if (e.keyCode == SWT.ARROW_DOWN) {
+						selectNext();
+					} else if (e.keyCode == SWT.HOME) {
+						selectFirst();
+					} else if (e.keyCode == SWT.END) {
+						selectLast();
+					}
+				}
+			}
+		};
+		return editorKeyListener;
+	}
+
+	public MenuListener getMenuListener() {
+		if (menuListener != null) return menuListener;
+
+		this.menuListener = new MenuListener() {
+
+			HashSet<MenuItem> entries = new HashSet<MenuItem>();
+
+			@Override
+			public void menuHidden(MenuEvent e) { }
+
+			@Override
+			public void menuShown(MenuEvent e) {
+
+				EditionPanel panel = editor.getEditionPanel(0);
+				if (panel == null) return;
+				Menu menu = panel.getBrowser().getMenu();
+
+				for (MenuItem item : entries) item.dispose(); 
+
+				int[] startend = getSelectionStartEndWordPositions(); 
+				//System.out.println("Word under mouse: "+id);
+				if (startend != null && startend.length == 2) {
+					// get the word start end positions
+					ArrayList<Unite> unitEntries = new ArrayList<Unite>(); // stores units  covering the word
+					ArrayList<Integer> noEntries = new ArrayList<Integer>(); // stores units  covering the word
+					int i = 1;
+					Unite[] unites = schemas[navigationField.getSelectionIndex()-1].getUnitesSousjacentes();
+					for (Unite unit : unites) {
+						if (unit.getDeb() > startend[0]) break; // don't go further
+						if (unit.getFin() < startend[0]) continue;
+						unitEntries.add(unit);
+						noEntries.add(i);
+						i++;
+					}
+
+					if (unitEntries.size() > 0) {
+						MenuItem item = new MenuItem(menu, SWT.SEPARATOR);
+						entries.add(item);
+					}
+
+					for (i = 0 ; i < unitEntries.size() ; i++) {
+						final Unite unit = unitEntries.get(i);
+						final Integer unitNo = Arrays.binarySearch(unites, unit)+1;
+
+						MenuItem item = new MenuItem(menu, SWT.NONE);
+						item.setText("Select "+unit.getType()+"-"+unitNo);
+						item.addSelectionListener(new SelectionListener() {
+							@Override
+							public void widgetDefaultSelected(SelectionEvent e) { }
+							@Override
+							public void widgetSelected(SelectionEvent e) {
+								highlightUnite(unit);
+								updatePropertiesView(unit);
+							}
+						});
+						entries.add(item);
+					}
+				}
+			}
+		};
+
+		return menuListener;
+	}
+
+	protected void highlightType() {
+		
+		if (schemas == null) return;
+		if (schemas.length == 0) return;
+
+		// highlight all units of all schemas ? -> too much
+		
+	}
+
+	protected void highlightSchema(Schema schema) {
+		//clearHighlight();
+
+		unites = schema.getUnitesSousjacentes();
+
+		if (unites == null) return;
+		if (unites.length > 0) {
+
+			Unite unite0 = schema.getUnite0();
+			int n2 = 0;
+			for (int i = 0 ; i < unites.length ; i++) {
+				for (int p = unites[i].getDeb() ; p <= unites[i].getFin() ; p++) {
+					n2++;
+				}
+			}
+			int allpositions[] = new int[n2];
+			n2 = 0;
+			for (int i = 0 ; i < unites.length ; i++) {
+				for (int p = unites[i].getDeb() ; p <= unites[i].getFin() ; p++) {
+					allpositions[n2++] = p;
+				}
+			}
+
+			org.txm.searchengine.cqp.corpus.CQPCorpus c = SchemaToolbar.this.editor.getCorpus();
+			try {
+				if (previousSelectedSchemaIDS != null) {
+					editor.removeHighlightWordsById(highlighted_unit_color, previousSelectedSchemaIDS);
+					previousSelectedSchemaIDS = null; // release memory
+				}
+				String ids2[] = CQPSearchEngine.getCqiClient().cpos2Str(c.getProperty("id").getQualifiedName(), allpositions); //$NON-NLS-1$
+				previousSelectedSchemaIDS = Arrays.asList(ids2);
+
+				editor.addHighlightWordsById(highlighted_unit_color, previousSelectedSchemaIDS);
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+	}
+
+	private void highlightUnite(Unite unite) {
+		int start = unite.getDeb();
+		int end = unite.getFin();
+		int positions [] = new int[end-start+1];
+		int n = 0;
+		for (int p = start ; p <= end ; p++) {
+			positions[n++] = p;
+		}
+		org.txm.searchengine.cqp.corpus.CQPCorpus c = SchemaToolbar.this.editor.getCorpus();
+
+		try {
+			if (previousSelectedUniteIDS != null) {
+				editor.removeHighlightWordsById(selected_unit_color, previousSelectedUniteIDS);
+				editor.removeFontWeightWordsById(previousSelectedUniteIDS);
+				previousSelectedUniteIDS = null; // release memory
+			}
+
+			String ids[] = CQPSearchEngine.getCqiClient().cpos2Str(c.getProperty("id").getQualifiedName(), positions); //$NON-NLS-1$
+			//System.out.println("Highlight words with ids="+Arrays.toString(ids));
+
+			positions = new int[]{positions[0]};
+			Property text_id = c.getStructuralUnit("text").getProperty("id"); //$NON-NLS-1$ //$NON-NLS-2$
+			int[] text_strucs = CQPSearchEngine.getCqiClient().cpos2Struc(text_id.getQualifiedName(), positions);
+			String[] text_ids = CQPSearchEngine.getCqiClient().struc2Str(text_id.getQualifiedName(), text_strucs);
+
+			String firstWordId = ids[0];
+			String firstWordTextId = text_ids[0];
+
+			EditionPanel panel = editor.getEditionPanel(0);
+			Edition e = panel.getEdition();
+			Project corpus = e.getText().getProject();
+			Text newText = corpus.getText(firstWordTextId); // get the new text
+			Edition newEdition = newText.getEdition(e.getName()); // get the edition of the new text
+			Page newPage = newEdition.getPageForWordId(firstWordId); // find out the page containing the word
+
+			previousSelectedUniteIDS = Arrays.asList(ids);
+//			System.out.println("HU: "+previousSelectedUniteIDS);
+			editor.addHighlightWordsById(selected_unit_color, previousSelectedUniteIDS);
+			editor.addFontWeightWordsById(EditionPanel.WEIGHT_BOLD, previousSelectedUniteIDS);
+			
+			if (previousSelectedUniteIDS.size() > 0)	editor.setFocusedWordID(previousSelectedUniteIDS.get(0));
+			//System.out.println("Word page= "+p+" current="+panel.getCurrentPage());
+			if (panel.getCurrentPage() != newPage || panel.getCurrentText() != newText) { // do we need to change page ?
+				//System.out.println("PAGE&TEXT CHANGED");
+				editor.goToPage(newText.getName(), newPage.getName());
+			} else  { // just reload the page to highlight words
+				//editor.updateWordStyles();
+			}
+			
+		} catch (Exception e1) {
+			e1.printStackTrace();
+		}
+	}
+
+	protected void onDeleteSchemaComboSelected(SelectionEvent e) {
+		int iSchema = navigationField.getSelectionIndex();
+		if (iSchema <= 0) return;
+		//System.out.println("Delete unite at i="+i);
+		Schema schema = schemas[iSchema-1];
+
+		String id = navigationField.getText();
+
+		ConfirmDialog dialog = new ConfirmDialog(Display.getCurrent().getActiveShell(), "org.txm.annotation.urs.delete", "Delete unit "+id, "Do you really want to delete schema "+id+" ?"); //$NON-NLS-1$
+		if (dialog.open() == ConfirmDialog.CANCEL) return;
+
+		//System.out.println("unite "+unite.toString());
+		SchemaToolbar.this.vue.getCorpus().supSchema(schema);
+		maincorpus.setIsModified(true);
+		reloadIdentifiants();
+		onIdentifiantComboSelected(null);
+
+		if (typeCombo.getSelectionIndex() > 0) {
+			highlightType(); // reload other unit highlight
+		}
+		editor.fireIsDirty();
+		if (e != null) editor.updateWordStyles();
+	}
+
+	protected void onDeleteUniteComboSelected(SelectionEvent e) {
+		int iSchema = navigationField.getSelectionIndex();
+		if (iSchema <= 0) return;
+		//System.out.println("Delete unite at i="+i);
+		Schema schema = schemas[iSchema-1];
+
+		int i = subNavigationField.getSelectionIndex();
+		if (i <= 0) return;
+		//System.out.println("Delete unite at i="+i);
+		Unite unite = unites[i-1];
+
+		String id = subNavigationField.getText();
+
+		ConfirmDialog dialog = new ConfirmDialog(Display.getCurrent().getActiveShell(), "org.txm.annotation.urs.delete", "Delete unit "+id, "Do you really want to delete unit "+id+" from the schema?"); //$NON-NLS-1$
+		if (dialog.open() == ConfirmDialog.CANCEL) return;
+
+		//System.out.println("unite "+unite.toString());
+		SchemaToolbar.this.vue.getCorpus().supUnite(unite);
+		maincorpus.setIsModified(true);
+		highlightSchema(schema);
+		reloadIdentifiantsUnites();
+		onIdentifiantUniteComboSelected(null);
+		editor.fireIsDirty();
+		if (e != null) editor.updateWordStyles();
+	}
+
+	protected void onIdentifiantUniteComboSelected(Event e) {
+		if (unites == null) return;
+
+		int iUnite = subNavigationField.getSelectionIndex();
+		if (iUnite > 0) {
+			Unite unite = unites[iUnite-1];
+			highlightUnite(unite);
+			deleteUniteButton.setEnabled(true);
+		} else {
+			clearUnitesHighlight();
+			deleteUniteButton.setEnabled(false);
+		}
+		
+		if (e != null) editor.updateWordStyles();
+	}
+
+	protected void onIdentifiantComboSelected(SelectionEvent e) {
+		// Log.finer("Identifiants SelectionListener: "+navigationField.getSelectionIndex());
+		int iSchema = navigationField.getSelectionIndex();
+		if (iSchema <= 0) {
+			if (previousSelectedSchemaIDS != null) {
+				editor.removeHighlightWordsById(highlighted_unit_color, previousSelectedSchemaIDS);
+				previousSelectedSchemaIDS = null; // release memory
+			}
+
+			highlightType();
+			deleteSchemaButton.setEnabled(false);
+			subNavigationField.setEnabled(false);
+			subNavigationField.setSelectionIndex(0);
+			deleteUniteButton.setEnabled(false);
+		} else {
+			Schema schema = schemas[iSchema-1];
+			clearHighlight();
+			highlightSchema(schema);
+			reloadIdentifiantsUnites();
+			updatePropertiesView(schema);
+			deleteSchemaButton.setEnabled(true);
+		}
+		
+		if (e != null) editor.updateWordStyles();
+	}
+
+	protected void onTypeComboSelected(SelectionEvent e) {
+		// Log.finer("Types SelectionListener: "+typeCombo.getSelectionIndex());
+		reloadIdentifiants();
+		if (typeCombo.getSelectionIndex() > 0) {
+			//String type = unitesAVoir[typeCombo.getSelectionIndex()-1];
+			highlightType();
+			navigationField.setEnabled(true);
+			if (schemas.length > 0) {
+				navigationField.selectFirst();
+				onIdentifiantComboSelected(null);
+			}
+		} else {
+			clearHighlight();
+			unites = null;
+			navigationField.setEnabled(false);
+		}
+
+		deleteSchemaButton.setEnabled(false);
+		if (e != null) editor.updateWordStyles();
+	}
+
+	/**
+	 * reload the identifiants combo
+	 * 
+	 * @param unite the unite to select, may be null
+	 */
+	public void reloadIdentifiants() {
+		// Log.finer("Reloading identifiants combo values.");
+		String type0 = typeCombo.getText();
+		schemas = vue.getSchemasAVoir(type0);
+		String[] identifiants = vue.getIdSchemas(type0, schemas);
+		navigationField.setIdentifiants(identifiants, type0, Schema.class);
+		navigationField.setSelectionIndex(0);
+	}
+
+	/**
+	 * reload the identifiants combo
+	 * 
+	 * @param unite the unite to select, may be null
+	 */
+	public void reloadIdentifiantsUnites() {
+		// Log.finer("Reloading unites combo values.");
+		int iSchema = navigationField.getSelectionIndex();
+		if (iSchema <= 0) {
+			subNavigationField.setIdentifiants(new String[0], null, null);
+			unites = null;
+			return;
+		} else {
+			Schema schema = schemas[iSchema-1];
+			unites = schema.getUnitesSousjacentes();
+			String[] identifiants = new String[unites.length];
+			for (int i = 0 ; i < unites.length ; i++) {
+				identifiants[i] = ""+(i+1);//vue.getIdElement(unites[i]); //$NON-NLS-1$
+			}
+			subNavigationField.setIdentifiants(identifiants, null, null);
+
+			//		String[] items = new String[identifiants.length +1];
+			//		System.arraycopy(identifiants, 0, items, 1, identifiants.length);
+			//		//System.out.println("Identifiants: "+Arrays.toString(identifiants));
+			//		items[0] = "< identifiant >";
+			//		identifiantCombo.setItems(items);
+			if (identifiants.length > 0) {
+				subNavigationField.setSelectionIndex(1);
+				subNavigationField.setEnabled(true);
+			} else {
+				subNavigationField.setSelectionIndex(0);
+				subNavigationField.setEnabled(false);
+			}
+			//identifiantCombo.layout();
+		}
+	}
+
+	public void reloadTypeSchemas() {
+
+		schemasAVoir = vue.getTypesSchemasAVoir();
+		String[] items = new String[schemasAVoir.length +1];
+		System.arraycopy(schemasAVoir, 0, items, 1, schemasAVoir.length);
+		items[0] = "<type de schéma>";
+		typeCombo.setItems(items);
+		if (items.length > 0) {
+			typeCombo.select(1);
+		}
+		typeCombo.layout();
+
+		onTypeComboSelected(null);
+	}
+
+	protected void selectSchemaInIdentifants(Schema schema) {
+		for (int i = 0 ; i < schemas.length ; i++) {
+			//System.out.println("VS "+unites[i]);
+			if (schemas[i] == schema) {
+				navigationField.setSelectionIndex(i+1);
+				return; // no need to go further
+			}
+		}
+	}
+
+	public void setEnable(boolean enable) {
+		
+		l.setEnabled(enable);
+		typeCombo.setEnabled(enable);
+		//		createButton.setEnabled(enable);
+		deleteSchemaButton.setEnabled(enable);
+		//		editButton.setEnabled(enable);
+		navigationField.setEnabled(enable);
+	}
+
+	@Override
+	public void traiterEvent(Message e) {
+		
+		if (annotationArea.isDisposed()) return;
+
+		if (e.getType().equals(TypeMessage.MODIF_STRUCTURE)) {
+			//System.out.println("SchemaToolbar.traiterEvent: Update toolbar ");
+			SchemaToolbar.this.annotationArea.getDisplay().syncExec(new Runnable() {
+				@Override
+				public void run() {
+					setEnable(!analecCorpus.isVide());
+					//reloadUnits();
+				}
+			});
+		} else if (e.getType().equals(TypeMessage.MODIF_ELEMENT)) {
+			//System.out.println("SchemaToolbar.traiterEvent: Update toolbar ");
+			SchemaToolbar.this.annotationArea.getDisplay().syncExec(new Runnable() {
+				@Override
+				public void run() {
+					//reloadUnits();
+				}
+			});
+		}
+	}
+
+	protected void tryHighlightingWord(String id, org.txm.searchengine.cqp.corpus.CQPCorpus c) throws CqiClientException {
+		
+		EditionPanel panel = editor.getEditionPanel(0);
+		if (panel == null) return;
+		if (id != null) {
+
+		}
+		QueryResult r = c.query(new CQLQuery("[_.text_id=\""+panel.getEdition().getText().getName()+"\" & id=\""+id+"\"]"), "TMP", false); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+		List<Match> matches = r.getMatches();
+		if (matches.size() == 0) {
+			Log.warning(NLS.bind("Error no word found for id={0}.", id));
+			return;
+		}
+		int start = matches.get(0).getStart();
+		//System.out.println("start="+start);
+		r.drop();
+		int i = 0;
+		Unite[] unites = schemas[navigationField.getSelectionIndex()-1].getUnitesSousjacentes();
+		for (Unite u : unites) {
+			if (u.getDeb() <= start &&  start <= u.getFin()) {
+				highlightUnite(u);
+				updatePropertiesView(u);
+
+				deleteSchemaButton.setEnabled(true);
+				return;
+			} else if (u.getFin() < start) { // no need to search further
+
+			}
+			i++;
+		}
+
+		//	navigationField.setSelectionIndex(0);
+		onIdentifiantComboSelected(null);
+	}
+
+	protected boolean updateUniteLimits(Unite unite, String id) throws CqiClientException {
+
+		String[] ids = {id};
+		EditionPanel panel = SchemaToolbar.this.editor.getEditionPanel(0);
+		String text_name = panel.getEdition().getText().getName();
+
+		int[] startend = getStartEndWordPositions(maincorpus, ids, text_name);
+		if (startend == null) return false;
+
+		int pos = startend[0];
+		Log.fine("Updating annotation limits: "+unite.getDeb()+" -> "+unite.getFin()+" with word id="+id+" with pos="+pos);
+		if ((pos == unite.getDeb() || pos == unite.getFin()) && (unite.getFin() - unite.getDeb()) == 1) {
+			analecCorpus.modifBornesUnite(unite, pos, pos);
+		} else if (pos <= unite.getDeb()) {
+			analecCorpus.modifBornesUnite(unite, pos, unite.getFin());
+		} else if (pos >= unite.getFin()) {
+			analecCorpus.modifBornesUnite(unite, unite.getDeb(), pos);
+		} else if ((pos - unite.getDeb()) < (unite.getFin() - pos)) {
+			analecCorpus.modifBornesUnite(unite, pos, unite.getFin());
+		} else {
+			analecCorpus.modifBornesUnite(unite, unite.getDeb(), pos);
+		}
+
+		return true;
+	}
+
+	public void selectNextUnite() {
+		subNavigationField.selectNext();
+	}
+
+	public void selectPreviousUnite() {
+		subNavigationField.selectPrevious();
+	}
+
+	public void selectFirstUnite() {
+		subNavigationField.selectFirst();
+	}
+
+	public void selectLastUnite() {
+		subNavigationField.selectLast();
+	}
+
+	@Override
+	public void selectNext() {
+		navigationField.selectNext();
+	}
+
+	@Override
+	public void selectPrevious() {
+		navigationField.selectPrevious();
+	}
+
+	@Override
+	public void selectFirst() {
+		navigationField.selectFirst();
+	}
+
+	@Override
+	public void selectLast() {
+		navigationField.selectLast();
+	}
+
+	@Override
+	public void select10Previous() {
+		navigationField.select10Previous();
+	}
+
+	@Override
+	public void select10Next() {
+		navigationField.select10Next();
+	}
+
+	@Override
+	public void select(Element currentElement) {
+		if (currentElement.getClass() == Schema.class) {
+			int i = Arrays.binarySearch(schemas, currentElement);
+			if (i >= 0) navigationField.setSelectionIndex(i+1);
+		}
+	}
+
+	@Override
+	public String getElementType() {
+		if (typeCombo.isDisposed()) return ""; //$NON-NLS-1$
+		return typeCombo.getText();
+	}
+
+	@Override
+	public void clearHighlight() {
+		clearSchemasHighlight();
+		clearUnitesHighlight();
+	}
+
+	@Override
+	public void onBackToText(Text text, String id) {
+		// TODO Auto-generated method stub
+		
+	}
+
+	@Override
+	public Class<? extends TXMResult> getAnnotatedTXMResultClass() {
+		return Text.class;
+	}
+
+	@Override
+	public String getName() {
+		return "Schema annotation";
+	}
+
+	@Override
+	public boolean notifyStartOfCompute() throws Exception {
+		// TODO Auto-generated method stub
+		return false;
+	}
+
+	@Override
+	public boolean notifyEndOfCompute() throws Exception {
+		// TODO Auto-generated method stub
+		return false;
+	}
+
+	@Override
+	public void notifyEndOfRefresh() throws Exception {
+		// TODO Auto-generated method stub
+		
+	}
+
+	@Override
+	public void notifyStartOfCreatePartControl() throws Exception {
+		// TODO Auto-generated method stub
+		
+	}
+
+	@Override
+	public void notifyStartOfRefresh() throws Exception {
+		// TODO Auto-generated method stub
+		
+	}
+	
+	ProgressListener pageProgressListener = null;
+	@Override
+	protected ProgressListener getPageReloadListener() {
+		if (pageProgressListener != null) {
+			return pageProgressListener;
+		}
+		
+		pageProgressListener = new ProgressListener() {
+			
+			@Override
+			public void completed(ProgressEvent event) {
+				if (typeCombo.getSelectionIndex() >= 0) {
+					highlightType();
+				}
+			}
+			
+			@Override
+			public void changed(ProgressEvent event) { }
+		};
+		return pageProgressListener;
+	}
+
+	@Override
+	public boolean needToUpdateIndexes() {
+		return false;
+	}
+	
+	@Override
+	public boolean hasChanges() {
+		return analecCorpus.isModifie();
+	}
+
+	@Override
+	public boolean needToUpdateEditions() {
+		return false;
+	}
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/SchemaToolbar.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/URSAnnotationToolbar.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/URSAnnotationToolbar.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/URSAnnotationToolbar.java	(revision 3653)
@@ -0,0 +1,385 @@
+package org.txm.annotation.urs.toolbar;
+
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.apache.commons.lang.StringUtils;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.ProgressListener;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MenuListener;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.ToolItem;
+import org.txm.annotation.rcp.editor.AnnotationArea;
+import org.txm.annotation.rcp.editor.AnnotationExtension;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.preferences.URSPreferences;
+import org.txm.annotation.urs.view.ElementPropertiesView;
+import org.txm.annotation.urs.view.ElementSearchView;
+import org.txm.core.results.TXMResult;
+import org.txm.edition.rcp.editors.EditionPanel;
+import org.txm.edition.rcp.editors.RGBA;
+import org.txm.edition.rcp.editors.SynopticEditionEditor;
+import org.txm.objects.Text;
+import org.txm.rcp.IImageKeys;
+import org.txm.rcp.editors.TXMEditor;
+import org.txm.rcp.swt.GLComposite;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.searchengine.cqp.corpus.QueryResult;
+import org.txm.searchengine.cqp.corpus.query.CQLQuery;
+import org.txm.searchengine.cqp.corpus.query.Match;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.Message;
+import visuAnalec.Message.TypeMessage;
+import visuAnalec.donnees.Corpus;
+import visuAnalec.donnees.Corpus.CorpusListener;
+import visuAnalec.elements.Element;
+import visuAnalec.elements.Unite;
+import visuAnalec.vue.Vue;
+
+public abstract class URSAnnotationToolbar extends AnnotationArea implements CorpusListener {
+	
+	// see https://groupes.renater.fr/wiki/txm-info/public/specs_charte_graphique
+	public static final RGBA blue = new RGBA(152, 159, 201, 0.7f);
+	
+	public static final RGBA lightblue = new RGBA(185, 193, 239, 0.4f);
+	
+	public static final RGBA green = new RGBA(122, 153, 0, 0.7f);
+	
+	public static final RGBA lightgreen = new RGBA(206, 240, 83, 0.5f);
+	
+	public static final RGBA yellow = new RGBA(255, 255, 50, 1f);
+	
+	public static final RGBA lightyellow = new RGBA(255, 255, 176, 0.5f);
+	
+	protected Corpus analecCorpus;
+	
+	protected Timer saveTimer;
+	
+	protected Vue vue;
+	
+	protected MainCorpus maincorpus;
+	
+	protected SynopticEditionEditor editor;
+	
+//	protected ToolItem button;
+	
+	private Button closeButton;
+
+	private TimerTask saveTask;
+	
+	public URSAnnotationToolbar() {}
+	
+	public abstract void selectFirst();
+	
+	public abstract void selectPrevious();
+	
+	public abstract void select10Previous();
+	
+	public abstract void select10Next();
+	
+	public abstract void selectNext();
+	
+	public abstract void selectLast();
+	
+	public abstract void select(Element currentElement);
+	
+	@Override
+	public boolean save() {
+		if (!analecCorpus.isModifie()) return false;
+		
+		Log.info("Saving URS annotation...");
+		if (URSCorpora.saveCorpus(analecCorpus)) {
+			Log.info("Done: URS annotations saved.");
+			return true;
+		} else {
+			Log.warning("Error: URS annotation not saved.");
+			return false;
+		}
+	}
+	
+	protected abstract boolean _install(TXMEditor<? extends TXMResult> txmeditor, AnnotationExtension extension, Composite parent, int position) throws Exception; 
+
+	@Override
+	public final boolean install(TXMEditor<? extends TXMResult> txmeditor, AnnotationExtension extension, Composite parent, int position) throws Exception {
+		
+		this.extension = extension;
+		this.editor = (SynopticEditionEditor) txmeditor;
+		this.maincorpus = (MainCorpus) this.editor.getCorpus();
+		analecCorpus = URSCorpora.getCorpus(maincorpus);
+		vue = URSCorpora.getVue(maincorpus);
+		
+		if (URSPreferences.getInstance().getInt(URSPreferences.SAVE_TIMER) > 0) {
+			saveTimer = new Timer(true);
+			
+			Log.info("URS auto-save timer is activated (set to "+URSPreferences.getInstance().getInt(URSPreferences.SAVE_TIMER)+" minutes).");
+			
+			saveTask = new TimerTask() {
+				
+				@Override
+				public void run() {
+					
+					Log.fine("URS auto-saving... ", false);
+					if (save()) {
+						Log.fine("Annotations saved.");
+						editor.getParent().getDisplay().syncExec(new Runnable() {
+							
+							@Override
+							public void run() {
+								editor.fireIsDirty();
+							}
+						});
+						
+					} else {
+						//Log.info("Annotations were already saved.");
+					}
+					
+				}
+			};
+			
+			saveTimer.scheduleAtFixedRate(saveTask, URSPreferences.getInstance().getInt(URSPreferences.SAVE_TIMER) * 60L * 1000L, URSPreferences.getInstance().getInt(URSPreferences.SAVE_TIMER) * 60L * 1000L);
+		}
+		annotationArea = new GLComposite(parent, SWT.NONE, "Unit annotation");
+		annotationArea.getLayout().horizontalSpacing = 1;
+		
+		if (getEditorClickListener() != null)
+			editor.getEditionPanel(0).getBrowser().addMouseListener(getEditorClickListener());
+		if (getMenuListener() != null)
+			editor.getEditionPanel(0).getBrowser().getMenu().addMenuListener(getMenuListener());
+		if (getEditorKeyListener() != null)
+			editor.getEditionPanel(0).getBrowser().addKeyListener(getEditorKeyListener());
+		if (getEditorKeyListener() != null)
+			editor.getEditionPanel(0).getBeforeHighlighListeners().add(getPageReloadListener());
+		
+		if (analecCorpus.getStructure().isVide()) {
+			analecCorpus.ajouterType(Unite.class, "Entity");
+			analecCorpus.ajouterProp(Unite.class, "Entity", "Property");
+		}
+		
+//		button = extension.getSaveButton();
+//		button.setEnabled(analecCorpus.isModifie());
+		
+		_install(txmeditor, extension, parent, position);
+		
+		closeButton = new Button(annotationArea, SWT.PUSH);
+		closeButton.setImage(IImageKeys.getImage(IImageKeys.ACTION_DELETE));
+		closeButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				extension.closeArea(URSAnnotationToolbar.this, true);
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		return true;
+	}
+	
+	protected void installCloseButton() {
+		
+	}
+	
+	
+	protected abstract ProgressListener getPageReloadListener();
+	
+	public Corpus getAnalecCorpus() {
+		return analecCorpus;
+	}
+	
+	protected void updatePropertiesView(Element element) {
+		ElementPropertiesView view = ElementPropertiesView.openView();
+		if (view != null) view.loadElement(this.maincorpus, this.analecCorpus, element, this);
+	}
+	
+	@Override
+	public boolean isDirty() {
+		if (analecCorpus != null) return analecCorpus.isModifie();
+		return false;
+	}
+	
+	public boolean isDisposed() {
+		return annotationArea == null || annotationArea.isDisposed();
+	}
+	
+	protected void clearPropertiesView() {
+		ElementPropertiesView view = ElementPropertiesView.openView();
+		if (view != null) {
+			view.unloadElement(this.analecCorpus, this);
+		}
+	}
+	
+	protected static void setFocusInPropertiesView() {
+		ElementPropertiesView view = ElementPropertiesView.openView();
+		if (view != null) {
+			view.setFocusOnProperty();
+		}
+	}
+	
+	protected int[] getSelectionStartEndWordPositions() {
+		EditionPanel panel = this.editor.getEditionPanel(0);
+		String text_name = panel.getEdition().getText().getName();
+		String[] sel = panel.getWordSelection();
+		if (sel == null) {
+			Log.warning("** Error: no word selection");
+			return null;
+		}
+		// System.out.println("Selection="+sel);
+		try {
+			return getStartEndWordPositions(maincorpus, sel, text_name);
+		}
+		catch (CqiClientException e1) {
+			e1.printStackTrace();
+		}
+		return null;
+	}
+	
+	protected int[] getStartEndWordPositions(MainCorpus c, String[] ids, String text_name) throws CqiClientException {
+		// System.out.println("IDS="+Arrays.toString(ids));
+		CQLQuery query = new CQLQuery("[_.text_id=\"" + text_name + "\" & id=\"" + StringUtils.join(ids, "|") + "\"]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+		QueryResult result = c.query(query, "TMP", false); //$NON-NLS-1$
+		List<Match> matches = result.getMatches();
+		int start, end;
+		// try {
+		// int[] indexes = CQPSearchEngine.getCqiClient().str2Id(c.getProperty("id").getQualifiedName(), ids);
+		// int[] positions = CQPSearchEngine.getCqiClient().id2Cpos(c.getProperty("id").getQualifiedName(), indexes);
+		//
+		// } catch (Exception e) {
+		//
+		// }
+		if (matches.size() == 0) {
+			Log.warning(NLS.bind("Error: no match for query={0}", query));
+			return null;
+		}
+		else {
+			start = matches.get(0).getStart();
+			end = matches.get(matches.size() - 1).getStart();
+		}
+		result.drop();
+		return new int[] { start, end };
+	}
+	
+	// listen to corpus structure modification -> enable/disable the button
+	// and to new annotations -> set the star modifier to the Corpus view
+	protected CorpusListener corpusListener = new CorpusListener() {
+		
+		@Override
+		public void traiterEvent(final Message e) {
+			if (maincorpus == null) return;
+			
+			// System.out.println("StartButton.corpusListener.traiterEvent: "+e);
+			
+//			button.getDisplay().syncExec(new Runnable() {
+//				
+//				@Override
+//				public void run() {
+//					if (e.getType() == TypeMessage.MODIF_STRUCTURE) {
+//						boolean ready = URSCorpora.isAnnotationStructureReady(maincorpus);
+//						button.setEnabled(ready);
+//						// if (!ready && utoolbar != null && !utoolbar.isDisposed()) utoolbar.clearHighlight();
+//					}
+//					
+//					if (e.getType() == TypeMessage.MODIF_ELEMENT) {
+//						button.setEnabled(URSCorpora.isAnnotationStructureReady(maincorpus));
+//						if (!maincorpus.isModified()) {
+//							maincorpus.setIsModified(true); // to show the * in corpora view
+//							updateCorporaView(maincorpus);
+//						}
+//						
+//					}
+//					else if (e.getType() == TypeMessage.CORPUS_SAVED) {
+//						button.setEnabled(false);
+//						if (maincorpus.isModified()) {
+//							maincorpus.setIsModified(false); // to remove the * in corpora view
+//							updateCorporaView(maincorpus);
+//						}
+//					}
+//				}
+//			});
+			
+		}
+	};
+	
+	public static void updateCorporaView(final MainCorpus corpus) {
+		CorporaView.refreshObject(corpus);
+	}
+	
+	@Override
+	public boolean discardChanges() {
+		if (maincorpus.isModified()) {
+			URSCorpora.revert(maincorpus);
+			analecCorpus = URSCorpora.getCorpus(maincorpus);
+			vue = URSCorpora.getVue(maincorpus);
+			analecCorpus.removeEventListener(corpusListener);
+			CorporaView.refreshObject(maincorpus);
+		}
+		return false;
+	}
+	
+	public abstract MenuListener getMenuListener();
+	
+	public abstract MouseListener getEditorClickListener();
+	
+	public abstract KeyListener getEditorKeyListener();
+	
+	public abstract void clearHighlight();
+	
+	public abstract void onBackToText(Text text, String id);
+	
+	@Override
+	public SynopticEditionEditor getEditor() {
+		return editor;
+	}
+	
+	@Override
+	public void _close() {
+		
+		this.clearHighlight();
+		
+		try {
+			analecCorpus.removeEventListener(this);
+		}
+		catch (Exception e) {
+		}
+		
+		if (!editor.isDisposed()) {
+			if (this.getEditorClickListener() != null)
+				editor.getEditionPanel(0).getBrowser().removeMouseListener(this.getEditorClickListener());
+			if (this.getMenuListener() != null)
+				editor.getEditionPanel(0).getBrowser().getMenu().removeMenuListener(this.getMenuListener());
+			if (this.getEditorKeyListener() != null)
+				editor.getEditionPanel(0).getBrowser().removeKeyListener(this.getEditorKeyListener());
+			if (this.getPageReloadListener() != null)
+				editor.getEditionPanel(0).getBeforeHighlighListeners().remove(this.getPageReloadListener());
+		}
+		if (annotationArea != null && annotationArea.isDisposed()) annotationArea.dispose();
+		
+		if (saveTimer != null) {
+			saveTimer.cancel();
+		}
+		
+		ElementPropertiesView.closeView();
+		ElementSearchView.closeView();
+		analecCorpus.removeEventListener(corpusListener);
+	}
+	
+	public org.txm.searchengine.cqp.corpus.CQPCorpus getCQPCorpus() {
+		return maincorpus;
+	}
+	
+	public abstract String getElementType();
+	
+	public void fireIsDirty() {
+		editor.fireIsDirty();
+//		this.extension.getSaveButton().setEnabled(true);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/toolbar/URSAnnotationToolbar.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/InstallURSFiles.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/InstallURSFiles.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/InstallURSFiles.java	(revision 3653)
@@ -0,0 +1,93 @@
+package org.txm.annotation.urs;
+
+import java.io.File;
+import java.util.Calendar;
+import java.util.Date;
+
+import org.eclipse.osgi.util.NLS;
+import org.osgi.framework.Version;
+import org.txm.PostTXMHOMEInstallationStep;
+import org.txm.Toolbox;
+import org.txm.annotation.urs.preferences.URSPreferences;
+import org.txm.groovy.core.InstallGroovyFiles;
+import org.txm.objects.Workspace;
+import org.txm.utils.BundleUtils;
+import org.txm.utils.DeleteDir;
+import org.txm.utils.logger.Log;
+
+/**
+ * 
+ * Copy all Groovy scripts in TXMHome directory
+ * 
+ * @author mdecorde
+ *
+ */
+public class InstallURSFiles extends PostTXMHOMEInstallationStep {
+
+	final static String createfolders[] = { "scripts/groovy/user" }; //$NON-NLS-1$
+	
+	@Override
+	public boolean do_install(Workspace workspace) {
+
+//		String saved = URSPreferences.getInstance().getString(URSPreferences.VERSION); //$NON-NLS-1$
+//		Version currentVersion = BundleUtils.getBundleVersion("org.txm.annotation.urs.rcp"); //$NON-NLS-1$
+//		Log.finer("Testing saved version with current version="+currentVersion+" and saved="+saved);
+//		if (saved != null && saved.length() > 0) {
+//			Version savedVersion = new Version(saved);
+//			if (currentVersion.compareTo(savedVersion) <= 0) {
+//				Log.finer(Messages.DoInstallStep_5);
+//				//System.out.println("No post-installation of URS to do");
+//				return true; // nothing to do
+//			}
+//		}
+		
+		File txmhomedir = new File(Toolbox.getTxmHomePath());
+
+		for (String folder : createfolders) {
+			new File(txmhomedir, folder).mkdirs();
+		}
+		File scriptsDirectory = new File(txmhomedir, "scripts/groovy");
+		File userDirectory = new File(scriptsDirectory, "user");
+		File macroDirectory = new File(userDirectory, "org/txm/macro");
+		File URSMacroDirectory = new File(macroDirectory, "urs");
+		
+		String bundle_id = "org.txm.annotation.urs.rcp";
+		
+		if (URSMacroDirectory.exists()) {
+//			long time = URSMacroDirectory.lastModified();
+//			File backDirectory = new File(macroDirectory, "urs-"+Toolbox.dateformat.format(new Date(time)));
+//			Log.info(NLS.bind("Making a copy of the {0} previous URS macros directory to {1}.", URSMacroDirectory, backDirectory));
+//			
+//			URSMacroDirectory.renameTo(backDirectory);
+			
+			InstallGroovyFiles.backupFiles(URSMacroDirectory, userDirectory.getParentFile(), bundle_id);
+			
+			DeleteDir.deleteDirectory(URSMacroDirectory);
+		}
+
+		
+		BundleUtils.copyFiles(bundle_id, "src/", "org/txm/macro", "urs", macroDirectory, true);
+
+		// saving current version
+//		URSPreferences.getInstance().put(URSPreferences.VERSION, currentVersion.toString());
+		
+		return URSMacroDirectory.exists() && URSMacroDirectory.listFiles().length > 0;
+	}
+
+	@Override
+	public String getName() {
+		return "URS Annotation";
+	}
+	
+	@Override
+	public boolean needsReinstall(Workspace workspace) {
+		
+		File txmhomedir = new File(Toolbox.getTxmHomePath());
+		for (String folder : createfolders) {
+			if (!new File(txmhomedir, folder).exists()) {
+				return true;
+			}
+		}
+		return false;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/InstallURSFiles.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSQuery.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSQuery.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSQuery.java	(revision 3653)
@@ -0,0 +1,32 @@
+package org.txm.annotation.urs.search;
+
+import org.txm.Toolbox;
+import org.txm.core.engines.EngineType;
+import org.txm.searchengine.core.IQuery;
+import org.txm.searchengine.core.Query;
+import org.txm.searchengine.core.SearchEngine;
+
+/**
+ * 
+ * Simple implementation of URS query in the "TYPE@PROPERTY=REGEX" form
+ * 
+ * @author mdecorde
+ *
+ */
+public class URSQuery extends Query {
+	
+	public URSQuery() {
+		
+		super("", (SearchEngine) Toolbox.getEngineManager(EngineType.SEARCH).getEngine("URS"));
+	}
+	
+	public URSQuery(String queryString) {
+		
+		super(queryString, (SearchEngine) Toolbox.getEngineManager(EngineType.SEARCH).getEngine("URS"));
+	}
+	
+	@Override
+	public IQuery fixQuery(String lang) {
+		return this;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSQuery.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSSelection.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSSelection.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSSelection.java	(revision 3653)
@@ -0,0 +1,67 @@
+package org.txm.annotation.urs.search;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.txm.objects.Match;
+import org.txm.searchengine.core.IQuery;
+import org.txm.searchengine.core.Selection;
+
+public class URSSelection extends Selection {
+
+	ArrayList<URSMatch> matches;
+	IQuery query;
+	
+	public URSSelection(IQuery query, ArrayList<URSMatch> matches2) {
+		this.query = query;
+		matches = matches2;
+	}
+	
+	@Override
+	public List<? extends Match> getMatches() throws Exception {
+		return matches;
+	}
+
+	@Override
+	public List<? extends Match> getMatches(int from, int to) throws Exception {
+		if (to > matches.size()) to = matches.size();
+		return matches.subList(from, to + 1); // +1 because Match.getMatches is start-end inclusive and List.subList is start inclusif and end exclusif
+	}
+
+	@Override
+	public int getNMatch() throws Exception {
+		return matches.size();
+	}
+
+	@Override
+	public IQuery getQuery() {
+		return query;
+	}
+
+	@Override
+	public boolean isTargetUsed() throws Exception {
+		return false;
+	}
+
+	@Override
+	public void drop() throws Exception {
+		// TODO Auto-generated method stub
+	}
+
+	@Override
+	public boolean delete(int iMatch) {
+		if (iMatch < 0) return false;
+		if (iMatch >= matches.size()) return false;
+		return matches.remove(iMatch) != null;
+	}
+
+	@Override
+	public boolean delete(Match match) {
+		return matches.remove(match);
+	}
+
+	@Override
+	public boolean delete(ArrayList<Match> matchesToRemove) {
+		return matches.removeAll(matchesToRemove);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSSelection.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSSearchEngine.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSSearchEngine.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSSearchEngine.java	(revision 3653)
@@ -0,0 +1,294 @@
+package org.txm.annotation.urs.search;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.core.results.TXMResult;
+import org.txm.objects.CorpusBuild;
+import org.txm.objects.Match;
+import org.txm.searchengine.core.IQuery;
+import org.txm.searchengine.core.Query;
+import org.txm.searchengine.core.SearchEngine;
+import org.txm.searchengine.core.SearchEngineProperty;
+import org.txm.searchengine.core.Selection;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.elements.*;
+
+public class URSSearchEngine extends SearchEngine {
+
+	public static final String NAME = "URS";
+	
+	public URSSearchEngine() {
+		// TODO Auto-generated constructor stub
+	}
+
+	@Override
+	public boolean isRunning() {
+		return true;
+	}
+
+	@Override
+	public boolean initialize() throws Exception {
+		return true;
+	}
+
+	@Override
+	public boolean start(IProgressMonitor monitor) throws Exception {
+		return true;
+	}
+
+	@Override
+	public boolean stop() throws Exception {
+		return true;
+	}
+
+	@Override
+	public void notify(TXMResult r, String state) {
+		// nothing
+	}
+
+	@Override
+	public String getName() {
+		return NAME;
+	}
+
+	@Override
+	public Selection query(CorpusBuild corpus, IQuery query, String name, boolean saveQuery) throws Exception {
+		
+		ArrayList<Element> elements = findAllInCorpus(0, URSCorpora.getCorpus(corpus), corpus, query.getQueryString());
+		ArrayList<URSMatch> matches = new ArrayList<URSMatch>();
+		for (Element e : elements) {
+			matches.add(new URSMatch(e, e.getUnite0().getDeb(), e.getUnite0().getFin()));
+		}
+		return new URSSelection(query, matches);
+	}
+	
+	static String[] getFilterParameters(String URSQL) {
+		
+		String clazz = "U";
+		String type = "";
+		String prop = "";
+		String value = "";
+
+		if (URSQL == null) return new String[] {type, prop, value};
+		
+		int clazzidx = URSQL.indexOf("/"); //TODO parse query to find out which URS Element use (U/R/S/E)
+		int atidx = URSQL.indexOf("@");
+		int equalidx = URSQL.indexOf("=");
+
+		if (atidx >= 0 && equalidx >= 0 && atidx < equalidx) {
+			type = URSQL.substring(0, atidx);
+			prop = URSQL.substring(atidx+1, equalidx);
+			value = URSQL.substring(equalidx+1);
+		} else if (atidx >= 0) {
+			type = URSQL.substring(0, atidx);
+			prop = URSQL.substring(atidx+1);
+		} else if (equalidx >= 0) {
+			type = URSQL.substring(0, equalidx);
+			value = URSQL.substring(equalidx+1);
+		} else {
+			type = URSQL;
+		}
+		//	println(["'"+type+"'", "'"+prop+"'", "'"+value+"'"])
+		Boolean mustmatch  = equalidx <= 0 ||  '!' != URSQL.charAt(equalidx-1);
+ 		
+		return new String[] {clazz, type, mustmatch.toString(), prop, value};
+	}
+	
+	static ArrayList<Element> findAllInCorpus(int debug, Corpus analecCorpus, CorpusBuild corpus, String URSQL) {
+		String[] params = getFilterParameters(URSQL);
+		if (debug >= 2) Log.finer("PARAMS=$params");
+		return findAllInCorpus(debug, analecCorpus, corpus, params[0], params[1], params[3], Boolean.parseBoolean(params[2]), params[4]);
+	}
+	
+	static ArrayList<Element> findAllInCorpus(int debug, Corpus analecCorpus, CorpusBuild corpus, String clazzString, String typeRegex, String propName, boolean valueMustMatch, String valueRegex) {
+		Class<? extends Element> clazz = Unite.class;
+		if ("R".equals(clazzString)) {
+			clazz = Relation.class;
+		} else if ("S".equals(clazzString)) {
+			clazz = Schema.class;
+		}  else if ("E".equals(clazzString)) {
+			clazz = Element.class;
+		}
+		return findAllInCorpus(debug, analecCorpus, corpus, clazz, typeRegex, propName, valueMustMatch, valueRegex);
+	}
+
+	static ArrayList<Element> findAllInCorpus(int debug, Corpus analecCorpus, CorpusBuild corpus, Class<? extends Element> elemClazz, String typeRegex, String propName, boolean valueMustMatch, String valueRegex) {
+		ArrayList<Element> allElements = new ArrayList<Element>();
+
+		if (elemClazz != null) {
+			if (elemClazz == Unite.class)
+				allElements.addAll(analecCorpus.getToutesUnites());
+			else if (elemClazz == Relation.class)
+				allElements.addAll(analecCorpus.getToutesRelations());
+			else if (elemClazz == Schema.class)
+				allElements.addAll(analecCorpus.getTousSchemas());
+		} else {
+			allElements.addAll(analecCorpus.getToutesUnites());
+			allElements.addAll(analecCorpus.getToutesRelations());
+			allElements.addAll(analecCorpus.getTousSchemas());
+		}
+
+		return filterElements(debug, allElements, corpus, typeRegex, propName, valueMustMatch, valueRegex);
+	}
+	
+	/**
+	 * group units by CQP match
+	 * 
+	 * units are sorted for faster processing
+	 * 
+	 * @param allUnites
+	 * @param matches
+	 * @param strict_inclusion
+	 * @return
+	 */
+	static LinkedHashMap groupByMatch(int debug, ArrayList<Element> allUnites, List<? extends Match> matches, boolean strict_inclusion) {
+		if (debug >= 2) Log.finer("group "+allUnites.size()+" units with "+matches.size()+" strict=$strict_inclusion");
+		//println allUnites.collect() {it -> it.getDeb()}
+		Collections.sort(allUnites);// { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() };
+		//println allUnites.collect() {it -> it.getDeb()}
+		int unitsSize = allUnites.size();
+		int iCurrentUnit = 0;
+		ArrayList<Element> selectedUnits = new ArrayList<Element>();
+
+		int matchesSize = matches.size();
+		int iCurrentMatch = 0;
+
+		LinkedHashMap<Match, ArrayList<Element>> selectedUnitsPerMatch = new LinkedHashMap<Match, ArrayList<Element>>();
+		selectedUnitsPerMatch.put(matches.get(iCurrentMatch), selectedUnits);
+
+		while (iCurrentMatch < matchesSize && iCurrentUnit < unitsSize) {
+			if (debug >= 2) Log.finer("** M $iCurrentMatch < $matchesSize && U $iCurrentUnit < $unitsSize");
+
+			Element e = allUnites.get(iCurrentUnit);
+			Unite unit = e.getUnite0();
+			Match match = matches.get(iCurrentMatch);
+			if (debug >= 3) Log.finer(""+unit.getDeb()+"->"+unit.getFin()+"	"+match.getStart()+"->"+match.getEnd());
+			if (unit.getFin() < match.getStart()) {
+				if (debug >= 3) Log.finer("next unit");
+					iCurrentUnit++;
+			} else if (unit.getDeb() > match.getEnd()) {
+				if (debug >= 3) Log.finer("next match");
+					iCurrentMatch++;
+				selectedUnits = new ArrayList<Element>();
+				selectedUnitsPerMatch.put(match, selectedUnits);
+			} else {
+				if (debug >= 3) Log.finer("iCurrentUnit=$iCurrentUnit	iCurrentMatch=$iCurrentMatch");
+				if (strict_inclusion) {
+
+					if (debug >= 3) Log.finer("m.start ${match.getStart()} <= u.deb ${unit.getDeb()} && u.fin ${unit.getFin()} <= m.end ${match.getEnd()}");
+					if (match.getStart() <= unit.getDeb() && unit.getFin() <= match.getEnd()) {
+						selectedUnits.add(unit);
+					}
+				} else {
+					selectedUnits.add(unit);
+				}
+
+				iCurrentUnit++;
+			}
+		}
+		return selectedUnitsPerMatch;
+	}
+
+	static ArrayList<Element> filterUniteByInclusion(int debug, ArrayList<Element> allUnites, List<? extends Match> matches, boolean strict_inclusion, int limit_distance) {
+
+		LinkedHashMap<Match, ArrayList<Element>> selectedUnitsPerMatch = groupByMatch(debug, allUnites, matches, strict_inclusion);
+		//println "selectedUnitsPerMatch size="+selectedUnitsPerMatch.size()
+		ArrayList<Element> selectedUnits = new ArrayList<Element>();
+		if (limit_distance != 0) {
+			if (limit_distance > 0) limit_distance--;
+
+			for (Match m : selectedUnitsPerMatch.keySet()) {
+				ArrayList<Element> units = selectedUnitsPerMatch.get(m);
+				if (units.size() > limit_distance && units.size() > 0) {
+					//println "$m -> "+units.collect() {it -> it.getDeb()}
+					Collections.sort(units);
+					//println "$m -> "+units.collect() {it -> it.getDeb()}
+					selectedUnits.add(units.get(limit_distance));
+					if (debug >=3) Log.finer("dist select: "+units.get(limit_distance).getUnite0().getDeb());
+				}
+			}
+		} else {
+			for (Match m : selectedUnitsPerMatch.keySet()) selectedUnits.addAll(selectedUnitsPerMatch.get(m));
+		}
+
+		return selectedUnits;
+	}
+	
+	static ArrayList<Element> filterElements(int debug, ArrayList<Element> allElements, CorpusBuild corpus, String typeRegex, String propName, boolean valueMustMatch, String valueRegex) {
+		if (debug >= 2) Log.finer("filtering "+allElements.size()+" elements with typeRegex='$typeRegex' propName='$propName' and valueRegex"+(valueMustMatch?"":"!")+"='$valueRegex'");
+		
+		if (corpus != null) {
+			allElements = filterUniteByInclusion(debug, allElements, corpus.getMatches(), true, 0);
+		}
+		
+		if (typeRegex != null && typeRegex.length() > 0) {
+			ArrayList<Element> filteredElements = new ArrayList<Element>();
+			Pattern pattern = Pattern.compile(typeRegex);
+			for (Element element : allElements) {
+				if (pattern.matcher(element.getType()).matches()) {
+					filteredElements.add(element);
+				}
+			}
+
+			allElements = filteredElements;
+		}
+		if (debug >= 2) Log.finer(" type step result: "+allElements.size());
+		
+		if (propName != null && propName.length() > 0) {
+			ArrayList<Element> filteredElements = new ArrayList<Element>();
+			if (valueRegex != null && valueRegex.length() > 0) {  // select only elements with the prop&value
+				Pattern pattern = Pattern.compile(valueRegex);
+				for (Element element : allElements) {
+					String value = element.getProp(propName);
+					if (value != null && pattern.matcher(value).matches() == valueMustMatch) {
+						filteredElements.add(element);
+					}
+				}
+			} else { // select only elements with the prop
+				for (Element element : allElements) {
+					if (element.getProps().containsKey(propName)) {
+						filteredElements.add(element);
+					}
+				}
+			}
+
+			allElements = filteredElements;
+		}
+		if (debug >= 2) Log.finer(" prop&value step result: "+allElements.size());
+		return allElements;
+	}
+	
+	@Override
+	public Query newQuery() {
+		return new URSQuery();
+	}
+
+	@Override
+	public boolean hasIndexes(CorpusBuild corpus) {
+		return URSCorpora.isAnnotationStructureReady(corpus);
+	}
+
+	@Override
+	public String getValueForProperty(Match match, SearchEngineProperty property) {
+		if (match instanceof URSMatch) {
+			return ((URSMatch) match).getValue(property.getName());
+		}
+		return null;
+	}
+
+	@Override
+	public List<String> getValuesForProperty(Match match, SearchEngineProperty property) {
+		ArrayList<String> a = new ArrayList<String>();
+		a.add(getValueForProperty(match, property));
+		return a;
+	}
+
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSSearchEngine.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSMatch.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSMatch.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSMatch.java	(revision 3653)
@@ -0,0 +1,20 @@
+package org.txm.annotation.urs.search;
+
+import org.txm.objects.Match2P;
+
+import visuAnalec.elements.Element;
+
+public class URSMatch extends Match2P {
+
+	Element element;
+	
+	public URSMatch(Element element, int start, int end) {
+		super(start, end);
+		this.element = element;
+	}
+	
+	public String getValue(String property) {
+		return this.element.getProp(property);
+	}
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/search/URSMatch.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/widgets/NavigationField.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/widgets/NavigationField.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/widgets/NavigationField.java	(revision 3653)
@@ -0,0 +1,360 @@
+package org.txm.annotation.urs.widgets;
+
+import org.eclipse.jface.bindings.keys.KeyStroke;
+import org.eclipse.jface.fieldassist.TXMAutoCompleteField;
+import org.eclipse.jface.fieldassist.TextContentAdapter;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseWheelListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowData;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.txm.annotation.urs.Messages;
+import org.txm.annotation.urs.toolbar.URSAnnotationToolbar;
+import org.txm.annotation.urs.toolbar.UnitToolbar;
+import org.txm.annotation.urs.view.ElementSearchView;
+import org.txm.rcp.IImageKeys;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.elements.Unite;
+
+/**
+ * Mimic the List and Combo widget to manage big data volume
+ * 
+ * Don't forget to add a SelectionListener to the parent to manage the selection change
+ * 
+ * @author mdecorde
+ *
+ */
+public class NavigationField extends Composite {
+
+	protected String[] identifiants;
+
+	protected org.eclipse.swt.widgets.Text identifiantCombo;
+	protected Button identifiantComboButtonStart;
+	protected Button identifiantComboButtonUp;
+	protected Button identifiantComboButtonDown;
+	protected Button identifiantComboButtonEnd;
+	protected Button searchButton;
+
+	protected TXMAutoCompleteField identifiantComboAutoCompleteField;
+
+	private URSAnnotationToolbar toolbar;
+
+	public NavigationField(URSAnnotationToolbar parent, int style) {
+		super(parent.getAnnotationArea(), style);
+		this.toolbar = parent;
+		GridLayout layout = new GridLayout(6, false);
+		layout.marginLeft = layout.marginRight = 0;
+		layout.marginWidth = 0;
+		//layout.horizontalSpacing = layout.marginBottom = layout.marginHeight = layout.marginLeft = layout.marginRight = layout.marginTop = layout.marginWidth = 0;
+		this.setLayout(layout);
+
+		//		Composite identifiantComboButtons = new Composite(this, SWT.NONE);
+		//		GridData gdata = new GridData(GridData.FILL, GridData.FILL, false, false);
+		//		identifiantComboButtons.setLayoutData(gdata);
+		//		//identifiantComboButtons.setLayout(new GridLayout(1, true));
+		//		RowLayout fillLayout = new RowLayout(SWT.HORIZONTAL);
+		//		fillLayout.spacing = 0;
+		//		fillLayout.marginHeight = 0;
+		//		fillLayout.marginWidth = 0;
+		//		identifiantComboButtons.setLayout(fillLayout);
+		//		RowData rdata = new RowData();
+		//		//rdata.width = 20;
+		identifiantComboButtonStart = new Button(this, SWT.PUSH);
+		identifiantComboButtonStart.setImage(IImageKeys.getImage(IImageKeys.CTRLSTART));
+		//		identifiantComboButtonStart.setLayoutData(rdata);
+		identifiantComboButtonStart.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				selectFirst();
+				toolbar.getEditor().updateWordStyles();
+			}
+
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) { }
+		});
+		identifiantComboButtonUp = new Button(this, SWT.PUSH);
+		identifiantComboButtonUp.setImage(IImageKeys.getImage(IImageKeys.CTRLREVERSE));
+		//		identifiantComboButtonUp.setLayoutData(rdata);
+		identifiantComboButtonUp.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				selectPrevious();
+				toolbar.getEditor().updateWordStyles();
+			}
+
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) { }
+		});
+
+		identifiantCombo = new org.eclipse.swt.widgets.Text(this, SWT.BORDER);
+		KeyStroke keys = KeyStroke.getInstance(SWT.CONTROL, SWT.SPACE);
+		identifiantComboAutoCompleteField = new TXMAutoCompleteField(identifiantCombo, new TextContentAdapter(), new String[0], keys);
+		Cursor cursor = new Cursor(identifiantCombo.getDisplay(), SWT.CURSOR_SIZENS);
+		identifiantCombo.setCursor(cursor);
+		identifiantCombo.setText(Messages.NavigationField_0);
+
+		GridData gdata2 = new GridData(GridData.FILL, GridData.FILL, true, false);
+		gdata2.minimumWidth = 100;
+		identifiantCombo.setLayoutData(gdata2);
+		identifiantCombo.addKeyListener(new KeyListener() {
+			@Override
+			public void keyReleased(KeyEvent e) {
+				//System.out.println("e:"+e.keyCode);
+				if (identifiantComboAutoCompleteField.isOpen()) return; // ignore keys when content assist is opened
+
+				if (e.keyCode == SWT.ARROW_UP) {
+					selectPrevious();
+					toolbar.getEditor().updateWordStyles();
+				} else if (e.keyCode == SWT.ARROW_DOWN) {
+					selectNext();
+					toolbar.getEditor().updateWordStyles();
+				} else if (e.keyCode == SWT.PAGE_UP) {
+					select10Previous();
+					toolbar.getEditor().updateWordStyles();
+				} else if (e.keyCode == SWT.PAGE_DOWN) {
+					select10Next();
+					toolbar.getEditor().updateWordStyles();
+				}  else if (e.keyCode == SWT.END) {
+					selectLast();
+					toolbar.getEditor().updateWordStyles();
+				} else if (e.keyCode == SWT.HOME) {
+					selectFirst();
+					toolbar.getEditor().updateWordStyles();
+				} else if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+					String id = identifiantCombo.getText().trim();
+					String prefix = type+"-"; //$NON-NLS-1$
+					if (id.startsWith(prefix)) {
+						id = id.substring(prefix.length());
+						//System.out.println("ID: "+id);
+						try {
+							Integer i = Integer.parseInt(id);
+							if (identifiants.length < i) {
+								Log.warning(NLS.bind(Messages.NavigationField_2, identifiantCombo.getText()));
+								return;
+							}
+							setSelectionIndex(i);
+							//notifySelectionChanged(null);
+							toolbar.getEditor().updateWordStyles();
+						} catch(Exception ex) {
+							Log.warning(NLS.bind(Messages.NavigationField_2, identifiantCombo.getText()));
+						}
+					}
+				}
+			}
+
+			@Override
+			public void keyPressed(KeyEvent e) { }
+		});
+		identifiantCombo.addMouseWheelListener(new MouseWheelListener() {
+			@Override
+			public void mouseScrolled(MouseEvent e) {
+				if (identifiantComboAutoCompleteField.isOpen()) return;
+
+				if (e.count > 0) {
+					selectPrevious();
+				} else {
+					selectNext();
+				}
+				//toolbar.getEditor().updateWordStyles();
+			}
+		});
+
+		identifiantComboButtonDown = new Button(this, SWT.PUSH);
+		identifiantComboButtonDown.setImage(IImageKeys.getImage(IImageKeys.CTRLPLAY));
+		//		identifiantComboButtonDown.setLayoutData(rdata);
+		identifiantComboButtonDown.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				selectNext();
+				toolbar.getEditor().updateWordStyles();
+			}
+
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) { }
+		});
+		identifiantComboButtonEnd = new Button(this, SWT.PUSH);
+		identifiantComboButtonEnd.setImage(IImageKeys.getImage(IImageKeys.CTRLEND));
+		//		identifiantComboButtonEnd.setLayoutData(rdata);
+		identifiantComboButtonEnd.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				selectLast();
+				toolbar.getEditor().updateWordStyles();
+			}
+
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) { }
+		});
+
+		searchButton = new Button(this, SWT.PUSH);
+		searchButton.setToolTipText(Messages.NavigationField_4);
+		searchButton.setImage(IImageKeys.getImage(IImageKeys.ACTION_SEARCH));
+		searchButton.setLayoutData(new GridData(GridData.CENTER, GridData.CENTER, false, false));
+		searchButton.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				ElementSearchView view = ElementSearchView.openView();
+				view.loadType(NavigationField.this.toolbar.getCQPCorpus(), 
+						NavigationField.this.toolbar.getAnalecCorpus(), 
+						clazz, 
+						type, 
+						NavigationField.this.toolbar);
+				view.setFocus();
+			}
+		});
+		searchButton.setVisible(false);
+	}
+
+
+
+	protected void notifySelectionChanged(Object object) {
+		Event event = new Event();
+		event.data = identifiantComboIndex;
+		this.notifyListeners(SWT.Selection, event);
+	}
+
+	// This is a set of identifiantCombo control methods to replace the ComboViewer Jface widget
+	protected int identifiantComboIndex = 0;
+	protected int identifiantComboSize = 0;
+
+	private String type;
+
+	private Class clazz;
+	/**
+	 * Set the navigation index AND notify the change value listener
+	 * @param i
+	 */
+	public void setSelectionIndex(int i) {
+		setSelectionIndex(i, true);
+	}
+	/**
+	 * Set the navigation index AND notify the change value listener
+	 * @param i
+	 * @param notify if false listeners won't be notified
+	 */
+	public void setSelectionIndex(int i, boolean notify) {
+		if (identifiantComboSize <= i) return;
+		if (i < 0) return;
+		identifiantComboIndex = i;
+		if (i == 0) {
+			this.identifiantCombo.setText(Messages.NavigationField_5);
+		} else if (type != null && type.length() > 0) {
+			this.identifiantCombo.setText(type+"-"+(i)); //$NON-NLS-1$
+		} else {
+			this.identifiantCombo.setText(""+i); //$NON-NLS-1$
+		}
+		Event e = new Event();
+		e.data = i;
+		if (notify) this.notifyListeners(SWT.Selection, e);
+	}
+	/**
+	 * 
+	 * @param values
+	 * @param type mandatory to display the search button
+	 * @param clazz mandatory to display the search button
+	 */
+	public void setIdentifiants(String[] values, String type, Class clazz) {
+		this.identifiants = values;
+		this.type = type;
+		this.clazz = clazz;
+
+		GridData gdata = (GridData) searchButton.getLayoutData();
+		if (type != null && clazz != null) {
+			searchButton.setVisible(true);
+			gdata.minimumWidth = -1;
+			gdata.widthHint = -1;
+		} else {
+			searchButton.setVisible(false);
+			gdata.minimumWidth = 0;
+			gdata.widthHint = 0;
+		}
+
+		identifiantComboSize = values.length + 1; // + 1 because of <identifiants>
+		identifiantComboAutoCompleteField.setProposals(values);
+	}
+	public int getSelectionIndex() { return identifiantComboIndex;}
+	public int getIdentifiantSize() { return identifiantComboSize;}
+	public String getText() {
+		return identifiantCombo.getText();
+	}
+
+	public void setEnabled(boolean b) {
+		this.identifiantCombo.setEnabled(b);
+		this.identifiantComboButtonStart.setEnabled(b);
+		this.identifiantComboButtonDown.setEnabled(b);
+		this.identifiantComboButtonUp.setEnabled(b);
+		this.identifiantComboButtonEnd.setEnabled(b);
+		this.searchButton.setEnabled(b);
+	}
+
+	public int selectNext() {
+		if (identifiantComboSize == 0) return 0;
+
+		int i = getSelectionIndex();
+		i = (i+1)%identifiantComboSize;
+		setSelectionIndex(i);
+		return i;
+	}
+
+	public int selectPrevious() {
+		if (identifiantComboSize == 0) return 0;
+
+		int i = getSelectionIndex();
+		i = (i-1)%identifiantComboSize;
+		if (i < 0) i = identifiantComboSize + i;
+		setSelectionIndex(i);
+
+		return i;
+	}
+
+	public int selectFirst() {
+		if (identifiantComboSize == 0) return 0;
+
+		int i = 1%identifiantComboSize;
+		setSelectionIndex(i);
+		return i;
+	}
+
+	public int select10Previous() {
+		if (identifiantComboSize == 0) return 0;
+
+		int i = getSelectionIndex();
+		i = (i-10)%identifiantComboSize;
+		if (i < 0) i = identifiantComboSize + i;
+		setSelectionIndex(i);
+		return i;
+	}
+
+	public int select10Next() {
+		if (identifiantComboSize == 0) return 0;
+
+		int i = getSelectionIndex();
+		i = (i+10)%identifiantComboSize;
+		setSelectionIndex(i);
+		return i;
+	}
+
+	public int selectLast() {
+		if (identifiantComboSize == 0) return 0;
+
+		int i = (identifiantComboSize - 1);
+		if (i < 0) i = identifiantComboSize + i;
+		setSelectionIndex(i);
+		return i;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/widgets/NavigationField.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/widgets/TextItem.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/widgets/TextItem.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/widgets/TextItem.java	(revision 3653)
@@ -0,0 +1,30 @@
+package org.txm.annotation.urs.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolBar;
+
+public class TextItem extends Item {
+
+	private ToolBar parent;
+	private Text field;
+
+	public TextItem (ToolBar parent, int style) {
+		super(parent, style);
+		this.parent = parent;
+	}
+	
+	public String getText() {
+		return field.getText();
+	}
+	
+	public void setText(String s) {
+		 field.setText(s);
+	}
+	
+	public void addSelectionListener(SelectionListener listener) {
+		 field.addSelectionListener(listener);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/widgets/TextItem.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/widgets/DropDownButton.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/widgets/DropDownButton.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/widgets/DropDownButton.java	(revision 3653)
@@ -0,0 +1,74 @@
+package org.txm.annotation.urs.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+public class DropDownButton extends Button {
+
+	public DropDownButton(ToolBar parent, int style) {
+		super(parent, style);
+		// TODO Auto-generated constructor stub
+	}
+	
+	public static void main (String [] args) {
+		final Display display = new Display ();
+		final Shell shell = new Shell (display);
+		final ToolBar toolBar = new ToolBar (shell, SWT.NONE);
+		Rectangle clientArea = shell.getClientArea ();
+		toolBar.setLocation(clientArea.x, clientArea.y);
+		final Menu menu = new Menu (shell, SWT.POP_UP);
+		for (int i=0 ; i < 8 ; i++) {
+			MenuItem item = new MenuItem (menu, SWT.PUSH);
+			item.setText ("Item " + i); //$NON-NLS-1$
+			item.addSelectionListener(new SelectionListener() {
+				
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					System.out.println("item "+this); //$NON-NLS-1$
+				}
+				
+				@Override
+				public void widgetDefaultSelected(SelectionEvent e) { }
+			});
+		}
+		
+		ToolItem b1 = new ToolItem(toolBar, SWT.PUSH);
+		b1.setText("push me"); //$NON-NLS-1$
+		
+		final ToolItem item = new ToolItem(toolBar, SWT.DROP_DOWN);
+		item.setText("default item"); //$NON-NLS-1$
+		item.addListener(SWT.Selection, new Listener() {
+			@Override
+			public void handleEvent(Event event) {
+				if (event.detail == SWT.ARROW) {
+					Rectangle rect = item.getBounds();
+					Point pt = new Point(rect.x, rect.y + rect.height);
+					pt = toolBar.toDisplay (pt);
+					menu.setLocation(pt.x, pt.y);
+					menu.setVisible(true);
+				}
+			}
+		});
+		
+		toolBar.pack();
+		shell.pack();
+		shell.open();
+		while (!shell.isDisposed()) {
+			if (!display.readAndDispatch()) display.sleep();
+		}
+		menu.dispose();
+		display.dispose();
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/widgets/DropDownButton.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/view/PropertyField.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/view/PropertyField.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/view/PropertyField.java	(revision 3653)
@@ -0,0 +1,179 @@
+package org.txm.annotation.urs.view;
+
+import java.text.Collator;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Locale;
+
+import org.eclipse.jface.bindings.keys.KeyStroke;
+import org.eclipse.jface.fieldassist.ComboContentAdapter;
+import org.eclipse.jface.fieldassist.TXMAutoCompleteField;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+import visuAnalec.elements.Element;
+
+public class PropertyField extends Composite {
+	
+	String property;
+	ElementPropertiesView view;
+	boolean first = true;
+	
+	public void reinitialiseModify() {
+		first = true;
+	}
+	
+	public PropertyField(Composite parent, int style, String property, ElementPropertiesView view) {
+		
+		super(parent, style);
+		this.property = property;
+		this.view = view;
+		
+		label = new Label(this, SWT.NONE);
+		label.setText(property);
+		label.setAlignment(SWT.RIGHT);
+		label.setToolTipText(NLS.bind("Apply the new ''{0}'' value with the RETURN or TAB keys", property));
+		GridData lData = new GridData(GridData.FILL, GridData.CENTER, false, false);
+		lData.minimumWidth = 75;
+		lData.widthHint = 75;
+		label.setLayoutData(lData);
+		
+		t = new Combo(this, SWT.BORDER);
+		t.setToolTipText(NLS.bind("Apply the new ''{0}'' value with the RETURN or TAB keys", property));
+		GridData tData = new GridData(GridData.FILL, GridData.FILL, true, false);
+		tData.minimumWidth = 150;
+		tData.widthHint = 150;
+		t.setLayoutData(tData);
+		
+		t.addModifyListener(new ModifyListener() {
+			
+			@Override
+			public void modifyText(ModifyEvent e) {
+				if (e.widget.isDisposed()) return;
+				if (first) {
+					first = false;
+				}
+				if (!t.getText().equals(view.getAnalecVue().getValeurChamp(view.element, getProperty()))) {
+					t.setBackground(new Color(t.getDisplay(),254, 216, 177));
+				} else {
+					t.setBackground(null);
+				}
+			}
+		});
+		t.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (!(e.widget instanceof Combo)) return;
+				view.saveFieldValue(PropertyField.this);
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {
+				
+			}
+		});
+		//	t.addKeyListener(allControlsKeyListener);
+		t.addKeyListener(new KeyListener() {
+			@Override
+			public void keyReleased(KeyEvent e) {
+				if (!(e.widget instanceof Combo)) return;
+				if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+					view.saveFieldValue(PropertyField.this);
+					
+				} else if (e.keyCode == SWT.ESC) {
+					//								System.out.println("w:"+e.widget+" key pressed2.");
+					
+					t.setText(view.getAnalecVue().getValeurChamp(view.element, getProperty()));
+				}
+			}
+			
+			@Override
+			public void keyPressed(KeyEvent e) { }
+		});
+		t.addFocusListener(new FocusListener() {
+			
+			@Override
+			public void focusLost(FocusEvent e) {
+				
+				if (PropertyField.this.isDisposed()) return;
+				
+				view.saveFieldValue(PropertyField.this);
+			}
+			
+			@Override
+			public void focusGained(FocusEvent e) { }
+		});
+	}
+	Label label;
+	Combo t;
+	
+	public void setItems(PropertyField t, Element newElement) {
+		
+		// don't use the view to get the values
+		//String[] items = view.getAnalecVue().getValeursChamp(newElement.getClass(), newElement.getType(), t.getProperty());
+		HashSet<String> valueshash = view.getCurrentAnalecCorpus().getStructure().getValeursProp(newElement.getClass(), newElement.getType(), t.getProperty());
+		String[] items = (String[]) valueshash.toArray(new String[valueshash.size()]);
+		
+		Arrays.sort(items, Collator.getInstance(Locale.getDefault()));
+		t.getCombo().setItems(items);
+		KeyStroke keys = KeyStroke.getInstance(SWT.CONTROL, SWT.SPACE);
+		new TXMAutoCompleteField(t.getCombo(), new ComboContentAdapter(), items, keys);
+		
+		t.setEnabled(view.getAnalecVue().isChampModifiable(newElement.getClass(), newElement.getType(), property));
+	}
+	
+	public String getToolTipText() {
+		return t.getToolTipText();
+	}
+	
+	public void setText(String value) {
+		t.setText(value);
+	}
+	
+	public boolean setFocus() {
+		return t.setFocus();
+	}
+	
+	public void update() {
+		super.update();
+		label.update();
+		t.update();
+	}
+	
+	public void setToolTipText(String title) {
+		this.getCombo().setToolTipText(title);
+	}
+	
+	public Combo getCombo() {
+		return t;
+	}
+
+	public String getProperty() {
+		
+		return property;
+	}
+
+	public String getText() {
+		
+		return t.getText();
+	}
+
+	public void setTextBackground(Color color) {
+		
+		t.setBackground(color);
+	}
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/view/PropertyField.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/view/ElementSearchView.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/view/ElementSearchView.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/view/ElementSearchView.java	(revision 3653)
@@ -0,0 +1,711 @@
+package org.txm.annotation.urs.view;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.jface.bindings.keys.KeyStroke;
+import org.eclipse.jface.fieldassist.ComboContentAdapter;
+import org.eclipse.jface.fieldassist.TXMAutoCompleteField;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowData;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.ViewPart;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.Messages;
+import org.txm.annotation.urs.toolbar.URSAnnotationToolbar;
+import org.txm.concordance.core.functions.Concordance;
+import org.txm.concordance.rcp.editors.ConcordanceEditor;
+import org.txm.concordance.rcp.handlers.ComputeConcordance;
+import org.txm.edition.rcp.handlers.BackToText;
+import org.txm.rcp.IImageKeys;
+import org.txm.rcp.utils.SWTEditorsUtils;
+import org.txm.searchengine.cqp.ReferencePattern;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.clientExceptions.InvalidCqpIdException;
+import org.txm.searchengine.cqp.corpus.FakeQueryResult;
+import org.txm.searchengine.cqp.corpus.Property;
+import org.txm.searchengine.cqp.corpus.WordProperty;
+import org.txm.searchengine.cqp.corpus.query.CQLQuery;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.Message;
+import visuAnalec.Message.TypeMessage;
+import visuAnalec.donnees.Corpus;
+import visuAnalec.donnees.Corpus.CorpusListener;
+import visuAnalec.elements.Element;
+import visuAnalec.elements.Unite;
+import visuAnalec.vue.Vue;
+
+public class ElementSearchView extends ViewPart {
+	
+	public static final String ID = ElementSearchView.class.getName();
+	
+	private LinkedHashMap<Combo, String> textWidgets = new LinkedHashMap<>();
+	
+	Element currentElement = null;
+	
+	int currentIndex = -1;
+	
+	ArrayList<Element> matchingElements = new ArrayList<>();
+	
+	URSAnnotationToolbar toolbar;
+	
+	private Composite buttons;
+	
+	private Composite fields;
+	
+	private Text text;
+	
+	private Label label;
+	
+	private Button firstButton;
+	
+	private Button previousButton;
+	
+	private Button nextButton;
+	
+	private Button lastButton;
+	
+	private Button resetButton;
+	
+	private Button searchButton;
+	
+	private Button concordanceButton;
+	
+	RowData cData = new RowData();
+	
+	private GridData lData;
+	
+	private GridData tData;
+	
+	private Corpus analecCorpus;
+	
+	private Class<? extends Element> clazzSearched;
+	
+	private String typeSearched;
+	
+	private Vue vue;
+	
+	private CorpusListener corpusListener = new CorpusListener() {
+		
+		@Override
+		public void traiterEvent(final Message e) {
+			Display.getDefault().syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					// System.out.println("EVENT: "+e);
+					if (fields == null || fields.isDisposed()) return;
+					
+					if (e.getType() == TypeMessage.MODIF_STRUCTURE) {
+						needUpdate = true;
+						loadType(corpus, analecCorpus, clazzSearched, typeSearched, toolbar);
+					}
+				}
+			});
+		}
+	};
+	
+	private boolean needUpdate = false;
+	
+	private SelectionListener selectionChangedListener;
+	
+	private org.txm.searchengine.cqp.corpus.CQPCorpus corpus;
+	
+	private ConcordanceEditor concordanceEditor;
+	
+	private IEditorPart fromEditor;
+	
+	private Concordance concordance;
+	
+	public static void closeView() {
+			IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+			ElementSearchView view = (ElementSearchView) page.findView(ElementSearchView.ID);
+			
+			// close Element View if opened
+			if (view != null) {
+				page.hideView(view);
+			}
+			
+			return;
+	}
+	
+	public static ElementSearchView openView() {
+		// open Element View if not opened
+		try {
+			IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+			ElementSearchView view = (ElementSearchView) page.findView(ElementSearchView.ID);
+			if (view == null) {
+				view = (ElementSearchView) page.showView(ElementSearchView.ID);
+				if (view != null && !view.fields.isDisposed() && view.fields.getParent() != null)
+					view.fields.getParent().layout(); // sometimes the part layout is broken
+			}
+			if (view == null) {
+				Log.warning(NLS.bind("Error ElementPropertiesView view not found: {0}.", ElementSearchView.ID));
+				return null;
+			}
+			view.getSite().getPage().activate(view);
+			return view;
+		}
+		catch (PartInitException e1) {
+			Log.warning(NLS.bind("Part initialisation error: {0}.", e1.getLocalizedMessage()));
+			Log.printStackTrace(e1);
+		}
+		return null;
+	}
+	
+	@Override
+	public void createPartControl(Composite parent) {
+		
+		GridLayout layout = new GridLayout();
+		parent.setLayout(layout);
+		
+		// previous and next buttons
+		buttons = new Composite(parent, SWT.NONE);
+		buttons.setLayout(new GridLayout(10, false));
+		GridData buttons_gdata = new GridData(GridData.FILL, GridData.CENTER, true, false);
+		buttons_gdata.horizontalSpan = 2;
+		buttons.setLayoutData(buttons_gdata);
+		
+		searchButton = new Button(buttons, SWT.PUSH);
+		searchButton.setImage(IImageKeys.getImage(IImageKeys.START));
+		searchButton.setToolTipText("Search elements using the search fields values");
+		searchButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				search();
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		resetButton = new Button(buttons, SWT.PUSH);
+		resetButton.setImage(IImageKeys.getImage("platform:/plugin/org.txm.rcp/icons/cross.png"));
+		resetButton.setToolTipText("Reset the search field values");
+		resetButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				for (Combo c : textWidgets.keySet())
+					c.setText("");
+				
+				ElementSearchView.this.concordanceButton.setEnabled(false);
+				ElementSearchView.this.firstButton.setEnabled(false);
+				ElementSearchView.this.previousButton.setEnabled(false);
+				ElementSearchView.this.nextButton.setEnabled(false);
+				ElementSearchView.this.lastButton.setEnabled(false);
+				ElementSearchView.this.text.setEnabled(false);
+				ElementSearchView.this.resetButton.setEnabled(false);
+				currentElement = null;
+				currentIndex = -1;
+				updateCurrentLabel();
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		label = new Label(buttons, SWT.NONE);
+		label.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+		label.setText("");
+		
+		firstButton = new Button(buttons, SWT.PUSH);
+		firstButton.setImage(IImageKeys.getImage(IImageKeys.CTRLSTART));
+		firstButton.setToolTipText("Select the first match");
+		firstButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				text.setText("" + 1);
+				selectionChangedListener.widgetSelected(null);
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		previousButton = new Button(buttons, SWT.PUSH);
+		previousButton.setImage(IImageKeys.getImage(IImageKeys.CTRLREVERSE));
+		previousButton.setToolTipText("Select the previous match");
+		previousButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				
+				splitViewIfNecessary();
+				int current = Integer.parseInt(text.getText());
+				current--;
+				if (current < 1) current = 1;
+				text.setText("" + current);
+				selectionChangedListener.widgetSelected(null);
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		text = new Text(buttons, SWT.BORDER);
+		text.setText("");
+		text.setToolTipText("Set a match number, and select it with the ENTER key");
+		selectionChangedListener = new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (toolbar == null || toolbar.isDisposed()) return;
+				// System.out.println("SELECTED!!");
+				try {
+					currentIndex = Integer.parseInt(text.getText()) - 1;
+					currentElement = matchingElements.get(currentIndex);
+					toolbar.select(currentElement);
+					updateCurrentLabel();
+				}
+				catch (Exception err) {
+					Log.warning(NLS.bind("Could not set current match: {0}.", err.getLocalizedMessage()));
+				}
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		};
+		text.addSelectionListener(selectionChangedListener);
+		text.addKeyListener(new KeyListener() {
+			
+			@Override
+			public void keyReleased(KeyEvent e) {
+				if (currentElement == null) return;
+				
+				if (e.keyCode == SWT.HOME) {
+					text.setText("" + 1);
+					selectionChangedListener.widgetSelected(null);
+				}
+				else if (e.keyCode == SWT.END) {
+					text.setText("" + matchingElements.size());
+					selectionChangedListener.widgetSelected(null);
+				}
+				else if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+					selectionChangedListener.widgetSelected(null);
+				}
+			}
+			
+			@Override
+			public void keyPressed(KeyEvent e) {}
+		});
+		
+		GridData gdata = new GridData(GridData.FILL, GridData.FILL, false, false);
+		gdata.minimumWidth = 100;
+		gdata.widthHint = 100;
+		text.setLayoutData(gdata);
+		label = new Label(buttons, SWT.NONE);
+		label.setText(" / -");
+		
+		nextButton = new Button(buttons, SWT.PUSH);
+		nextButton.setImage(IImageKeys.getImage(IImageKeys.CTRLPLAY));
+		nextButton.setToolTipText("Select the next match");
+		nextButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				int current = Integer.parseInt(text.getText());
+				current++;
+				if (current > matchingElements.size()) current = matchingElements.size();
+				text.setText("" + current);
+				selectionChangedListener.widgetSelected(null);
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		lastButton = new Button(buttons, SWT.PUSH);
+		lastButton.setImage(IImageKeys.getImage(IImageKeys.CTRLEND));
+		lastButton.setToolTipText("Select the last match");
+		lastButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				text.setText("" + matchingElements.size());
+				selectionChangedListener.widgetSelected(null);
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		concordanceButton = new Button(buttons, SWT.PUSH);
+		concordanceButton.setImage(IImageKeys.getImage(ConcordanceEditor.class, IImageKeys.ACTION_CONCORDANCES));
+		concordanceButton.setToolTipText("View the matches in concordances");
+		concordanceButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				try {
+					toConcordances(e);
+				}
+				catch (Exception e1) {
+					// TODO Auto-generated catch block
+					e1.printStackTrace();
+				}
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		this.searchButton.setEnabled(false);
+		this.concordanceButton.setEnabled(false);
+		this.firstButton.setEnabled(false);
+		this.previousButton.setEnabled(false);
+		this.nextButton.setEnabled(false);
+		this.lastButton.setEnabled(false);
+		this.text.setEnabled(false);
+		this.resetButton.setEnabled(false);
+		
+		fields = new Composite(parent, SWT.NONE);
+		GridData fields_gdata = new GridData(GridData.FILL, GridData.FILL, true, true);
+		fields.setLayoutData(fields_gdata);
+		fields.setLayout(new RowLayout());
+		this.setPartName("Element");
+		
+		// GridDatas to use when a new field is added
+		cData.width = 325;
+		lData = new GridData(GridData.FILL, GridData.CENTER, false, false);
+		lData.minimumWidth = 75;
+		lData.widthHint = 75;
+		tData = new GridData(GridData.FILL, GridData.FILL, true, false);
+		tData.minimumWidth = 150;
+		tData.widthHint = 150;
+		
+		updateCurrentLabel();
+	}
+	
+	protected void splitViewIfNecessary() {
+		
+//		for (IViewReference ref : ElementSearchView.this.getSite().getPage().getViewReferences()) {
+//			System.out.println("ref="+ref+" id="+ref.getId());
+//			if (ref.getId().equals(ElementPropertiesView.class.getName())) {
+//				IWorkbenchPage p = ref.getView(true).getSite().getPage();
+//				MPart mp1 = ref.getView(true).getSite().getService(MPart.class);
+//				MPart mp2 = this.getSite().getService(MPart.class);
+//				SWTEditorsUtils.addPart(mp1, mp2, EModelService.RIGHT_OF, 0.5f);
+//				return;
+//			}
+//		}
+	}
+
+	protected void updateCurrentLabel() {
+		if (currentIndex >= 0) {
+			this.setPartName("" + (currentIndex + 1) + " / " + matchingElements.size() + " " + typeSearched);
+			text.setText("" + (currentIndex + 1));
+			label.setText(" / " + matchingElements.size());
+			text.setEnabled(true);
+		}
+		else {
+			if (typeSearched != null) this.setPartName(typeSearched);
+			text.setText("1");
+			text.setEnabled(false);
+			label.setText(" / -");
+		}
+		label.getParent().layout();
+	}
+	
+	/**
+	 * 
+	 * @param corpus the CQP corpus
+	 * @param analecCorpus the analec corpus
+	 * @param clazz the search Analec Element class (Unite, Schema, Relation)
+	 * @param type the searched Element type
+	 * @param toolbar the annotation toolbar which called loadType
+	 */
+	public void loadType(org.txm.searchengine.cqp.corpus.CQPCorpus corpus, Corpus analecCorpus, Class<? extends Element> clazz, String type, URSAnnotationToolbar toolbar) {
+		if (toolbar == null || toolbar.isDisposed()) return;
+		
+		this.searchButton.setEnabled(true);
+		
+		if (this.analecCorpus != null) { // remove corpus listener from previous corpus
+			this.analecCorpus.removeEventListener(corpusListener);
+		}
+		
+		this.fromEditor = toolbar.getEditor();
+		if (this.corpus != corpus && concordanceEditor != null) {
+			concordanceEditor = null;
+		}
+		this.corpus = corpus;
+		this.analecCorpus = analecCorpus;
+		this.analecCorpus.addEventListener(corpusListener);
+		this.vue = URSCorpora.getVue(analecCorpus);
+		
+		if (this.needUpdate || type.equals(type)) { // no need to rebuild the widgets
+			needUpdate = false;
+			clear(); // remove all previous widgets
+			
+			String[][] props = vue.getChamps(clazz, type);
+			if (props.length > 0)
+				for (String p : props[0]) { // the first is the prop names
+				
+				Composite c = new Composite(fields, SWT.NONE);
+				c.setLayoutData(cData);
+				c.setLayout(new GridLayout(2, false));
+				Label l = new Label(c, SWT.None);
+				l.setText(p);
+				l.setLayoutData(lData);
+				
+				Combo t = new Combo(c, SWT.BORDER);
+				t.setLayoutData(tData);
+				textWidgets.put(t, p);
+				setItems(t, clazz, type, p);
+				t.addKeyListener(new KeyListener() {
+					
+					@Override
+					public void keyReleased(KeyEvent e) {
+						if (!(e.widget instanceof Combo)) return;
+						if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+							search();
+						}
+					}
+					
+					@Override
+					public void keyPressed(KeyEvent e) {}
+				});
+				}
+			fields.layout();
+			fields.getParent().layout();
+		}
+		
+		this.toolbar = toolbar;
+		this.clazzSearched = clazz;
+		this.typeSearched = type;
+		
+		this.setPartName(corpus.getName() + " - " + typeSearched);
+	}
+	
+	public static final String letters = "abcefghijklmnopqrstu";// vwxyz0123456789";
+	
+	public static final int MAXCONCORDANCEQUERYSIZE = 1150; // 1200 in fact
+	// public static String[] doubleletters = new String[letters.length()+ (letters.length()*letters.length())];
+	// static {
+	// for (int i = 0 ; i < letters.length() ; i++) doubleletters[i] = ""+letters.charAt(i);
+	// for (int i = 0 ; i < letters.length() ; i++)
+	// for (int j = 0 ; j < letters.length() ; j++) doubleletters[letters.length()+ i + (j*letters.length())] = ""+letters.charAt(i)+letters.charAt(j);
+	// System.out.println(Arrays.toString(doubleletters));
+	// }
+	//
+	// /**
+	// * just a simple way to create a label using the match length
+	// * @param size
+	// * @return a uniq String if size is < to doubleletters.length()
+	// */
+	// public static String getLetter(int size) {
+	// if (size >= doubleletters.length) return "zzz";
+	// else return doubleletters[size];
+	// }
+	
+	public void toConcordances(SelectionEvent e) throws Exception {
+		if (matchingElements.size() == 0) return;
+		
+		LinkedHashSet<Unite> unites = new LinkedHashSet<>();
+		for (Element m : matchingElements) {
+			for (Unite unite : m.getUnitesSousjacentes()) {
+				unites.add(unite);
+			}
+		}
+		
+		List<Unite> unites_list = new ArrayList<>();
+		unites_list.addAll(unites);
+		Collections.sort(unites_list);
+		
+		int[] starts = new int[unites.size()];
+		int[] ends = new int[unites.size()];
+		int[] targets = null;
+		
+		int i = 0;
+		for (Unite u : unites_list) {
+			starts[i] = u.getDeb();
+			ends[i] = u.getFin();
+			i++;
+		}
+		
+		FakeQueryResult fqr = new FakeQueryResult("SearchViewLink", toolbar.getCQPCorpus(), new CQLQuery(""),
+				starts, ends, targets);
+		
+		HashSet<Integer> sizes = new HashSet<>();
+		for (Unite unite : unites) {
+			int size = unite.getFin() - unite.getDeb() + 1;
+			if (size > letters.length()) size = letters.length() - 1;
+			sizes.add(size);
+		}
+		
+		
+		concordance = null;
+		
+		if (concordanceEditor == null || concordanceEditor.isDisposed()) {
+			concordance = new Concordance(corpus);
+			List<WordProperty> viewProperties = Arrays.asList(corpus.getWordProperty());
+			ReferencePattern ref = new ReferencePattern(corpus.getStructuralUnit("text").getProperty("id"));
+			concordance.setParameters(new CQLQuery(""),
+					viewProperties, viewProperties, viewProperties,
+					viewProperties, viewProperties, viewProperties,
+					ref, ref,
+					7, 10);
+		}
+		else {
+			concordance = concordanceEditor.getConcordance();
+		}
+		concordance.setQueryResult(fqr);
+		
+		e.widget.getDisplay().syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				if (concordanceEditor == null || // no editor opened
+						concordanceEditor.getLineTableViewer().getTable().isDisposed() // editor was closed
+						|| !concordanceEditor.getCorpus().equals(corpus)) { // editor opened but with different corpus
+					
+					IEditorPart editor = ComputeConcordance.openEditor(concordance);
+					if (editor == null) {
+						return;
+					}
+					concordanceEditor = (ConcordanceEditor) editor;
+					
+					if (toolbar.getEditor() != null) {
+						SWTEditorsUtils.addEditor(toolbar.getEditor(), concordanceEditor, EModelService.BELOW);
+					}
+					// BackToText.associateEditors(toolbar.getEditor(), concordanceEditor);
+					toolbar.getEditor().addLinkedEditor(concordanceEditor);
+					concordanceEditor.addLinkedEditor(toolbar.getEditor());
+				}
+				
+				concordanceEditor.compute(false);
+				IWorkbenchPage attachedPage = concordanceEditor.getEditorSite().getPage();
+				attachedPage.activate(concordanceEditor);
+			}
+		});
+	}
+	
+	/**
+	 * start a new search
+	 */
+	public void search() {
+		if (toolbar == null || toolbar.isDisposed()) return;
+		
+		ArrayList<? extends Element> elements = analecCorpus.getElements(clazzSearched, typeSearched);
+		matchingElements.clear();
+		for (Element e : elements) {
+			boolean insert = true;
+			for (Combo w : textWidgets.keySet()) {
+				if (w.getText().trim().length() > 0
+						&& !e.getProp(textWidgets.get(w)).matches(w.getText())) {
+					insert = false;
+					continue;
+				}
+			}
+			if (insert) matchingElements.add(e);
+		}
+		
+		if (matchingElements.size() > 0) {
+			
+			// sort elements
+			Collections.sort(matchingElements, new Comparator<Element>() {
+				
+				@Override
+				public int compare(Element o1, Element o2) {
+					if (o1 == null) return 1;
+					else if (o2 == null) return -1;
+					else if (o1.getUnite0().getDeb() < o2.getUnite0().getDeb()) {
+						return -1;
+					}
+					else if (o1.getUnite0().getDeb() > o2.getUnite0().getDeb()) {
+						return 1;
+					}
+					else if (o1.getUnite0().getFin() < o2.getUnite0().getFin()) {
+						return -1;
+					}
+					else if (o1.getUnite0().getFin() > o2.getUnite0().getFin()) {
+						return 1;
+					}
+					return 0;
+				}
+			});
+			
+			currentElement = matchingElements.get(0);
+			currentIndex = 0;
+			toolbar.select(currentElement);
+			updateCurrentLabel();
+			this.searchButton.setEnabled(true);
+			this.concordanceButton.setEnabled(true);
+			this.firstButton.setEnabled(true);
+			this.previousButton.setEnabled(true);
+			this.nextButton.setEnabled(true);
+			this.lastButton.setEnabled(true);
+			this.text.setEnabled(true);
+			this.resetButton.setEnabled(true);
+		}
+		else {
+			this.concordanceButton.setEnabled(false);
+			this.firstButton.setEnabled(false);
+			this.previousButton.setEnabled(false);
+			this.nextButton.setEnabled(false);
+			this.lastButton.setEnabled(false);
+			this.text.setEnabled(false);
+			this.resetButton.setEnabled(false);
+			currentElement = null;
+			currentIndex = -1;
+			updateCurrentLabel();
+		}
+	}
+	
+	private void setItems(Combo t, Class<? extends Element> clazz, String type, String prop) {
+		String[] items = vue.getValeursChamp(clazz, type, prop);
+		t.setItems(items);
+		KeyStroke keys = KeyStroke.getInstance(SWT.CONTROL, SWT.SPACE);
+		new TXMAutoCompleteField(t, new ComboContentAdapter(), items, keys);
+	}
+	
+	public Corpus getCurrentAnalecCorpus() {
+		return analecCorpus;
+	}
+	
+	@Override
+	public void setFocus() {
+		for (Combo w : textWidgets.keySet()) {
+			w.setFocus();
+			return;
+		}
+	}
+	
+	public void clear() {
+		Control[] children = fields.getChildren();
+		for (int i = 0; i < children.length; i++) {
+			children[i].dispose();
+		}
+		textWidgets.clear();
+		fields.layout();
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/view/ElementSearchView.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/view/ElementPropertiesView.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/view/ElementPropertiesView.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/view/ElementPropertiesView.java	(revision 3653)
@@ -0,0 +1,437 @@
+package org.txm.annotation.urs.view;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowData;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.ViewPart;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.annotation.urs.toolbar.URSAnnotationToolbar;
+import org.txm.rcp.IImageKeys;
+import org.txm.rcp.swt.GLComposite;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.Message;
+import visuAnalec.Message.TypeMessage;
+import visuAnalec.donnees.Corpus;
+import visuAnalec.donnees.Corpus.CorpusListener;
+import visuAnalec.elements.Element;
+import visuAnalec.elements.Schema;
+import visuAnalec.elements.Unite;
+import visuAnalec.vue.Vue;
+
+public class ElementPropertiesView extends ViewPart {
+	
+	public static final String ID = ElementPropertiesView.class.getName();
+	
+	private LinkedHashMap<String, PropertyField> textWidgets = new LinkedHashMap<String, PropertyField>();
+	//private String[][] properties;
+	
+	Element element;
+	URSAnnotationToolbar toolbar;
+	
+	private ToolBar buttons;
+	private Composite fields;
+	private ToolItem firstButton;
+	private ToolItem previousButton;
+	private ToolItem nextButton;
+	private ToolItem lastButton;
+	RowData cData = new RowData();
+	
+	private Corpus analecCorpus;
+	private Vue vue;
+	private CorpusListener corpusListener = new CorpusListener() {
+		@Override
+		public void traiterEvent(final Message e) {
+			Display.getDefault().syncExec(new Runnable() {
+				@Override
+				public void run() {
+					//System.out.println("EVENT: "+e);
+					if (ElementPropertiesView.this.element == null) return;
+					if (fields == null || fields.isDisposed()) return;
+					
+					if (e.getType() == TypeMessage.MODIF_STRUCTURE) {
+						loadElement(corpus, analecCorpus, element, toolbar);
+					} else if (e.getType() == TypeMessage.CORPUS_SAVED) {
+						for (PropertyField c : textWidgets.values()) {
+							if (c.isDisposed()) continue;
+							c.setBackground(null);
+							c.update();
+						}
+					}
+				}
+			});
+			
+		}
+	};
+	
+	private org.txm.searchengine.cqp.corpus.CQPCorpus corpus;
+
+	private ToolItem applyButton;
+
+	private ScrolledComposite sc1;
+
+	private GridLayout glayoutFields;
+	
+	//	private KeyListener allControlsKeyListener;
+	
+	public static void closeView() {
+		IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+		ElementPropertiesView view = (ElementPropertiesView) page.findView(ElementPropertiesView.ID);
+		
+		// close Element View if opened
+		if (view != null) {
+			page.hideView(view);
+		}
+		
+		return;
+	}
+	
+	public static ElementPropertiesView getView() {
+		IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+		return (ElementPropertiesView) page.findView(ElementPropertiesView.ID);
+	}
+	
+	public static ElementPropertiesView openView() {
+		// open Element View if not opened
+		try {
+			IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+			ElementPropertiesView view = (ElementPropertiesView) page.findView(ElementPropertiesView.ID);
+			if (view == null) {
+				view = (ElementPropertiesView) page.showView(ElementPropertiesView.ID);
+				
+				if (view != null && !view.fields.isDisposed() && view.fields.getParent() != null) 
+					view.fields.getParent().layout(); // sometimes the part layout is broken
+			}
+			if (view == null) {
+				Log.warning(NLS.bind("Error ElementPropertiesView view not found: {0}.", ElementPropertiesView.ID));
+				return null;
+			}
+			view.getSite().getPage().activate(view);
+			return view;
+		} catch (PartInitException e1) {
+			Log.warning(NLS.bind("Part initialisation error: {0}", e1.getLocalizedMessage()));
+			Log.printStackTrace(e1);
+		}
+		return null;
+	}
+	
+	@Override
+	public void createPartControl(Composite parent) {
+		
+		GridLayout layout = new GridLayout();
+		parent.setLayout(layout);
+		
+		//previous and next buttons
+		buttons = new ToolBar(parent, SWT.WRAP);
+		GridData buttons_gdata = new GridData(GridData.FILL, GridData.CENTER, false, false);
+		buttons_gdata.horizontalSpan = 2;
+		buttons.setLayoutData(buttons_gdata);
+		
+		firstButton = new ToolItem(buttons, SWT.PUSH);
+		firstButton.setImage(IImageKeys.getImage(IImageKeys.CTRLSTART));
+		//firstButton.setText("First");
+		firstButton.setToolTipText("Select the first element");
+		firstButton.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (toolbar != null && !toolbar.isDisposed()) toolbar.selectFirst();
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) { }
+		});
+		
+		previousButton = new ToolItem(buttons, SWT.PUSH);
+		previousButton.setImage(IImageKeys.getImage(IImageKeys.CTRLREVERSE));
+		//previousButton.setText("Previous");
+		previousButton.setToolTipText("Select the previous element");
+		previousButton.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (toolbar != null && !toolbar.isDisposed()) toolbar.selectPrevious();
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) { }
+		});
+		nextButton = new ToolItem(buttons, SWT.PUSH);
+		nextButton.setImage(IImageKeys.getImage(IImageKeys.CTRLPLAY));
+		//nextButton.setText("Next");
+		nextButton.setToolTipText("Select the next element");
+		nextButton.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (toolbar != null && !toolbar.isDisposed()) toolbar.selectNext();
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) { }
+		});
+		lastButton = new ToolItem(buttons, SWT.PUSH);
+		lastButton.setImage(IImageKeys.getImage(IImageKeys.CTRLEND));
+		//lastButton.setText("Last");
+		lastButton.setToolTipText("Select the last element");
+		lastButton.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (toolbar != null && !toolbar.isDisposed()) toolbar.selectLast();
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) { }
+		});
+		
+		applyButton = new ToolItem(buttons, SWT.PUSH);
+		applyButton.setImage(IImageKeys.getImage(IImageKeys.CHECKED));
+		//applyButton.setText("OK");
+		applyButton.setToolTipText("Apply all new values in the fields");
+		applyButton.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				applyAll();
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) { }
+		});
+		
+		sc1 = new ScrolledComposite(parent, SWT.V_SCROLL);
+		GridLayout glayout = new GridLayout(1, true);
+		glayout.marginBottom = glayout.marginTop = glayout.marginHeight = glayout.verticalSpacing = 0;
+		sc1.setLayout(glayout);
+		sc1.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
+		sc1.setExpandHorizontal(true);
+		sc1.setExpandVertical(true);
+		sc1.setMinSize(0, 120);
+		
+		fields = new Composite(sc1, SWT.NONE);
+		GridData fields_gdata = new GridData(GridData.FILL, GridData.FILL, true, true);
+		fields.setLayoutData(fields_gdata);
+		glayoutFields = new GridLayout();
+		glayoutFields.numColumns = 1;
+		fields.setLayout(glayoutFields);
+		sc1.setContent(fields);
+		fields.addListener( SWT.Resize, event -> {
+			sc1.setMinSize(fields.computeSize(sc1.getParent().getSize().x, SWT.DEFAULT));
+			} );
+		this.setPartName("Element");
+		
+		// GridDatas to use when a new field is added
+		cData.width = 325;
+		
+		parent.addDisposeListener(new DisposeListener() {
+			@Override
+			public void widgetDisposed(DisposeEvent e) {
+				try {
+					if (element != null) { // save previous unit changes
+						
+						for (PropertyField c : textWidgets.values()) {
+							if (c.isDisposed()) continue;
+							saveFieldValue(c);
+						}
+					}
+				} catch(Exception ex) { ex.printStackTrace();}
+			}
+		});		
+	}
+	
+	/**
+	 * Apply all fields values
+	 */
+	public void applyAll() {
+		
+		for (PropertyField c : textWidgets.values()) {
+			if (c.isDisposed()) continue;
+			saveFieldValue(c);
+		}
+		
+	}
+
+	public void unloadElement(Corpus analecCorpus, URSAnnotationToolbar toolbar) {
+		
+		if (this.element != null) { // save previous unit changes
+			for (PropertyField c : textWidgets.values()) {
+				if (c.isDisposed()) continue;
+				saveFieldValue(c);
+			}
+		}
+		
+		if (this.analecCorpus != null) { // remove corpus listener from previous corpus
+			this.analecCorpus.removeEventListener(corpusListener);
+		}
+		
+		clear();
+		this.setPartName("Element");
+		this.setContentDescription("No annotation selected");
+	}
+	
+	public synchronized void loadElement(org.txm.searchengine.cqp.corpus.CQPCorpus corpus, Corpus analecCorpus, Element newElement, URSAnnotationToolbar toolbar) {
+		
+		if (this.element != null) { // save previous unit changes
+			
+			for (PropertyField c : textWidgets.values()) {
+				if (c.isDisposed()) continue;
+				if (!c.isDisposed()) saveFieldValue(c);
+			}
+		}
+		
+		if (this.analecCorpus != null) { // remove corpus listener from previous corpus
+			this.analecCorpus.removeEventListener(corpusListener);
+		}
+		
+		this.corpus = corpus;
+		this.analecCorpus = analecCorpus;
+		this.analecCorpus.addEventListener(corpusListener);
+		this.vue = URSCorpora.getVue(analecCorpus);
+		
+		if (this.element != newElement) {
+			//System.out.println("CLEAR FIELDS");
+			clear();
+		}
+		
+		//if (this.element == null || (!this.element.getType().equals(newElement.getType()))) { // no need to rebuild the widgets
+		//clear(); // remove all previous widgets
+		String[][] props = vue.getChamps(newElement.getClass(), newElement.getType());
+		HashMap<String, Integer> niveaux = vue.getNiveauxChampsAVoir(newElement.getClass(), newElement.getType());
+		HashMap<String, Integer> ordres = vue.getPositionsChampsAVoir(newElement.getClass(), newElement.getType());
+		int ncol = 0;
+		int nline = props.length;
+		for (int l = 0 ; l < props.length ; l++) {
+			if (ncol < props[l].length) ncol = props[l].length;
+			
+		}
+		for (int l = 0 ; l < nline ; l++) {
+			
+			Composite lineComposite = new Composite(fields, SWT.NONE);
+			//lineComposite.getLayout().numColumns = props[l].length;
+			lineComposite.setLayout(new RowLayout());
+			lineComposite.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+			
+			for (String p : props[l]) { // the first is the prop names
+				
+				PropertyField c = null;
+				if (textWidgets.containsKey(p)) {
+					c = textWidgets.get(p);
+				} else {
+					c = new PropertyField(lineComposite, SWT.NONE, p, this);
+					
+					c.setLayoutData(cData);
+					c.setLayout(new GridLayout(2, false));
+					textWidgets.put(p, c);
+				}
+				
+				c.setItems(c, newElement);
+			}
+
+		}
+		
+		//glayoutFields.numColumns = ncol;
+		fields.layout();
+		fields.getParent().layout();
+		
+		//}
+		
+		Log.fine("Refreshing unit properties view with: "+newElement);
+		this.toolbar = toolbar;
+		this.element = newElement;
+		for (PropertyField t : new ArrayList<PropertyField>(textWidgets.values())) {
+			String tname = t.getProperty();
+			if (newElement.getProps().get(tname) != null) {
+				String newValue = newElement.getProps().get(tname);
+				String oldValue = t.getText();
+				//System.out.println("new="+newValue+" old="+oldValue+" differs? "+(!newValue.equals(t.getText())));
+				if (!newValue.equals(oldValue)) {
+					t.setText(newValue);
+				}
+			}
+		}
+		
+		if (newElement instanceof Unite) {
+			Unite unit = (Unite)newElement;
+			if (unit.getDeb() == unit.getFin())
+				this.setPartName(corpus.getName()+" - "+unit.getType()+" ["+unit.getDeb()+"]");
+			else
+				this.setPartName(corpus.getName()+" - "+unit.getType()+" ["+unit.getDeb()+"-"+unit.getFin()+"]");
+		} else if (newElement instanceof Schema) {
+			Schema schema = (Schema)newElement;
+			this.setPartName(corpus.getName()+" - "+schema.getType()+" "+schema.getUnitesSousjacentes().length+" unités");
+		} else {
+			this.setPartName("Element");
+		}
+		this.setContentDescription("");
+	}
+	
+	protected void saveFieldValue(PropertyField c) {
+		if (toolbar == null || toolbar.isDisposed() || c.isDisposed()) return;
+		
+		String newVal = c.getCombo().getText().trim();
+		String v = ElementPropertiesView.this.vue.getValeurChamp(ElementPropertiesView.this.element, c.getProperty());
+		if (!v.equals(newVal) && v != null) {
+			
+			ElementPropertiesView.this.vue.setValeurChamp(ElementPropertiesView.this.element, c.getProperty(), newVal);
+			ElementPropertiesView.this.analecCorpus.isModifie();
+			if (toolbar != null && !toolbar.isDisposed()) this.toolbar.fireIsDirty(); // the Analec corpus should be saved
+			
+			if (!c.isDisposed()) {
+				c.setTextBackground(new Color(c.getDisplay(), 255,255,255));
+				c.update();
+			}
+		}
+	}
+	
+	
+	public Element getCurrentElement() {
+		return element;
+	}
+	
+	public Corpus getCurrentAnalecCorpus() {
+		return analecCorpus;
+	}
+	
+	public void setFocusOnProperty() {
+		for (PropertyField w : textWidgets.values()) {
+			w.setFocus();
+			return;
+		}
+	}
+	
+	public void clear() {
+		Control[] children = fields.getChildren();
+		for (int i = 0 ; i < children.length ; i++) { 
+			children[i].dispose();
+		}
+		if (textWidgets != null) textWidgets.clear();
+		fields.layout();
+	}
+	@Override
+	public void setFocus() {
+		// TODO Auto-generated method stub
+		
+	}
+	public Vue getAnalecVue() {
+		
+		return vue;
+	}
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/view/ElementPropertiesView.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/URSCorpora.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/URSCorpora.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/URSCorpora.java	(revision 3653)
@@ -0,0 +1,314 @@
+package org.txm.annotation.urs;
+
+import java.io.File;
+import java.util.HashMap;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.txm.annotation.core.AnnotationEngine;
+import org.txm.core.results.TXMResult;
+import org.txm.objects.CorpusBuild;
+import org.txm.objects.Project;
+import org.txm.utils.DeleteDir;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.fichiers.FichiersJava;
+import visuAnalec.vue.Vue;
+
+/**
+ * Manages Analec corpus: the corpus are associated with the TXM MainCorpus objects
+ * 
+ * Use URSCorpora.getCorpus(mcorpus) to start using Analec annotations
+ * 
+ * Test if a corpus has Analec annotations URSCorpora.hasCorpus(mcorpus)
+ * 
+ * Save changes with URSCorpora.saveCorpus(mcorpus)
+ * 
+ * @author mdecorde
+ *
+ */
+public class URSCorpora extends AnnotationEngine {
+	
+	private static final HashMap<CorpusBuild, Corpus> corpora = new HashMap<>();
+	
+	private static final HashMap<CorpusBuild, Vue> vues = new HashMap<>();
+	
+	/**
+	 * Create the ec file if needed, store a reference to the corpus if not already done.
+	 * 
+	 * @param mcorpus
+	 * @return the Corpus loaded and stored
+	 */
+	public static Corpus getCorpus(CorpusBuild mcorpus) {
+		mcorpus = mcorpus.getRootCorpusBuild(); // ensure this is the root CorpusBuild
+		File fichierCorpus = getECFile(mcorpus);
+		File fichierVue = getECVFile(mcorpus);
+		Corpus corpus = null;
+		if (URSCorpora.corpora.containsKey(mcorpus)) {
+			corpus = URSCorpora.corpora.get(mcorpus);
+		}
+		else {
+			corpus = new Corpus();
+			
+			if (fichierCorpus.exists()) {
+				if (!FichiersJava.ouvrirCorpus(corpus, fichierCorpus, false)) {
+					System.out.println(NLS.bind(Messages.URSCorpora_3, fichierCorpus));
+					return null;
+				}
+			}
+			else {
+				fichierCorpus.getParentFile().mkdirs();
+				
+				if (!FichiersJava.enregistrerCorpus(corpus, fichierCorpus)) {
+					System.out.println(NLS.bind(Messages.URSCorpora_4, fichierCorpus));
+					return null;
+				}
+			}
+			
+			URSCorpora.corpora.put(mcorpus, corpus);
+			
+			Vue vue = getVue(mcorpus);
+			
+			// TODO: does not work :(
+			if (fichierVue.exists()) {
+				if (!FichiersJava.ouvrirVue(vue, fichierVue)) {
+					Log.warning("Warning: Fail to open corpus Vue file: " + fichierVue);
+					// return null;
+				}
+				String[] types = vue.getTypesUnitesAVoir();
+				if (types == null || types.length == 0) {
+					vue.retablirVueParDefaut();
+				}
+			}
+			else {
+				vue.retablirVueParDefaut(); //
+				if (!FichiersJava.enregistrerVue(vue, fichierVue)) {
+					Log.warning("Warning: Fail to create corpus Vue file: " + fichierVue);
+					// return null;
+				}
+			}
+		}
+		return corpus;
+	}
+	
+	public static boolean isAnnotationStructureReady(CorpusBuild mcorpus) {
+		
+		mcorpus = mcorpus.getRootCorpusBuild(); // ensure this is the root CorpusBuild
+		
+		if (URSCorpora.corpora.containsKey(mcorpus)) {
+			return !URSCorpora.corpora.get(mcorpus).getStructure().isVide();
+		}
+		else {
+			File fichierCorpus = getECFile(mcorpus);
+			if (fichierCorpus.exists()) {
+				return !getCorpus(mcorpus).getStructure().isVide();
+			}
+			else {
+				return false;
+			}
+		}
+	}
+	
+	/**
+	 * need the corpus to be loaded
+	 * 
+	 * @param mcorpus
+	 * @return the corpus Vue
+	 */
+	public static Vue getVue(CorpusBuild mcorpus) {
+		mcorpus = mcorpus.getRootCorpusBuild(); // ensure this is the root CorpusBuild
+		
+		if (!vues.containsKey(mcorpus)) {
+			if (!corpora.containsKey(mcorpus)) {
+				getCorpus(mcorpus);
+			}
+			Corpus corpus = getCorpus(mcorpus);
+			Vue vue = new Vue(corpus);
+			vues.put(mcorpus, vue);
+		}
+		return vues.get(mcorpus);
+	}
+	
+	/**
+	 * Has a Vue being loaded for a Corpusbuild
+	 * 
+	 * @param mcorpus
+	 * @return true if a Vue is loaded
+	 */
+	public static boolean hasVue(CorpusBuild mcorpus) {
+		mcorpus = mcorpus.getRootCorpusBuild(); // ensure this is the root CorpusBuild
+		
+		return vues.containsKey(mcorpus);
+	}
+	
+	/**
+	 * Save the associated AnalecCorpus
+	 * 
+	 * @param mcorpus
+	 * @return true if the annotations have been saved
+	 */
+	public static boolean saveCorpus(CorpusBuild mcorpus) {
+		mcorpus = mcorpus.getRootCorpusBuild(); // ensure this is the root CorpusBuild
+		if (hasCorpus(mcorpus)) {
+			Corpus corpus = getCorpus(mcorpus);
+			Vue vue = getVue(mcorpus);
+			
+			File fichierCorpus = getECFile(mcorpus);
+			File fichierVueCorpus = getECVFile(mcorpus);
+			fichierCorpus.getParentFile().mkdirs();
+			
+			return FichiersJava.enregistrerCorpus(corpus, fichierCorpus) && FichiersJava.enregistrerVue(vue, fichierVueCorpus);
+		} else {
+			return false;
+		}
+	}
+	
+	public static Vue getVue(Corpus corpus) {
+		for (CorpusBuild mcorpus : corpora.keySet()) {
+			if (corpora.get(mcorpus) == corpus) return vues.get(mcorpus);
+		}
+		return null;
+	}
+	
+	public static boolean saveCorpus(Corpus corpus) {
+		for (CorpusBuild mcorpus : corpora.keySet()) {
+			if (corpora.get(mcorpus) == corpus) return saveCorpus(mcorpus);
+		}
+		return false;
+	}
+	
+	public static void removeCorpus(CorpusBuild mcorpus) {
+		
+		mcorpus = mcorpus.getRootCorpusBuild(); // ensure this is the root CorpusBuild
+		
+		if (!vues.containsKey(mcorpus)) {
+			vues.remove(mcorpus);
+		}
+		if (!corpora.containsKey(mcorpus)) {
+			corpora.remove(mcorpus);
+		}
+	}
+	
+	public static void revert(CorpusBuild mcorpus) {
+		
+		mcorpus = mcorpus.getRootCorpusBuild(); // ensure this is the root CorpusBuild
+		Corpus acorpus = corpora.get(mcorpus);
+		if (acorpus == null) return;
+		corpora.remove(mcorpus);
+		vues.remove(mcorpus);
+		mcorpus.setIsModified(false);
+	}
+	
+	@Override
+	public boolean isRunning() {
+		return true;
+	}
+	
+	@Override
+	public boolean initialize() throws Exception {
+		return true;
+	}
+	
+	@Override
+	public boolean start(IProgressMonitor monitor) throws Exception {
+		return true;
+	}
+	
+	@Override
+	public boolean stop() throws Exception {
+		return true;
+	}
+	
+	@Override
+	public void notify(TXMResult r, String state) {
+		if (r instanceof CorpusBuild && "clean".equals(state)) { // $NON-NLS
+			CorpusBuild mcorpus = (CorpusBuild) r;
+			mcorpus = mcorpus.getRootCorpusBuild(); // ensure this is the root CorpusBuild
+			
+			if (URSCorpora.hasCorpus(mcorpus)) {
+				Corpus analec_corpus = URSCorpora.getCorpus(mcorpus);
+				analec_corpus.fermer();
+			}
+			
+			URSCorpora.removeCorpus(mcorpus);
+			
+			File fichierCorpus = getECFile(mcorpus); 
+			File fichierVue = getECVFile(mcorpus);
+			fichierCorpus.delete();
+			fichierVue.delete();
+		}
+		else if (r instanceof Project) {
+			Project project = ((Project) r);
+			if ("clean".equals(state)) {
+				File analecDir = new File(project.getProjectDirectory(), "analec"); //$NON-NLS
+				if (analecDir.exists()) {
+					DeleteDir.deleteDirectory(analecDir);
+				}
+			}
+			else if ("save".equals(state)) {
+				for (TXMResult c : project.getChildren(CorpusBuild.class)) {
+					URSCorpora.saveCorpus((CorpusBuild) c);
+				}
+			}
+		}
+	}
+	
+	@Override
+	public String getName() {
+		return "URS";
+	}
+	
+	@Override
+	public boolean isAutomatic() {
+		
+		return false;
+	}
+	
+	@Override
+	public boolean processFile(File xmlFile, File binaryCorpusDirectory, HashMap<String, Object> parameters) {
+		
+		return false;
+	}
+	
+	@Override
+	public String getDetails() {
+		
+		return corpora.toString();
+	}
+	
+	@Override
+	public boolean hasAnnotationsToSave(CorpusBuild mcorpus) {
+		
+		return hasAnnotationsToSaveStatic(mcorpus);
+	}
+	
+	public static boolean hasAnnotationsToSaveStatic(CorpusBuild mcorpus) {
+		
+		if (corpora.isEmpty()) return false;
+		if (!URSCorpora.hasCorpus(mcorpus)) return false; // no corpus instanced -> no annotations to save
+		return URSCorpora.getCorpus(mcorpus).isModifie();
+	}
+	
+	/**
+	 * 
+	 * @param mcorpus
+	 * @return true is an Analec corpus is already instanced
+	 */
+	public static boolean hasCorpus(CorpusBuild mcorpus) {
+		
+		if (!corpora.containsKey(mcorpus)) {
+			return getECFile(mcorpus).exists();
+		}
+		
+		return true;
+	}
+	
+	public static File getECFile(CorpusBuild mcorpus) {
+		return new File(mcorpus.getProjectDirectory(), "analec/" + mcorpus.getID() + ".ec"); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+	
+	public static File getECVFile(CorpusBuild mcorpus) {
+		return new File(mcorpus.getProjectDirectory(), "analec/" + mcorpus.getID() + ".ecv"); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/URSCorpora.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/export/HookableStaxIdentityParser.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/export/HookableStaxIdentityParser.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/export/HookableStaxIdentityParser.java	(revision 3653)
@@ -0,0 +1,48 @@
+package org.txm.annotation.urs.export;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.IOException;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.txm.importer.StaxIdentityParser;
+
+public class HookableStaxIdentityParser extends StaxIdentityParser {
+
+	
+	String hookPath;
+	private XMLStreamWriter hookedwriter;
+	private BufferedOutputStream hookedoutput;
+	private XMLStreamReader hookedparser;
+	
+	public HookableStaxIdentityParser(File infile, String hookPath) throws IOException, XMLStreamException {
+		super(infile);
+		// TODO Auto-generated constructor stub
+	}
+
+	public boolean process(XMLStreamWriter awriter) throws XMLStreamException, IOException
+	{
+		this.writer = awriter;
+		goToEnd(hookPath); // write all until text is reached
+		this.hookedwriter = writer;
+		this.hookedoutput = output;
+		this.hookedparser = parser;
+		this.writer = null;
+		this.output = null;
+		this.parser = null;
+		return true;
+	}
+	
+	public XMLStreamWriter getWriter() {
+		return hookedwriter;
+	}
+	
+	public void close() throws XMLStreamException, IOException {
+		hookedwriter.close();
+		hookedoutput.close();
+		hookedparser.close();
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/export/HookableStaxIdentityParser.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/export/ExportToGlozzMacro.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/export/ExportToGlozzMacro.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/export/ExportToGlozzMacro.java	(revision 3653)
@@ -0,0 +1,192 @@
+package org.txm.annotation.urs.export;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashSet;
+
+import org.eclipse.osgi.util.NLS;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.searchengine.cqp.AbstractCqiClient;
+import org.txm.searchengine.cqp.CQPSearchEngine;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.searchengine.cqp.corpus.Property;
+import org.txm.searchengine.cqp.serverException.CqiServerError;
+import org.txm.utils.io.IOUtils;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.Unite;
+import visuAnalec.fichiers.FichiersGlozz.ModelGlozzPrinter;
+
+/**
+ * @author: Bruno Oberlé
+ * 
+ *          v1.0.0 2017-08-28
+ * 
+ *          adapted and included in TXM by mdecorde
+ * 
+ *          Cette macro exporte le corpus sélectionné et ses annotations vers deux fichiers de format Glozz:
+ *          - un fichier .ac contenant le corpus brut,
+ *          - un fichier .aa contenant les annotations au format XML utilisé par Glozz,
+ *          - un fichier .aam contenant la structure d'annotation.
+ * 
+ *          Le corpus sélectionné dans TXM devrait contenir une structure Analec avec au moins un type d'unité défini (e.g. MENTION, maillon, etc.). S'il n'y a pas de structure,
+ *          ce n'est pas grave: le fichier est exporter, mais aucune annotation n'est créer. Cela permet d'exporter n'importe quel corpus au format Glozz.
+ * 
+ *          Pour exporter un texte au format Glozz *sans* les annotations qu'il contient, simplement mettre un unit_type qui n'existe pas (e.g. "foobar" au lieu de "MENTION").
+ * 
+ *          deprecated: La macro ne produit pour l'instant pas automatiquement de modèle Glozz (fichier .aam). Cela n'est pas un problème pour ouvrir le résultat dans Glozz ou Analec.
+ **/
+public class ExportToGlozzMacro {
+	
+	public void doExport(MainCorpus corpus, String unit_type, String filename) throws NumberFormatException, IOException, CqiServerError, CqiClientException {
+		
+		// export the annotation structure as a glozz model
+		Corpus analecCorpus = URSCorpora.getCorpus(corpus);
+		if (analecCorpus == null) {
+			Log.warning("No Analec corpus associated with $corpus");
+			return;
+		}
+		Log.info("Writing annotation structure...");
+		PrintWriter model = null;
+		File fichierModel = new File(filename + ".aam");
+		try {
+			Structure structure = analecCorpus.getStructure();
+			model = new PrintWriter(fichierModel, "UTF-8");
+			ModelGlozzPrinter gp = new ModelGlozzPrinter(structure, model);
+			gp.ecrireModel();
+		}
+		catch (Exception ex) {
+			Log.warning(NLS.bind("Erreur d'écriture de fichier: {0}.", ex));
+		}
+		finally {
+			if (model != null) model.close();
+			Log.info(NLS.bind("Annotations structure written to ''{0}''.", fichierModel));
+		}
+		
+		int size = corpus.getSize(); // you may also use:
+		// corpus.getTextEndLimits() (= index of
+		// last token = size-1)
+		AbstractCqiClient CQI = CQPSearchEngine.getCqiClient();
+		Property word = corpus.getWordProperty();
+		// note: using "lbn" seems to work better than "pn" (some imported
+		// corpora are missing this information)
+		// pn = corpus.getProperty("pn")
+		// if (pn == null) pn = corpus.getProperty("div")
+		Property pn = corpus.getProperty("lbn");
+		
+		// BUILD THE RAW TEXT, THE POSITIONS AND FIND THE PARAGRAPHS
+		
+		String rawText = ""; // the corpus for the .ac file
+		ArrayList<int[]> positions = new ArrayList<>(); // each element is an array
+		// [start, end] indicating the
+		// position in the rawText
+		int pnCount = 0; // the par counter, used for indexing the pns array
+		int lastPn = -1; // the last paragraph number
+		ArrayList<int[]> pns = new ArrayList<>(); // each element is an array [start,
+		// end] representing the start and
+		// end of the paragraph in the
+		// rawText
+		int end = -1;
+		for (int i = 0; i < size; i++) {
+			String f = CQI.cpos2Str(word.getQualifiedName(), new int[] { i })[0];
+			int p = 0;
+			if (pn == null) {
+				p = 1;
+			}
+			else {
+				p = Integer.parseInt(CQI.cpos2Str(pn.getQualifiedName(), new int[] { i })[0]);
+			}
+			int start = rawText.length();
+			rawText += f;
+			if (lastPn != p) {
+				pnCount++;
+				if (pnCount > 1 && pns.size() > 0) {
+					pns.get(pnCount - 2)[1] = end;
+				}
+				pns.add(new int[] { start, 0 });
+			}
+			lastPn = p;
+			end = rawText.length(); // must be after setting it up in pns!
+			if (i != size - 1)
+				rawText += " ";
+			positions.add(new int[] { start, end });
+		}
+		pns.get(pnCount - 1)[1] = end;
+		Log.info(NLS.bind("{0} paragraph(s) found.", pnCount));
+		
+		// CORPUS ANALEC (GET THE ANNOTATIONS)
+		
+		// note that unit_type has been defined with an option of the dialog at
+		// the beginning
+		
+		
+		// list of properties
+		
+		Structure struct = analecCorpus.getStructure();
+		HashSet<String> propertyList = struct.getUniteProperties(unit_type);
+		
+		// export to file (corpus)
+		
+		Log.info("Writing corpus...");
+		String corpusFilename = filename + ".ac";
+		File corpusFile = new File(corpusFilename);
+		PrintWriter corpusFileWriter = IOUtils.getWriter(corpusFile);
+		corpusFileWriter.write(rawText);
+		corpusFileWriter.close();
+		Log.info(NLS.bind("Corpus written to ''{0}''.", corpusFilename));
+		
+		// export to file (annotations)
+		Log.info("Writing annotations...");
+		String annotFilename = filename + ".aa";
+		File annotFile = new File(annotFilename);
+		PrintWriter annotFileWriter = IOUtils.getWriter(annotFile);
+		annotFileWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<annotations>"); // erase
+		int counter = 0;
+		
+		// export paragraphs
+		for (int i = 0; i < pns.size(); i++) {
+			int start = pns.get(i)[0];
+			end = pns.get(i)[1];
+			annotFileWriter.println("<unit id=\"me_" + counter + "\">");
+			annotFileWriter.println("<metadata><author>me</author><creation-date>" + counter + "</creation-date></metadata>");
+			annotFileWriter.println("<characterisation><type>paragraph</type><featureSet /></characterisation>");
+			annotFileWriter.println("<positioning><start><singlePosition index=\"" + start + "\" /></start><end><singlePosition index=\"" + end + "\" /></end></positioning>");
+			annotFileWriter.println("</unit>");
+			counter++;
+		}
+		
+		// export units
+		ArrayList<Unite> units = analecCorpus.getUnites(unit_type);
+		// units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=>
+		// b.getFin() };
+		int unitCount = 0;
+		for (Unite unit : units) {
+			unitCount++;
+			annotFileWriter.println("<unit id=\"me_" + counter + "\">");
+			annotFileWriter.println("<metadata><author>me</author><creation-date>" + counter + "</creation-date></metadata>");
+			annotFileWriter.println("<characterisation>");
+			annotFileWriter.println("<type>" + unit_type + "</type>");
+			annotFileWriter.println("<featureSet>");
+			for (String propertyName : propertyList) {
+				annotFileWriter.println("<feature name=\"" + propertyName + "\">" + unit.getProp(propertyName) + "</feature>");
+			}
+			annotFileWriter.println("</featureSet>");
+			annotFileWriter.println("</characterisation>");
+			int start = positions.get(unit.getDeb())[0];
+			end = positions.get(unit.getFin())[1];
+			annotFileWriter.println("<positioning><start><singlePosition index=\"" + start + "\" /></start><end><singlePosition index=\"" + end + "\" /></end></positioning>");
+			annotFileWriter.println("</unit>");
+			counter++;
+		}
+		annotFileWriter.println("</annotations>");
+		annotFileWriter.close();
+		Log.info(NLS.bind("{0} unit(s) found.", unitCount));
+		
+		Log.info(NLS.bind("Annotations written to the''{0}''.", annotFile));
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/export/ExportToGlozzMacro.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/export/URSAnnotationTEIExporter.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/export/URSAnnotationTEIExporter.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/export/URSAnnotationTEIExporter.java	(revision 3653)
@@ -0,0 +1,583 @@
+package org.txm.annotation.urs.export;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.commons.lang.StringUtils;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.importer.PersonalNamespaceContext;
+import org.txm.importer.StaxIdentityParser;
+import org.txm.scripts.importer.StaxStackWriter;
+import org.txm.searchengine.cqp.CQPSearchEngine;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.searchengine.cqp.corpus.Property;
+import org.txm.searchengine.cqp.corpus.StructuralUnit;
+import org.txm.utils.BundleUtils;
+import org.txm.utils.DeleteDir;
+import org.txm.utils.io.FileCopy;
+import org.txm.utils.logger.Log;
+import org.txm.utils.zip.Zip;
+
+import visuAnalec.donnees.Corpus;
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.Element;
+import visuAnalec.elements.Relation;
+import visuAnalec.elements.Schema;
+import visuAnalec.elements.Unite;
+import visuAnalec.fichiers.FichiersGlozz;
+import visuAnalec.fichiers.FichiersJava;
+import visuAnalec.vue.Vue;
+
+/**
+ * Analec annotations exporter. It uses the XML-TXM format described at https://groupes.renater.fr/wiki/txm-info/public/xml_tei_txm
+ * 
+ * @author mdecorde
+ *
+ */
+public class URSAnnotationTEIExporter {
+
+	public static final DateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
+	
+	protected File outputDirectory;
+	protected MainCorpus mainCorpus;
+	protected Property wordid;
+	protected Corpus analecCorpus;
+	protected Vue analecVue;
+	protected IProgressMonitor monitor;
+	protected boolean copyXMLTXMFiles = true;
+
+	/**
+	 * 
+	 * @param monitor may be null
+	 * @param outputDirectory
+	 * @param mainCorpus
+	 * @param analecCorpus
+	 * @param analecVue
+	 */
+	public URSAnnotationTEIExporter(IProgressMonitor monitor, File outputDirectory, MainCorpus mainCorpus, Corpus analecCorpus, Vue analecVue, boolean copyXMLTXMFiles) {
+		this.outputDirectory = outputDirectory;
+		this.mainCorpus = mainCorpus;
+		this.analecCorpus = analecCorpus;
+		this.analecVue = analecVue;
+		this.monitor = monitor;
+		this.copyXMLTXMFiles = copyXMLTXMFiles;
+	}
+
+	/**
+	 * 1- Copy the XML-TXM files
+	 * 2- Write the annotations
+	 * 3- Write the structure
+	 * 4- Write the view
+	 * 
+	 * @return true if success
+	 * @throws Exception
+	 */
+	public boolean process(boolean standoff, boolean createArchive) throws Exception {
+		
+		if (!standoff) {
+			Log.warning("Inligned annotations not implemented yet. Aborting");
+			return false;
+		}
+
+		wordid = mainCorpus.getProperty("id");
+		int[] starts = mainCorpus.getTextStartLimits();
+		int[] ends = mainCorpus.getTextEndLimits();
+		StructuralUnit su_text = mainCorpus.getStructuralUnit("text");
+		int[] strucs = CQPSearchEngine.getCqiClient().cpos2Struc(su_text.getQualifiedName(), starts);
+		String[] ids = CQPSearchEngine.getCqiClient().struc2Str(su_text.getProperty("id").getQualifiedName(), strucs);
+
+		File textsDirectory = new File(outputDirectory, "texts");
+		textsDirectory.mkdir();
+		File annotationsDirectory = new File(outputDirectory, "annotations");
+		if (standoff) annotationsDirectory.mkdir();
+
+		if (monitor != null) monitor.beginTask("Writing annotations...", starts.length);
+		for (int i = 0 ; i < starts.length ; i++) {
+			File xmltxmFile = new File(textsDirectory, ids[i]+".xml");
+			File xmltxmAnalecFile = new File(annotationsDirectory, ids[i]+"-urs.xml");
+			if (monitor != null) monitor.subTask(ids[i]+" text...");
+			processText(standoff, xmltxmFile, xmltxmAnalecFile, ids[i], starts[i], ends[i]);
+			if (monitor != null) monitor.worked(1);
+		}
+
+		if (monitor != null) monitor.beginTask("Writing structure", 1);
+
+		//FichiersGlozz.exporterModeleGlozz(analecCorpus.getStructure());
+		File xmltxmStructureFile = new File(outputDirectory, mainCorpus.getName()+".aam");
+		PrintWriter model = new PrintWriter(xmltxmStructureFile, "UTF-8");
+		FichiersGlozz.ModelGlozzPrinter gp = new FichiersGlozz.ModelGlozzPrinter(analecCorpus.getStructure(), model);
+		gp.ecrireModel();
+		model.close();
+		
+		//FichiersGlozz.exporterModeleGlozz(analecCorpus.getStructure());
+		File fichierVueCorpus = new File(outputDirectory, mainCorpus.getName()+".ev");
+		FichiersJava.enregistrerVue(analecVue, fichierVueCorpus);
+
+		//		File xmltxmStructureFile = new File(outputDirectory, mainCorpus.getName()+"-structure.xml");
+		//		StaxStackWriter writer = new StaxStackWriter(xmltxmStructureFile);
+		//		PersonalNamespaceContext Nscontext = new PersonalNamespaceContext();
+		//		writer.setNamespaceContext(Nscontext);
+		//		writer.writeStartElement(StaxIdentityParser.TEINS, "TEI");
+		//		writer.writeNamespace("tei", StaxIdentityParser.TEINS);
+		//		writer.writeStartElement("teiHeader");
+		//		writer.writeStartElement("fileDesc");
+		//		writer.writeStartElement("titleStmt");
+		//		writer.writeStartElement("title");
+		//		writer.writeCharacters(mainCorpus.getName()+" - structure");
+		//		writer.writeEndElement(); // title
+		//		writer.writeStartElement("respStmt");
+		//		writer.writeStartElement("resp");
+		//		writer.writeCharacters("annotated by");
+		//		writer.writeEndElement(); // resp
+		//		writer.writeStartElement("name");
+		//		writer.writeCharacters("non renseigné");
+		//		writer.writeEndElement(); // name
+		//		writer.writeEndElement(); // respStmt
+		//		writer.writeEndElement(); // titleStmt
+		//		writer.writeStartElement("publicationStmt");
+		//		writer.writeStartElement("publisher");
+		//		writer.writeCharacters("non renseigné");
+		//		writer.writeEndElement(); // publisher
+		//		writer.writeEndElement(); // publicationStmt
+		//		writer.writeStartElement("sourceDesc");
+		//		writer.writeStartElement("bibl");
+		//		writer.writeCharacters("non renseigné");
+		//		writer.writeEndElement(); // bibl
+		//		writer.writeEndElement(); // sourceDesc
+		//		writer.writeEndElement(); // fileDesc
+		//		writer.writeEndElement(); // teiHeader
+		//		writer.writeStartElement("text");
+		//		writer.writeStartElement("back");
+		//		writeStructure(writer);
+		//		writer.writeEndElement(); // back
+		//		writer.writeEndElement(); // text
+		//		writer.writeEndElement(); // TEI
+		//		writer.close();
+
+		if (monitor != null) monitor.worked(1);
+
+		if (createArchive) {
+			if (monitor != null) monitor.subTask("Creating archive...");
+			File zipArchive = new File(outputDirectory+".urs");
+			Zip.compress(outputDirectory, zipArchive);
+			DeleteDir.deleteDirectory(outputDirectory);
+			Log.info(NLS.bind("Done: {0}.", zipArchive));
+		} else {
+			Log.info(NLS.bind("Done: {0}.", outputDirectory));
+		}
+
+		return true;
+	}
+
+	protected boolean processText(boolean standoff, File xmltxmFile, File xmltxmAnalecFile, String textid, int from, int to) throws Exception {
+		
+		Log.info(NLS.bind("Processing text: {0}", textid));
+
+		// 1) copy the XML-TXM file
+		File xmltxmFileFromBin = new File(mainCorpus.getProjectDirectory(), "txm/"+mainCorpus.getName().toUpperCase()+"/"+textid+".xml");
+		if (!xmltxmFileFromBin.exists()) {
+			Log.warning(NLS.bind("Error: could not find the XML-TXM reference file: {0}.", xmltxmFileFromBin));
+			return false;
+		}
+
+		if (copyXMLTXMFiles) {
+			if (!FileCopy.copy(xmltxmFileFromBin, xmltxmFile)) {
+				Log.warning(NLS.bind("Error: could not copy the XML-TXM reference file: {0}.", xmltxmFileFromBin));
+				return false;
+			}
+		}
+
+		XMLStreamWriter writer = null;
+		HookableStaxIdentityParser identidywriter = null;
+		if (standoff) { // write a new file
+			writer = new StaxStackWriter(xmltxmAnalecFile);
+			PersonalNamespaceContext Nscontext = new PersonalNamespaceContext();
+			writer.setNamespaceContext(Nscontext);
+			writer.writeStartElement(StaxIdentityParser.TEINS, "TEI");
+			writer.writeNamespace("tei", StaxIdentityParser.TEINS);writer.writeCharacters("\n");
+			writer.writeStartElement("teiHeader");writer.writeCharacters("\n");
+			writer.writeStartElement("fileDesc");writer.writeCharacters("\n");
+			writer.writeStartElement("titleStmt");writer.writeCharacters("\n");
+			writer.writeStartElement("title");writer.writeCharacters("\n");
+			writer.writeCharacters(textid+" - annotations");
+			writer.writeEndElement(); // title
+			writer.writeCharacters("\n");
+			writer.writeStartElement("respStmt");writer.writeCharacters("\n");
+			writer.writeStartElement("resp");writer.writeCharacters("\n");
+			writer.writeCharacters("annotated by");
+			writer.writeEndElement(); // resp
+			writer.writeCharacters("\n");
+			writer.writeStartElement("name");writer.writeCharacters("\n");
+			writer.writeCharacters(System.getProperty("user.name"));
+			writer.writeEndElement(); // name
+			writer.writeCharacters("\n");
+			writer.writeEndElement(); // respStmt
+			writer.writeCharacters("\n");
+			writer.writeEndElement(); // titleStmt
+			writer.writeCharacters("\n");
+			writer.writeStartElement("publicationStmt");writer.writeCharacters("\n");
+			writer.writeStartElement("publisher");writer.writeCharacters("\n");
+			writer.writeCharacters("non renseigné");
+			writer.writeEndElement(); // publisher
+			writer.writeCharacters("\n");
+			writer.writeEndElement(); // publicationStmt
+			writer.writeCharacters("\n");
+			writer.writeStartElement("sourceDesc");writer.writeCharacters("\n");
+			writer.writeStartElement("bibl");writer.writeCharacters("\n");
+			writer.writeCharacters("non renseigné");
+			writer.writeEndElement(); // bibl
+			writer.writeCharacters("\n");
+			writer.writeEndElement(); // sourceDesc
+			writer.writeCharacters("\n");
+			writer.writeEndElement(); // fileDesc
+			writer.writeCharacters("\n");
+			writer.writeEndElement(); // teiHeader
+			writer.writeCharacters("\n");
+			writer.writeStartElement("text");writer.writeCharacters("\n");
+			writer.writeEndElement(); // text
+		} else {
+			identidywriter = new HookableStaxIdentityParser(xmltxmFile, "text");
+			identidywriter.process(xmltxmAnalecFile);
+			writer = identidywriter.getWriter();
+		}
+
+		try {
+			writer.writeStartElement("standOff");writer.writeCharacters("\n");
+			writer.writeStartElement("soHeader");writer.writeCharacters("\n");
+			writer.writeStartElement("titleStmt");writer.writeCharacters("\n");
+			writer.writeStartElement("title");writer.writeCharacters("\n");
+			writer.writeCharacters("URS annotations");
+			writer.writeEndElement(); // title
+			writer.writeCharacters("\n");
+			writer.writeEndElement(); // titleStmt
+			writer.writeCharacters("\n");
+			writer.writeStartElement("respStmt");writer.writeCharacters("\n");
+			writer.writeStartElement("resp");writer.writeCharacters("\n");
+			writer.writeStartElement("name");
+			writer.writeAttribute("id", System.getProperty("user.name"));
+			writer.writeCharacters("\n");
+			writer.writeCharacters(System.getProperty("user.name"));
+			writer.writeEndElement(); // name
+			writer.writeCharacters("\n");
+			writer.writeEndElement(); // resp
+			writer.writeCharacters("\n");
+			writer.writeEndElement(); // respStmt
+			writer.writeCharacters("\n");
+			writer.writeStartElement("revisionDesc");writer.writeCharacters("\n");
+			writer.writeStartElement("change");
+			writer.writeAttribute("who", "#"+System.getProperty("user.name"));
+			writer.writeAttribute("when", dateformat.format(Calendar.getInstance().getTime()));
+			writer.writeCharacters("\n");
+			writer.writeCharacters("Created with TXM "+BundleUtils.getBundleVersion("org.txm.rcp")+" and Analec extension "+BundleUtils.getBundleVersion("AnalecRCP")+" with 'XML-TEI-URS Export....' export command on "+mainCorpus.getName()+" corpus");
+			writer.writeEndElement(); // change
+			writer.writeEndElement(); // revisionDesc
+			writer.writeStartElement("encodingDesc");writer.writeCharacters("\n");
+			writer.writeStartElement("listPrefixDef");writer.writeCharacters("\n");
+			writer.writeStartElement("prefixDef");
+			writer.writeAttribute("ident", "text");
+			writer.writeAttribute("matchPattern", "(.+)");
+			writer.writeAttribute("replacementPattern", "../texts/"+xmltxmFile.getName()+"#$1");
+			writer.writeCharacters("\n");
+			writer.writeEndElement(); // prefixDef
+			writer.writeCharacters("\n");
+			writer.writeEndElement(); // listPrefixDef
+			writer.writeCharacters("\n");
+			writer.writeEndElement(); // encodingDesc
+			writer.writeCharacters("\n");
+			writer.writeEndElement(); // soHeader
+			writer.writeCharacters("\n");
+			writer.writeStartElement("annotations");
+			writer.writeAttribute("type", "coreference");
+			writer.writeCharacters("\n");
+			ArrayList<Element> writtenElements = new ArrayList<Element>();
+			writtenElements.addAll(writeUnits(writer, from, to));
+			writtenElements.addAll(writeRelations(writer, from, to));
+			writtenElements.addAll(writeSchemas(writer, from, to));
+			//			System.out.println("Written:");
+			//			for (Element e : writtenElements) System.out.print(" "+buildId(e));
+			//			System.out.println("");
+			writeProperties(writer, writtenElements);
+			//writeStructure(writer);
+			writer.writeEndElement(); // annotations
+			writer.writeEndElement(); // standOff
+
+			writtenElements.clear();
+
+			writer.writeEndElement(); // TEI
+
+			if (identidywriter != null) identidywriter.close();
+			else writer.close();
+		} catch(Exception e) {
+			writer.close();
+			Log.warning(NLS.bind("Error: {0}.", e.getLocalizedMessage()));
+			e.printStackTrace();
+			return false;
+		}
+
+		return true;
+	}
+
+	protected String buildId(Element e) {
+		if (e instanceof Unite) return "u-"+analecVue.getIdElement(e);
+		else if (e instanceof Schema) return "s-"+analecVue.getIdElement(e);
+		else if (e instanceof Relation) return "r-"+analecVue.getIdElement(e);
+		else return "iderror:"+e;
+	}
+
+	protected HashSet<Element> writeUnits(XMLStreamWriter writer, int from, int to) throws Exception {
+		HashSet<Element> written = new HashSet<Element>();
+		
+		for (String type : analecCorpus.getStructure().getUnites()) {
+			ArrayList<Unite> unites = analecCorpus.getUnites(type);
+			Collections.sort(unites, new Comparator<Unite>() {
+				@Override
+				public int compare(Unite u1, Unite u2) {
+					if (u1.getDeb() < u2.getDeb()) return -1;
+					if (u1.getDeb() > u2.getDeb()) return 1;
+					if (u1.getFin() < u2.getFin()) return -1;
+					if (u1.getFin() > u2.getFin()) return 1;
+					return 0;
+				}
+			});
+			writer.writeStartElement("annotationGrp");
+			writer.writeAttribute("type", "Unit");
+			writer.writeAttribute("subtype", type);
+			writer.writeCharacters("\n");
+			for (Unite unite : unites) {
+				if (unite.getDeb() > to) continue; // commence apres le texte
+				if (unite.getFin() < from) continue; // termine avant le texte
+
+				String id = buildId(unite);
+				writer.writeStartElement("span");
+				writer.writeAttribute("id", id);
+				int[] cpos = {unite.getDeb(), unite.getFin()};
+				String[] wordids = CQPSearchEngine.getCqiClient().cpos2Str(wordid.getQualifiedName(), cpos);
+				writer.writeAttribute("from", "text:"+wordids[0]);
+				writer.writeAttribute("to", "text:"+wordids[1]);
+				writer.writeAttribute("ana", "#"+id+"-fs");
+				writer.writeEndElement(); // span
+				writer.writeCharacters("\n");
+				written.add(unite);
+			}
+			writer.writeEndElement(); // spanGrp
+			writer.writeCharacters("\n");
+		}
+		return written;
+	}
+
+	protected HashSet<Element> writeRelations(XMLStreamWriter writer, int from, int to) throws XMLStreamException {
+		HashSet<Element> written = new HashSet<Element>();
+		for (String type : analecCorpus.getStructure().getRelations()) {
+			ArrayList<Relation> relations = analecCorpus.getRelations(type);
+			Collections.sort(relations, new Comparator<Relation>() {
+				@Override
+				public int compare(Relation r1, Relation r2) {
+					Unite u1 = r1.getUnite0();
+					Unite u2 = r2.getUnite0();
+					if (u1.getDeb() < u2.getDeb()) return -1;
+					if (u1.getDeb() > u2.getDeb()) return 1;
+					if (u1.getFin() < u2.getFin()) return -1;
+					if (u1.getFin() > u2.getFin()) return 1;
+					return 0;
+				}
+			});
+			writer.writeStartElement("annotationGrp");
+			writer.writeAttribute("type", "Relation");
+			writer.writeAttribute("subtype", type);
+			writer.writeCharacters("\n");
+			for (Relation relation : relations) {
+
+				Element e1 = relation.getElt1();
+				Element e2 = relation.getElt2();
+				if (e1 instanceof Unite && e2 instanceof Unite) {
+					Unite u1 = (Unite)e1;
+					Unite u2 = (Unite)e2;
+					if (u1.getDeb() > to) continue; // commence apres le texte
+					if (u1.getFin() < from) continue; // termine avant le texte
+					if (u2.getDeb() > to) continue; // commence apres le texte
+					if (u2.getFin() < from) continue; // termine avant le texte
+				} else {
+					continue; // TODO: implement other cases
+				}
+				String id = buildId(relation);
+				writer.writeStartElement("link");
+				writer.writeAttribute("id", id);
+				writer.writeAttribute("target", "#"+buildId(e1)+" #"+buildId(e2));
+				writer.writeAttribute("ana", "#"+id+"-fs");
+				writer.writeEndElement(); // join
+				writer.writeCharacters("\n");
+				written.add(relation);
+			}
+			writer.writeEndElement(); // joinGrp
+			writer.writeCharacters("\n");
+		}
+
+		return written;
+	}
+
+	protected HashSet<Element> writeSchemas(XMLStreamWriter writer, int from, int to) throws XMLStreamException {
+		HashSet<Element> writtenSchemas = new HashSet<Element>();
+		for (String type : analecCorpus.getStructure().getSchemas()) {
+			ArrayList<Schema> schemas = analecCorpus.getSchemas(type);
+			Collections.sort(schemas, new Comparator<Schema>() {
+				@Override
+				public int compare(Schema s1, Schema s2) {
+					Unite u1 = s1.getUnite0();
+					Unite u2 = s2.getUnite0();
+					
+					if (u1 == null && u2 == null) return 0;
+					if (u1 == null) return -1;
+					if (u2 == null) return 1;
+					
+					if (u1.getDeb() < u2.getDeb()) return -1;
+					if (u1.getDeb() > u2.getDeb()) return 1;
+					
+					// u1.deb == u2.deb
+					if (u1.getFin() < u2.getFin()) return -1;
+					if (u1.getFin() > u2.getFin()) return 1;
+					
+					return 0;
+				}
+			});
+			writer.writeStartElement("annotationGrp");
+			writer.writeAttribute("type", "Schema");
+			writer.writeAttribute("subtype", type);
+			writer.writeCharacters("\n");
+			for (Schema schema : schemas) {
+
+				HashSet<String> elements = new HashSet<String>();
+				for (Element e : schema.getContenu()) {
+					if (e instanceof Unite) {
+						Unite unite = (Unite)e;
+						if (unite.getDeb() > to) continue; // commence apres le texte
+						if (unite.getFin() < from) continue; // termine avant le texte
+						elements.add("#"+buildId(unite));
+					} else {
+						continue;
+						// TODO: to implement
+					}
+				}
+				if (elements.size() == 0) continue;
+
+				String id = buildId(schema);
+				writer.writeStartElement("link");
+				writer.writeAttribute("id", id);
+				writer.writeAttribute("target", StringUtils.join(elements, " "));
+				writer.writeAttribute("ana", "#"+id+"-fs");
+				writer.writeEndElement(); // span
+				writer.writeCharacters("\n");
+
+				writtenSchemas.add(schema);
+			}
+			writer.writeEndElement(); // join
+			writer.writeCharacters("\n");
+		}
+		return writtenSchemas;
+	}
+
+	protected void writeProperties(XMLStreamWriter writer, ArrayList<Element> writtenElements) throws Exception {
+		//writer.writeStartElement("fvLib");
+		//writer.writeAttribute("type", "AnalecElementProperties");
+		//writer.writeCharacters("\n");
+		Collections.sort(writtenElements, new Comparator<Element>() {
+			@Override
+			public int compare(Element o1, Element o2) {
+				Unite u1 = o1.getUnite0();
+				Unite u2 = o2.getUnite0();
+				if (u1.getDeb() < u2.getDeb()) return -1;
+				if (u1.getDeb() > u2.getDeb()) return 1;
+				if (u1.getFin() < u2.getFin()) return -1;
+				if (u1.getFin() > u2.getFin()) return 1;
+				return 0;
+			}
+		});
+
+		String[] fstypes = {"unit-fs", "relation-fs", "schema-fs"};
+		Class[] classes = {Unite.class, Relation.class, Schema.class};
+		
+		for (int i = 0 ; i < fstypes.length ; i++) {
+			Class c = classes[i];
+			String type = fstypes[i];
+			
+			writer.writeStartElement("div");
+			writer.writeAttribute("type", type);
+			
+			for (Element e : writtenElements) {
+				
+				if (!(e.getClass().equals(c))) continue;
+				
+				writer.writeStartElement("fs");
+				writer.writeAttribute("id", buildId(e)+"-fs");
+				writer.writeCharacters("\n");
+				for (String p : e.getProps().keySet()) {
+					writer.writeStartElement("f");
+					writer.writeAttribute("name", p);
+					writer.writeStartElement("string");
+					writer.writeCharacters(e.getProps().get(p));
+					writer.writeEndElement(); // string
+					writer.writeEndElement(); // f
+					writer.writeCharacters("\n");
+				}
+				writer.writeEndElement(); // fs
+				writer.writeCharacters("\n");
+			}
+			writer.writeEndElement(); // div
+			writer.writeCharacters("\n");
+		}
+	}
+
+	protected void writeStructure(XMLStreamWriter writer) throws XMLStreamException {
+		Structure structure = analecCorpus.getStructure();
+		writer.writeStartElement("fvLib");
+		writer.writeAttribute("type", "AnalecStructure");
+		writer.writeCharacters("\n");
+		writeStructureClass(structure, Unite.class, writer);
+		writeStructureClass(structure, Relation.class, writer);
+		writeStructureClass(structure, Schema.class, writer);
+
+		writer.writeEndElement(); // fvLib
+	}
+
+	@SuppressWarnings("unchecked")
+	protected void writeStructureClass(Structure structure, Class<? extends Element> clazz, XMLStreamWriter writer) throws XMLStreamException {
+		writer.writeStartElement("fs");
+		writer.writeAttribute("type", clazz.getSimpleName());
+		writer.writeCharacters("\n");
+		for (String type : structure.getTypes(clazz)) {
+			writer.writeStartElement("fs");
+			writer.writeAttribute("type", type);
+			writer.writeCharacters("\n");
+			for (String prop : structure.getNomsProps(clazz, type)) {
+				writer.writeStartElement("fs");
+				writer.writeAttribute("type", prop);
+				writer.writeCharacters("\n");
+				for (String v : structure.getValeursProp(clazz, type, prop)) {
+					writer.writeStartElement("f");
+					writer.writeStartElement("string");
+					writer.writeCharacters(v);
+					writer.writeEndElement(); // string
+					writer.writeEndElement(); // f
+					writer.writeCharacters("\n");
+				}
+				writer.writeEndElement(); // fs Unite prop
+				writer.writeCharacters("\n");
+			}
+			writer.writeEndElement(); // fs Unite type
+			writer.writeCharacters("\n");
+		}
+		writer.writeEndElement(); // fs Unite
+		writer.writeCharacters("\n");
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/export/URSAnnotationTEIExporter.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/rcp/testers/IsURSCorpusDirty.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/rcp/testers/IsURSCorpusDirty.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/rcp/testers/IsURSCorpusDirty.java	(revision 3653)
@@ -0,0 +1,25 @@
+package org.txm.annotation.urs.rcp.testers;
+
+import java.util.List;
+
+import org.eclipse.core.expressions.PropertyTester;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+
+public class IsURSCorpusDirty extends PropertyTester {
+	
+	@Override
+	public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
+		
+		if (receiver instanceof List) {
+			List list = (List) receiver;
+			if (list.size() == 0) return true;
+			receiver = list.get(0);
+		}
+		if (receiver instanceof MainCorpus) {
+			return URSCorpora.hasAnnotationsToSaveStatic((MainCorpus)receiver);
+		}
+		
+		return false;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/rcp/testers/IsURSCorpusDirty.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/Messages.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/Messages.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/Messages.java	(revision 3653)
@@ -0,0 +1,159 @@
+package org.txm.annotation.urs;
+
+import org.eclipse.osgi.util.NLS;
+import org.txm.utils.messages.Utf8NLS;
+
+public class Messages extends NLS {
+
+	public static String URSCorpora_3;
+	public static String URSCorpora_4;
+	
+	public static String DoInstallStep_11;
+	public static String DoInstallStep_17;
+	public static String DoInstallStep_18;
+	public static String DoInstallStep_2;
+	public static String DoInstallStep_5;
+	public static String DoInstallStep_6;
+	public static String DoInstallStep_9;
+	public static String EditStructure_0;
+	public static String ExportGlozzCorpus_0;
+	public static String ExportGlozzCorpus_1;
+	public static String ExportGlozzCorpus_2;
+	public static String ExportGlozzCorpus_3;
+	public static String ExportTEICorpus_0;
+	public static String ExportTEICorpus_1P0;
+	public static String ExportTEICorpus_2;
+	public static String ExportTEICorpus_3;
+	public static String ImportGlozzAnnotations_0;
+	public static String ImportGlozzAnnotations_1;
+	public static String ImportGlozzAnnotations_10;
+	public static String ImportGlozzAnnotations_2;
+	public static String ImportGlozzAnnotations_3;
+	public static String ImportGlozzAnnotations_4;
+	public static String ImportGlozzAnnotations_6;
+	public static String ImportGlozzAnnotations_7;
+	public static String ImportGlozzAnnotations_8;
+	public static String ImportGlozzAnnotations_9;
+	public static String ImportGlozzCorpus_0;
+	public static String ImportGlozzCorpus_1;
+	public static String ImportGlozzCorpus_10;
+	public static String ImportGlozzCorpus_11;
+	public static String ImportGlozzCorpus_15;
+	public static String ImportGlozzCorpus_17;
+	public static String ImportGlozzCorpus_19;
+	public static String ImportGlozzCorpus_22;
+	public static String ImportGlozzCorpus_23;
+	public static String ImportGlozzCorpus_24;
+	public static String ImportGlozzCorpus_25;
+	public static String ImportGlozzCorpus_26;
+	public static String ImportGlozzCorpus_27;
+	public static String ImportGlozzCorpus_28;
+	public static String ImportGlozzCorpus_29;
+	public static String ImportGlozzCorpus_3;
+	public static String ImportGlozzCorpus_30;
+	public static String ImportGlozzCorpus_32;
+	public static String ImportGlozzCorpus_4;
+	public static String ImportGlozzCorpus_5;
+	public static String ImportGlozzCorpus_8;
+	public static String ImportGlozzCorpus_9;
+	public static String ImportTEIAnnotations_0;
+	public static String ImportTEIAnnotations_1;
+	public static String ImportTEIAnnotations_2;
+	public static String ImportTEIAnnotations_3;
+	public static String ImportTEIAnnotations_5;
+	public static String ImportTEICorpus_0;
+	public static String ImportTEICorpus_11;
+	public static String ImportTEICorpus_14;
+	public static String ImportTEICorpus_15;
+	public static String ImportTEICorpus_16;
+	public static String ImportTEICorpus_18;
+	public static String ImportTEICorpus_19;
+	public static String ImportTEICorpus_2;
+	public static String ImportTEICorpus_20;
+	public static String ImportTEICorpus_21;
+	public static String ImportTEICorpus_22;
+	public static String ImportTEICorpus_23;
+	public static String ImportTEICorpus_24;
+	public static String ImportTEICorpus_3;
+	public static String ImportTEICorpus_5;
+	public static String ImportTEICorpus_7;
+	public static String ImportTEICorpus_9;
+	public static String LoadCorpus_0;
+	public static String LoadCorpus_1;
+	public static String LoadCorpus_2;
+	public static String LoadCorpus_3;
+	public static String LoadCorpus_4;
+	public static String LoadCorpus_5;
+	public static String LoadStructure_0;
+	public static String LoadStructure_1;
+	public static String LoadStructure_2;
+	public static String LoadStructure_3;
+	public static String LoadStructureFromGlozz_0;
+	public static String LoadStructureFromGlozz_1;
+	public static String LoadStructureFromGlozz_2;
+	public static String LoadStructureFromGlozz_3;
+	public static String LoadStructureFromGlozz_4;
+	public static String LoadVue_0;
+	public static String LoadVue_1;
+	public static String LoadVue_2;
+	public static String LoadVue_3;
+	public static String SaveCorpus_0;
+	public static String SaveCorpus_3;
+	public static String SaveCorpus_5;
+	public static String SaveStructure_0;
+	public static String SaveStructure_3;
+	public static String SaveStructure_5;
+	public static String SaveStructureAsGlozzModel_0;
+	public static String SaveStructureAsGlozzModel_1;
+	public static String SaveStructureAsGlozzModel_2;
+	public static String SaveStructureAsGlozzModel_3;
+	public static String SaveVue_0;
+	public static String SaveVue_3;
+	public static String SaveVue_5;
+	
+	public static String AnalecPreferencePage_3;
+	public static String AnalecPreferencePage_4;
+	public static String AnalecPreferencePage_9;
+	
+	public static String AnnotationToolbar_0;
+	public static String AnnotationToolbar_6;
+	public static String AnnotationToolbar_7;
+	public static String UnitToolbar_10;
+	public static String UnitToolbar_12;
+	public static String UnitToolbar_14;
+	public static String UnitToolbar_16;
+	public static String UnitToolbar_27;
+	public static String UnitToolbar_28;
+	public static String UnitToolbar_29;
+	public static String UnitToolbar_3;
+	public static String UnitToolbar_32;
+	public static String UnitToolbar_44;
+	public static String UnitToolbar_47;
+	public static String UnitToolbar_48;
+	public static String UnitToolbar_5;
+	public static String UnitToolbar_54;
+	public static String UnitToolbar_59;
+	public static String UnitToolbar_6;
+	public static String UnitToolbar_7;
+	public static String UnitToolbar_8;
+	
+	public static String StartButton_0;
+	public static String StartButton_1;
+	public static String StartButton_11;
+	public static String StartButton_12;
+	public static String StartButton_4;
+	public static String StartButton_5;
+	
+	public static String NavigationField_0;
+	public static String NavigationField_2;
+	public static String NavigationField_4;
+	public static String NavigationField_5;
+	
+	static {
+		// initialize resource bundle
+		Utf8NLS.initializeMessages(Messages.class);
+	}
+
+	private Messages() {
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/Messages.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/messages_fr.properties
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/messages_fr.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/messages_fr.properties	(revision 3653)
@@ -0,0 +1,276 @@
+
+AnalecPreferencePage_3 = Utiliser la correction des limites d'unité d'Analec
+
+AnalecPreferencePage_4 = Recherche d'autocomplétion par prefix (au lieu de infixe)
+
+AnalecPreferencePage_9 = Palette de couleur de mise en évidence
+
+AnnotationToolbar_0 = Pas de sélection trouvée. Abandon.
+
+AnnotationToolbar_6 = ** le nombre de match est {0}
+
+AnnotationToolbar_7 = la requête est {0}
+
+DoInstallStep_11 = Les macro URS précédentes ont été déplacée à {0}
+
+DoInstallStep_17 = ** Erreur lors de la copie du dossier de macro "org/txm/macro/urs" dans {0}
+
+DoInstallStep_18 = URS post-installation terminé.
+
+DoInstallStep_2 = URS.DoInstallStep.install()
+
+DoInstallStep_5 = Pas de post-installation URS à faire
+
+DoInstallStep_6 = Post-installing URS version={0}
+
+DoInstallStep_9 = Le dossier de backup existe déjà : {0}
+
+EditStructure_0 = La sélection n'est pas un corpus : {0}
+
+ExportGlozzCorpus_0 = La sélection n'est pas un corpus racine : {0}
+
+ExportGlozzCorpus_1 = Export Glozz 
+
+ExportGlozzCorpus_2 = Annulé.
+
+ExportGlozzCorpus_3 = ** Erreur lors de l'export des annotations : {0}
+
+ExportTEICorpus_0 = La sélection n'est pas un corpus : {0}
+
+ExportTEICorpus_1P0 = {0} annotations export...
+
+ExportTEICorpus_2 = ** Erreur lors de l'export du corpus.
+
+ExportTEICorpus_3 = ** Error lors de l'export du corpus to XML-URS : {0}
+
+ImportGlozzAnnotations_0 = Les fichiers "aa", "aam" et "ac" doivent être présent.
+
+ImportGlozzAnnotations_1 = La sélection n'est pas un corpus racine : {0}
+
+ImportGlozzAnnotations_10 = Terminé.
+
+ImportGlozzAnnotations_2 = Import du modèle Glozz depuis : {0}
+
+ImportGlozzAnnotations_3 = Erreur lors de l'import du modèle Glozz.
+
+ImportGlozzAnnotations_4 = Import du corpus Glozz avec les fichiers {0} et {1} 
+
+ImportGlozzAnnotations_6 = ** Erreur lors de l'import du corpus Glozz.
+
+ImportGlozzAnnotations_7 = Reindexer les annotations avec les mots TXM
+
+ImportGlozzAnnotations_8 = ** Erreur lors de la réindexation des annotations URS.
+
+ImportGlozzAnnotations_9 = Enregistrement des annotations.
+
+ImportGlozzCorpus_0 = Le dossier {0} glozz doit exister.
+
+ImportGlozzCorpus_1 = Création du dossier source {0}.
+
+ImportGlozzCorpus_10 = Le nombre de fichier aa est différent du nombre de fichier ac dans {0}.
+
+ImportGlozzCorpus_11 = Import des données Glozz depuis {0}.
+
+ImportGlozzCorpus_15 = ** Erreur lors de l'import des données Glozz.
+
+ImportGlozzCorpus_17 = ** Le fichier source TXT {0} n'a pas pu être créé.
+
+ImportGlozzCorpus_19 = ** la configuration du corpus n'a pas pu être enregistré : {0}
+
+ImportGlozzCorpus_22 = ** Pas de script {0} trouvé pour le module d'import {0}
+
+ImportGlozzCorpus_23 = Erreur lors de l'import
+
+ImportGlozzCorpus_24 = Finalisation de l'import de corpus Analec
+
+ImportGlozzCorpus_25 = Import de la structure d'annotation {0}.
+
+ImportGlozzCorpus_26 = Erreur lors de l'import du modèle Glozz
+
+ImportGlozzCorpus_27 = Réindexation des annotations avec les mots TXM.
+
+ImportGlozzCorpus_28 = Erreur lors de la ré-indexation des annotations.
+
+ImportGlozzCorpus_29 = Enregistrement des annotations...
+
+ImportGlozzCorpus_3 = Création du dossier ec: {0}.
+
+ImportGlozzCorpus_30 = Terminé.
+
+ImportGlozzCorpus_32 = Erreur lors de la finalisation de l'import du corpus : {0}
+
+ImportGlozzCorpus_4 = Le dossier {0} des sources n'a pu être créé.
+
+ImportGlozzCorpus_5 = Le dossier ec {0} n''a pu être créé
+
+ImportGlozzCorpus_8 = Pas de fichier .aa trouvé dans le dossier {0}
+
+ImportGlozzCorpus_9 = Pas de fichier .ac trouvé dans le dossier {0}
+
+ImportTEIAnnotations_0 = La sélection n''est pas un corpus : {0}
+
+ImportTEIAnnotations_1 = Import de {0} annotations...
+
+ImportTEIAnnotations_2 = Erreur lors de l'import des annotations.
+
+ImportTEIAnnotations_3 = Erreur lors de l'import des annotations : {0}
+
+ImportTEIAnnotations_5 = Terminé: {0} unités, {1} relations et {2} schemas.
+
+ImportTEICorpus_0 = ** Les fichiers XML doivent exister : {0}
+
+ImportTEICorpus_11 = ** Echec de l''enregistrement de la configuration d''import : {0}
+
+ImportTEICorpus_14 = ** Pas de script {1} trouvé pour le module d''import {0}
+
+ImportTEICorpus_15 = ** Erreur lors de l'import
+
+ImportTEICorpus_16 = Finalisation de l'import de corpus Analec
+
+ImportTEICorpus_18 = Import du model d''annotation TEI depuis : {0}
+
+ImportTEICorpus_19 = Erreur lors de l'import du modèle d'annotation TEI.
+
+ImportTEICorpus_2 = Creation du dossier source : {0}
+
+ImportTEICorpus_20 = Réindexation des annotations avec les mots TXM.
+
+ImportTEICorpus_21 = Erreur lors de la réindexation des annotations avec les mots TXM.
+
+ImportTEICorpus_22 = Enregistrement des annotations.
+
+ImportTEICorpus_23 = Terminé.
+
+ImportTEICorpus_24 = Erreur lors de la finalisation de l''import du corpus : {0}
+
+ImportTEICorpus_3 = ** Le dossier source {0} n''a pas pu être créé 
+
+ImportTEICorpus_5 = Import des données TEI depuis : {0}
+
+ImportTEICorpus_7 = Erreur lors de l'import des données TEI.
+
+ImportTEICorpus_9 = Le fichier source TXT {0} n''a pas pu être créé
+
+LoadCorpus_0 = La sélection n''est pas un corpus racine : {0}
+
+LoadCorpus_1 = Chargement du corpus depuis le fichier...
+
+LoadCorpus_2 = Le fichier EC n'existe pas.
+
+LoadCorpus_3 = Chargement du corpus depuis le fichier {0}
+
+LoadCorpus_4 = Échec du chargement de la structure
+
+LoadCorpus_5 = Terminé : 
+
+LoadStructureFromGlozz_0 = La sélection n''est pas un corpus racine : {0}
+
+LoadStructureFromGlozz_1 = Import du modèle Glozz pour le corpus {0}
+
+LoadStructureFromGlozz_2 = Le fichier AAM n'existe pas.
+
+LoadStructureFromGlozz_3 = Échec du chargement de la structure depuis le modèle Glozz.
+
+LoadStructureFromGlozz_4 = Terminé.
+
+LoadStructure_0 = La sélection n''est pas un corpus racine : {0}
+
+LoadStructure_1 = Chargement de la structure pour le corpus {0}
+
+LoadStructure_2 = Échec du chargement de la structure.
+
+LoadStructure_3 = Terminé : 
+
+LoadVue_0 = La sélection n''est pas un corpus racine : {0}
+
+LoadVue_1 = Chargement de la vue pour le corpus {0}
+
+LoadVue_2 = Échec du chargement de la vue.
+
+LoadVue_3 = Terminé : 
+
+NavigationField_0 = <identifiant>
+
+NavigationField_2 = Mauvais identifiant de mot : {0}
+
+NavigationField_4 = Recherche d'unité par propriétés
+
+NavigationField_5 = <identifiant>
+
+SaveCorpus_0 = La sélection n''est pas un corpus racine ({0})
+
+SaveCorpus_3 = Enregistrement des annotations URS ({0}, {1})
+
+SaveCorpus_5 = Erreur lors de l'enregistrement  du corpus.
+
+SaveStructureAsGlozzModel_0 = La sélection n''est pas un corpus racine : {0}
+
+SaveStructureAsGlozzModel_1 = Enregistrement de la structure du corpus {0} dans un modèle Glozz
+
+SaveStructureAsGlozzModel_2 = Erreur lors de l'enregistrement de la structure.
+
+SaveStructureAsGlozzModel_3 = Terminé.
+
+SaveStructure_0 = La sélection n''est pas un corpus racine : {0}
+
+SaveStructure_3 = Enregistrement de la structure du corpus {0} ({1})
+
+SaveStructure_5 = Erreur lors de l'enregistrement de la structure.
+
+SaveVue_0 = La sélection n''est pas un corpus racine : {0}
+
+SaveVue_3 = Enregistrement de la vue du corpus {0} dans {1} 
+
+SaveVue_5 = Erreur lors de l'enregistrement de la vue.
+
+StartButton_0 = Unités
+
+StartButton_1 = Schemas
+
+StartButton_11 = Enregistrer and fermer l'interface d'annotation : 
+
+StartButton_12 = Démarrer l'annotation URS
+
+StartButton_4 = ** Le corpus n'a pas été enregistré.
+
+StartButton_5 = Terminé.
+
+URSCorpora_3 = Erreur lors de l''ouverture du corpus : {0}
+
+URSCorpora_4 = Erreur lors de la création du corpus : {0}
+
+UnitToolbar_10 = Supprimer
+
+UnitToolbar_12 = Corriger la limite gauche en cliquant sur un mot
+
+UnitToolbar_14 = Corriger les limites gauche et droite avec une nouvelle sélection de mot
+
+UnitToolbar_16 = Corriger la limite droite en cliquant sur un mot
+
+UnitToolbar_27 = Il faut sélectionner un mot.
+
+UnitToolbar_28 = ** Erreur lors de la mise à jour des limites de l'unité {0}
+
+UnitToolbar_29 = Selectioner {0}
+
+UnitToolbar_3 = ** Erreur lors de la récupération de la taille de {0} : {1}
+
+UnitToolbar_32 = Selectioner {0}
+
+UnitToolbar_44 = Création de l''unité (de {0} à {0})
+
+UnitToolbar_47 = Supprimer l''unité {0} 
+
+UnitToolbar_48 = Voulez vous supprimer l''unité {0} ? 
+
+UnitToolbar_5 = Type d''unité : {0}
+
+UnitToolbar_54 = < type d'unité >
+
+UnitToolbar_59 = ** Pas de mots trouvé pour l'identifiant {0}
+
+UnitToolbar_6 = Type d'unité
+
+UnitToolbar_7 = Type d'unité
+
+UnitToolbar_8 = Créer

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/messages_fr.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/testers/IsCorpusAnnotated.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/testers/IsCorpusAnnotated.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/testers/IsCorpusAnnotated.java	(revision 3653)
@@ -0,0 +1,39 @@
+package org.txm.annotation.urs.testers;
+
+import java.util.List;
+
+import org.eclipse.core.expressions.PropertyTester;
+import org.txm.annotation.urs.URSCorpora;
+import org.txm.searchengine.cqp.corpus.CQPCorpus;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+
+public class IsCorpusAnnotated extends PropertyTester {
+
+	public static final String PROPERTY_NAMESPACE = "org.txm.annotation.urs.testers"; //$NON-NLS-1$
+	public static final String PROPERTY_CAN_SAVE = "canAnnotate";
+	
+	@Override
+	public boolean test(Object receiver, String property, Object[] args,
+			Object expectedValue) {
+
+		if (receiver instanceof List) {
+			@SuppressWarnings("unchecked")
+			List<Object> list = (List<Object>)receiver;
+			if (list.size() == 0) return false;
+			receiver = list.get(0);
+		}
+		
+		//System.out.println("test org.txm.annotation.urs.testers.canAnnotate with "+receiver.getClass());
+		if (receiver instanceof CQPCorpus) {
+			return testCorpus((CQPCorpus)receiver);
+		}
+		return false;
+	}
+
+	protected boolean testCorpus(CQPCorpus c) {
+		MainCorpus mc = c.getMainCorpus();
+		boolean ret = URSCorpora.isAnnotationStructureReady(mc);
+		//System.out.println(" Corpus:"+c+" org.txm.annotation.urs.testers.canAnnotate: "+ret);
+		return ret;
+	}
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/annotation/urs/testers/IsCorpusAnnotated.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/export/ExportUnitsToGlozz.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/export/ExportUnitsToGlozz.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/export/ExportUnitsToGlozz.groovy	(revision 3653)
@@ -0,0 +1,160 @@
+package org.txm.macro.urs.export
+
+// @author: Bruno Oberlé
+// v1.0.0 2017-08-28
+
+/*
+ Cette macro exporte le corpus sélectionné et ses annotations vers deux fichiers de format Glozz:
+ - un fichier .ac contenant le corpus brut,
+ - un fichier .aa contenant les annotations au format XML utilisé par Glozz.
+ Le corpus sélectionné dans TXM devrait contenir une structure Analec avec au moins un type d'unité défini (e.g. MENTION, maillon, etc.). S'il n'y a pas de structure,
+ ce n'est pas grave: le fichier est exporter, mais aucune annotation n'est créer. Cela permet d'exporter n'importe quel corpus au format Glozz.
+ Pour exporter un texte au format Glozz *sans* les annotations qu'il contient, simplement mettre un unit_type qui n'existe pas (e.g. "foobar" au lieu de "MENTION").
+ La macro ne produit pour l'instant pas automatiquement de modèle Glozz (fichier .aam).  Cela n'est pas un problème pour ouvrir le résultat dans Glozz ou Analec.
+ */
+
+// STANDARD DECLARATIONS
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+// CHECK CORPUS
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+
+@Field @Option(name="unit_type",usage="", widget="String", required=true, def="MENTION")
+		String unit_type
+
+@Field @Option(name="filename",usage="", widget="String", required=true, def="filename without extension (.ac/.aa)")
+		String filename
+
+if (!ParametersDialog.open(this)) return;
+
+// VARIABLES
+
+corpus = corpusViewSelection
+
+doExport(corpus, unit_type, filename)
+
+public void doExport(MainCorpus corpus, String unit_type, String filename) {
+
+	size = corpus.getSize() // you may also use: corpus.getTextEndLimits() (= index of last token = size-1)
+	CQI = CQPSearchEngine.getCqiClient()
+	word = corpus.getWordProperty()
+	// note: using "lbn" seems to work better than "pn" (some imported corpora are missing this information)
+	//pn = corpus.getProperty("pn")
+	//if (pn == null) pn = corpus.getProperty("div")
+	pn = corpus.getProperty("lbn")
+
+	// BUILD THE RAW TEXT, THE POSITIONS AND FIND THE PARAGRAPHS
+
+	rawText = "" // the corpus for the .ac file
+	positions = [] // each element is an array [start, end] indicating the position in the rawText
+	pnCount = 0 // the par counter, used for indexing the pns array
+	lastPn = -1 // the last paragraph number
+	pns = [] // each element is an array [start, end] representing the start and end of the paragraph in the rawText
+	for (def i=0; i<size; i++) {
+		f = CQI.cpos2Str(word.getQualifiedName(), (int[])[i])[0]
+		if (pn == null) {
+			p = 1
+		} else {
+			p = CQI.cpos2Str(pn.getQualifiedName(), (int[])[i])[0]
+		}
+		start = rawText.length()
+		rawText += f
+		if (lastPn != p) {
+			pnCount++;
+			if (pnCount > 1) {
+				pns[pnCount-2][1] = end
+			}
+			pns[pnCount-1] = [start, 0]
+		}
+		lastPn = p
+		end = rawText.length() // must be after setting it up in pns!
+		if (i != size-1) rawText += " "
+		positions[i] = [start, end]
+	}
+	pns[pnCount-1][1] = end
+	println pnCount + " paragraph(s) found."
+
+
+
+	// CORPUS ANALEC (GET THE ANNOTATIONS)
+
+	// note that unit_type has been defined with an option of the dialog at the beginning
+	def analecCorpus = URSCorpora.getCorpus(corpus);
+
+	// list of properties
+
+	struct = analecCorpus.getStructure();
+	propertyList = struct.getUniteProperties(unit_type);
+
+	// export to file (corpus)
+
+	corpusFilename = filename + ".ac";
+	def corpusFile = new File(corpusFilename);
+	corpusFile.write(rawText)
+	println("Corpus written to `"+corpusFilename+"'.");
+
+	// export to file (annotations)
+
+	annotFilename = filename + ".aa";
+	def annotFile = new File(annotFilename)
+	annotFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<annotations>\n") // erase
+	def counter = 0
+
+	// export paragraphs
+	for (def i=0; i<pns.size(); i++) {
+		def start = pns[i][0]
+		def end = pns[i][1]
+		annotFile << "<unit id=\"me_"+counter+"\">\n";
+		annotFile << "<metadata><author>me</author><creation-date>"+counter+"</creation-date></metadata>\n";
+		annotFile << "<characterisation><type>paragraph</type><featureSet /></characterisation>\n";
+		annotFile << "<positioning><start><singlePosition index=\""+start+"\" /></start><end><singlePosition index=\""+end+"\" /></end></positioning>\n";
+		annotFile << "</unit>\n";
+		counter++;
+	}
+
+	// export units
+	def units = analecCorpus.getUnites(unit_type);
+	//units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() };
+	def unitCount = 0
+	for (Unite unit : units) {
+		unitCount++;
+		annotFile << "<unit id=\"me_"+counter+"\">\n";
+		annotFile << "<metadata><author>me</author><creation-date>"+counter+"</creation-date></metadata>\n";
+		annotFile << "<characterisation>\n";
+		annotFile << "<type>"+unit_type+"</type>\n";
+		annotFile << "<featureSet>\n";
+		for (String propertyName : propertyList) {
+			annotFile << "<feature name=\""+propertyName+"\">"+unit.getProp(propertyName)+"</feature>\n";
+		}
+		annotFile << "</featureSet>\n";
+		annotFile << "</characterisation>\n";
+		start = positions[unit.getDeb()][0]
+		end = positions[unit.getFin()][1]
+		annotFile << "<positioning><start><singlePosition index=\""+start+"\" /></start><end><singlePosition index=\""+end+"\" /></end></positioning>\n";
+		annotFile << "</unit>\n";
+		counter++;
+	}
+	annotFile << "</annotations>\n";
+
+	println unitCount + " unit(s) found."
+
+	println("Annotations written to `"+annotFilename+"'.");
+}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/export/ExportCorpusAsMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/export/ExportCorpusAsMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/export/ExportCorpusAsMacro.groovy	(revision 3653)
@@ -0,0 +1,127 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.export
+
+import groovy.transform.Field
+
+import org.jfree.chart.JFreeChart
+import org.kohsuke.args4j.*
+import org.txm.Toolbox
+import org.txm.annotation.urs.*
+import org.txm.macro.urs.AnalecUtils
+import org.txm.rcp.Application
+import org.txm.rcp.IImageKeys
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+import org.txm.utils.io.FileCopy;
+import org.txm.utils.io.IOUtils
+import org.txm.utils.zip.Zip
+
+import visuAnalec.elements.*
+
+def scriptName = this.class.getSimpleName()
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "** $scriptName please select a MainCorpus to run the macro"
+	return;
+}
+
+@Field @Option(name="new_name", usage="Corpus name in uppercase", widget="String", required=true, def="CORPUSNAME")
+String new_name
+if (!ParametersDialog.open(this)) return
+
+new_name = new_name.toUpperCase()
+def pattern = "[A-Z][-A-Z0-9]{1,20}"
+if (!new_name.matches(pattern)) {
+	println "New corpus name not conformant to CQP corpus name: "+pattern
+	return false
+}
+
+MainCorpus mainCorpus = corpusViewSelection.getMainCorpus()
+String name = mainCorpus.getName()
+if (mainCorpus.isModified()) {
+	println "Selected corpus is not saved. Aborting"
+	return false
+}
+
+visuAnalec.donnees.Corpus analecCorpus = URSCorpora.getCorpus(mainCorpus)
+if (analecCorpus.isModifie()) {
+	println "Selected Analec corpus is not saved. Aborting"
+	return false
+}
+
+File binDirectory = mainCorpus.getProjectDirectory()
+String binName = binDirectory.getName()
+
+
+File newBinDirectory = new File(binDirectory.getParentFile(), new_name)
+
+if (newBinDirectory.exists()) {
+	println "The new corpus directory already exists: $newBinDirectory. Aborting."
+	return false
+}
+
+FileCopy.copyFiles(binDirectory, newBinDirectory)
+if (!newBinDirectory.exists()) {
+	println "Fail to copy binary directory $binDirectory to $newBinDirectory"
+	return
+}
+
+File ecFile = new File(newBinDirectory, "analec/${name}.ec")
+File ecvFile = new File(newBinDirectory, "analec/${name}.ecv")
+File cssFile = new File(newBinDirectory, "css/${name}.css")
+File dataFile = new File(newBinDirectory, "data/${name}")
+File htmlFile = new File(newBinDirectory, "HTML/${name}")
+File defaultCSSFile = new File(newBinDirectory, "HTML/${name}/default/css/${name}.css")
+File registryFile = new File(newBinDirectory, "registry/${name.toLowerCase()}")
+File txmFile = new File(newBinDirectory, "txm/${name}")
+
+File ecFile2 = new File(newBinDirectory, "analec/${new_name}.ec")
+File ecvFile2 = new File(newBinDirectory, "analec/${new_name}.ecv")
+File cssFile2 = new File(newBinDirectory, "css/${new_name}.css")
+File dataFile2 = new File(newBinDirectory, "data/${new_name}")
+File htmlFile2 = new File(newBinDirectory, "HTML/${new_name}")
+File defaultCSSFile2 = new File(newBinDirectory, "HTML/${new_name}/default/css/${new_name}.css")
+File registryFile2 = new File(newBinDirectory, "registry/${new_name.toLowerCase()}")
+File txmFile2 = new File(newBinDirectory, "txm/${new_name}")
+
+println "renaming $ecFile : "+ecFile.renameTo(ecFile2)
+println "renaming $ecvFile : "+ecvFile.renameTo(ecvFile2)
+println "renaming $cssFile : "+cssFile.renameTo(cssFile2)
+println "renaming $dataFile : "+dataFile.renameTo(dataFile2)
+println "renaming $htmlFile : "+htmlFile.renameTo(htmlFile2)
+println "renaming $defaultCSSFile : "+defaultCSSFile.renameTo(defaultCSSFile2)
+println "renaming $registryFile : "+registryFile.renameTo(registryFile2)
+println "renaming $txmFile : "+txmFile.renameTo(txmFile2)
+
+// patch name in settings
+println "replacing old name $name ->  ${new_name} in preferences"
+File settingsDirectory = new File(newBinDirectory, ".settings")
+for (File prefFile : settingsDirectory.listFiles()) {
+	IOUtils.write(prefFile, prefFile.getText().replace(name, new_name))
+}
+
+File projectSetting = new File(newBinDirectory, ".project")
+IOUtils.write(projectSetting, projectSetting.getText().replace(name, new_name))
+
+// patch registry
+String oldcontent = registryFile2.getText();
+content = oldcontent.replace(name, new_name)
+content = content.replace(name.toLowerCase(), new_name.toLowerCase())
+registryFile2.withWriter { writer -> 
+	writer.write(content)
+}
+
+println "creating the TXM file..."
+File zipFile = new File(newBinDirectory.getAbsolutePath()+".txm")
+Zip.compress(newBinDirectory, zipFile, monitor)
+
+if (!zipFile.exists()) {
+	println "Fail to zip binary directory $binDirectory to $zipFile"
+	return
+} else {
+	println "Done: $zipFile"
+}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/export/ExportToGlozz1_0_0.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/export/ExportToGlozz1_0_0.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/export/ExportToGlozz1_0_0.groovy	(revision 3653)
@@ -0,0 +1,161 @@
+package org.txm.macro.urs.export
+
+// @author: Bruno Oberlé
+// v1.0.0 2017-08-28
+
+/*
+ Cette macro exporte le corpus sélectionné et ses annotations vers deux fichiers de format Glozz:
+ - un fichier .ac contenant le corpus brut,
+ - un fichier .aa contenant les annotations au format XML utilisé par Glozz.
+ Le corpus sélectionné dans TXM devrait contenir une structure Analec avec au moins un type d'unité défini (e.g. MENTION, maillon, etc.). S'il n'y a pas de structure,
+ ce n'est pas grave: le fichier est exporter, mais aucune annotation n'est créer. Cela permet d'exporter n'importe quel corpus au format Glozz.
+ Pour exporter un texte au format Glozz *sans* les annotations qu'il contient, simplement mettre un unit_type qui n'existe pas (e.g. "foobar" au lieu de "MENTION").
+ La macro ne produit pour l'instant pas automatiquement de modèle Glozz (fichier .aam).  Cela n'est pas un problème pour ouvrir le résultat dans Glozz ou Analec.
+ */
+
+// STANDARD DECLARATIONS
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+// CHECK CORPUS
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+
+@Field @Option(name="unit_type",usage="", widget="String", required=true, def="MENTION")
+		String unit_type
+
+@Field @Option(name="filename",usage="", widget="String", required=true, def="filename without extension (.ac/.aa)")
+		String filename
+
+if (!ParametersDialog.open(this)) return;
+
+// VARIABLES
+
+corpus = corpusViewSelection
+
+doExport(corpus, unit_type, filename)
+
+public void doExport(MainCorpus corpus, String unit_type, String filename) {
+
+	size = corpus.getSize() // you may also use: corpus.getTextEndLimits() (= index of last token = size-1)
+	CQI = CQPSearchEngine.getCqiClient()
+	word = corpus.getWordProperty()
+	// note: using "lbn" seems to work better than "pn" (some imported corpora are missing this information)
+	//pn = corpus.getProperty("pn")
+	//if (pn == null) pn = corpus.getProperty("div")
+	pn = corpus.getProperty("lbn")
+
+	// BUILD THE RAW TEXT, THE POSITIONS AND FIND THE PARAGRAPHS
+
+	rawText = "" // the corpus for the .ac file
+	positions = [] // each element is an array [start, end] indicating the position in the rawText
+	pnCount = 0 // the par counter, used for indexing the pns array
+	lastPn = -1 // the last paragraph number
+	pns = [] // each element is an array [start, end] representing the start and end of the paragraph in the rawText
+	for (def i=0; i<size; i++) {
+		f = CQI.cpos2Str(word.getQualifiedName(), (int[])[i])[0]
+		if (pn == null) {
+			p = 1
+		} else {
+			p = CQI.cpos2Str(pn.getQualifiedName(), (int[])[i])[0]
+		}
+		start = rawText.length()
+		rawText += f
+		if (lastPn != p) {
+			pnCount++;
+			if (pnCount > 1) {
+				pns[pnCount-2][1] = end
+			}
+			pns[pnCount-1] = [start, 0]
+		}
+		lastPn = p
+		end = rawText.length() // must be after setting it up in pns!
+		if (i != size-1) rawText += " "
+		positions[i] = [start, end]
+	}
+	pns[pnCount-1][1] = end
+	println pnCount + " paragraph(s) found."
+
+
+
+	// CORPUS ANALEC (GET THE ANNOTATIONS)
+
+	// note that unit_type has been defined with an option of the dialog at the beginning
+	def analecCorpus = URSCorpora.getCorpus(corpus);
+
+	// list of properties
+
+	struct = analecCorpus.getStructure();
+	propertyList = struct.getUniteProperties(unit_type);
+
+	// export to file (corpus)
+
+	corpusFilename = filename + ".ac";
+	def corpusFile = new File(corpusFilename);
+	corpusFile.write(rawText)
+	println("Corpus written to `"+corpusFilename+"'.");
+
+	// export to file (annotations)
+
+	annotFilename = filename + ".aa";
+	def annotFile = new File(annotFilename)
+	annotFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<annotations>\n")
+		// erase (if you use << you don't erase!)
+	def counter = 0
+
+	// export paragraphs
+	for (def i=0; i<pns.size(); i++) {
+		def start = pns[i][0]
+		def end = pns[i][1]
+		annotFile << "<unit id=\"me_"+counter+"\">\n";
+		annotFile << "<metadata><author>me</author><creation-date>"+counter+"</creation-date></metadata>\n";
+		annotFile << "<characterisation><type>paragraph</type><featureSet /></characterisation>\n";
+		annotFile << "<positioning><start><singlePosition index=\""+start+"\" /></start><end><singlePosition index=\""+end+"\" /></end></positioning>\n";
+		annotFile << "</unit>\n";
+		counter++;
+	}
+
+	// export units
+	def units = analecCorpus.getUnites(unit_type);
+	//units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() };
+	def unitCount = 0
+	for (Unite unit : units) {
+		unitCount++;
+		annotFile << "<unit id=\"me_"+counter+"\">\n";
+		annotFile << "<metadata><author>me</author><creation-date>"+counter+"</creation-date></metadata>\n";
+		annotFile << "<characterisation>\n";
+		annotFile << "<type>"+unit_type+"</type>\n";
+		annotFile << "<featureSet>\n";
+		for (String propertyName : propertyList) {
+			annotFile << "<feature name=\""+propertyName+"\">"+unit.getProp(propertyName)+"</feature>\n";
+		}
+		annotFile << "</featureSet>\n";
+		annotFile << "</characterisation>\n";
+		start = positions[unit.getDeb()][0]
+		end = positions[unit.getFin()][1]
+		annotFile << "<positioning><start><singlePosition index=\""+start+"\" /></start><end><singlePosition index=\""+end+"\" /></end></positioning>\n";
+		annotFile << "</unit>\n";
+		counter++;
+	}
+	annotFile << "</annotations>\n";
+
+	println unitCount + " unit(s) found."
+
+	println("Annotations written to `"+annotFilename+"'.");
+}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/export/ExportToGlozz1_1_0.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/export/ExportToGlozz1_1_0.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/export/ExportToGlozz1_1_0.groovy	(revision 3653)
@@ -0,0 +1,200 @@
+package org.txm.macro.urs.export
+
+// @author: Bruno Oberle
+// v1.1.0 2017-10-25:
+//  - using the "p" structural unit if available to get paragraphs
+//  - no space before comma, parenthesis, full stop, hyphen, etc.
+//  - no space after hyphen, parenthesis, apostrophe, etc.
+// v1.0.0 2017-08-28
+
+/*
+ Cette macro exporte le corpus sélectionné et ses annotations vers deux fichiers de format Glozz:
+ - un fichier .ac contenant le corpus brut,
+ - un fichier .aa contenant les annotations au format XML utilisé par Glozz.
+ Le corpus sélectionné dans TXM devrait contenir une structure Analec avec au moins un type d'unité défini (e.g. MENTION, maillon, etc.). S'il n'y a pas de structure,
+ ce n'est pas grave: le fichier est exporter, mais aucune annotation n'est créer. Cela permet d'exporter n'importe quel corpus au format Glozz.
+ Pour exporter un texte au format Glozz *sans* les annotations qu'il contient, simplement mettre un unit_type qui n'existe pas (e.g. "foobar" au lieu de "MENTION").
+ La macro ne produit pour l'instant pas automatiquement de modèle Glozz (fichier .aam).  Cela n'est pas un problème pour ouvrir le résultat dans Glozz ou Analec.
+ */
+
+// STANDARD DECLARATIONS
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+
+// GLOBAL VARIABLES
+
+corpus = corpusViewSelection
+CQI = CQPSearchEngine.getCqiClient()
+
+// CHECK CORPUS
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return;
+}
+
+// PARAGRAPH AS STRUCTURAL UNIT?
+
+/* note: some text have a structural unit called "p", which represents a paragraph.
+   If this structural unit is present, we use it.  Otherwise we ask the user (the
+   best way is to use the "pn" (paragraph number) or "lbn" (line number) property),
+   depending on what is available in the corpus. If the user give not property name,
+   we only define one paragraph for the whole text. */
+
+parUnit = corpus.getStructuralUnit("p")
+
+// BEGINNING OF PARAMETERS
+
+@Field @Option(name="unit_type",usage="", widget="String", required=true, def="MENTION")
+		String unit_type
+
+@Field @Option(name="filename",usage="", widget="String", required=true, def="filename without extension (.ac/.aa)")
+		String filename
+
+if (!parUnit) {
+	@Field @Option(name="par_prop",usage="the property used to compute paragraphs", widget="String", required=false, def="lbn")
+		String par_prop
+}
+
+if (!ParametersDialog.open(this)) return;
+
+// what paragraph unit to use?
+
+pn = null
+if (!parUnit && !par_prop.equals("")) {
+	pn = corpus.getProperty(par_prop)
+	if (!pn) {
+		println "Error: I can't find a the property `$par_prop'."
+		return
+	}
+}
+
+/*********************************/
+
+doExport(corpus, unit_type, filename)
+
+public void doExport(MainCorpus corpus, String unit_type, String filename) {
+
+	size = corpus.getSize() // you may also use: corpus.getTextEndLimits() (= index of last token = size-1)
+	word = corpus.getWordProperty()
+
+	// BUILD THE RAW TEXT, THE POSITIONS AND FIND THE PARAGRAPHS
+
+	rawText = "" // the corpus for the .ac file
+	positions = [] // each element is an array [start, end] indicating the position in the rawText
+	pnCount = 0 // the par counter, used for indexing the pars array
+	lastPn = -1 // the last paragraph number
+	pars = [] // each element is an array [start, end] representing the start and end of the paragraph in the rawText
+	insertSpace = true
+	for (def i=0; i<size; i++) {
+		f = CQI.cpos2Str(word.getQualifiedName(), (int[])[i])[0]
+		if (parUnit) {
+			p = CQI.cpos2Struc(parUnit.getQualifiedName(), (int[])[i])[0]
+		} else if (pn == null) {
+			p = 1
+		} else {
+			p = CQI.cpos2Str(pn.getQualifiedName(), (int[])[i])[0]
+		}
+		if (i > 0 && insertSpace
+				&& !f.equals(".") && !f.equals(",") && !f.equals("'") && !f.equals("’") && !f.equals("-")
+				&& !f.equals(")") && !f.equals("]") && !f.startsWith("-")) {
+			rawText += " "
+		}
+		insertSpace = true // reset
+		if (f.equals("-") || f.equals("[") || f.equals("(")
+				|| f.endsWith("-") || f.endsWith("'") || f.endsWith("’") || f.endsWith("-")) {
+			insertSpace = false
+		}
+		start = rawText.length()
+		rawText += f
+		if (lastPn != p) {
+			pnCount++;
+			if (pnCount > 1) {
+				pars[pnCount-2][1] = end
+			}
+			pars[pnCount-1] = [start, 0]
+		}
+		lastPn = p
+		end = rawText.length() // must be after setting it up in pars!
+		positions[i] = [start, end]
+	}
+	pars[pnCount-1][1] = end
+	println pnCount + " paragraph(s) found."
+
+	// CORPUS ANALEC (GET THE ANNOTATIONS)
+
+	// note that unit_type has been defined with an option of the dialog at the beginning
+	def analecCorpus = URSCorpora.getCorpus(corpus);
+
+	// list of properties
+
+	struct = analecCorpus.getStructure();
+	propertyList = struct.getUniteProperties(unit_type);
+
+	// export to file (corpus)
+
+	corpusFilename = filename + ".ac";
+	def corpusFile = new File(corpusFilename);
+	corpusFile.write(rawText)
+	println("Corpus written to `"+corpusFilename+"'.");
+
+	// export to file (annotations)
+
+	annotFilename = filename + ".aa";
+	def annotFile = new File(annotFilename)
+	annotFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<annotations>\n")
+		// erase (if you use << you don't erase!)
+	def counter = 0
+
+	// export paragraphs
+	for (def i=0; i<pars.size(); i++) {
+		def start = pars[i][0]
+		def end = pars[i][1]
+		annotFile << "<unit id=\"me_"+counter+"\">\n";
+		annotFile << "<metadata><author>me</author><creation-date>"+counter+"</creation-date></metadata>\n";
+		annotFile << "<characterisation><type>paragraph</type><featureSet /></characterisation>\n";
+		annotFile << "<positioning><start><singlePosition index=\""+start+"\" /></start><end><singlePosition index=\""+end+"\" /></end></positioning>\n";
+		annotFile << "</unit>\n";
+		counter++;
+	}
+
+	// export units
+	def units = analecCorpus.getUnites(unit_type);
+	//units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() };
+	def unitCount = 0
+	for (Unite unit : units) {
+		unitCount++;
+		annotFile << "<unit id=\"me_"+counter+"\">\n";
+		annotFile << "<metadata><author>me</author><creation-date>"+counter+"</creation-date></metadata>\n";
+		annotFile << "<characterisation>\n";
+		annotFile << "<type>"+unit_type+"</type>\n";
+		annotFile << "<featureSet>\n";
+		for (String propertyName : propertyList) {
+			annotFile << "<feature name=\""+propertyName+"\">"+unit.getProp(propertyName)+"</feature>\n";
+		}
+		annotFile << "</featureSet>\n";
+		annotFile << "</characterisation>\n";
+		start = positions[unit.getDeb()][0]
+		end = positions[unit.getFin()][1]
+		annotFile << "<positioning><start><singlePosition index=\""+start+"\" /></start><end><singlePosition index=\""+end+"\" /></end></positioning>\n";
+		annotFile << "</unit>\n";
+		counter++;
+	}
+	annotFile << "</annotations>\n";
+
+	println unitCount + " unit(s) found."
+
+	println("Annotations written to `"+annotFilename+"'.");
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/URSDemo.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/URSDemo.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/URSDemo.groovy	(revision 3653)
@@ -0,0 +1,173 @@
+package org.txm.macro.urs
+
+import org.txm.annotation.urs.URSCorpora
+import org.txm.searchengine.cqp.corpus.CQPCorpus
+import visuAnalec.elements.*
+
+// get the CQP corpus
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Corpus view selection is no a corpus: $corpusViewSelection"
+	return false;
+}
+def corpus = corpusViewSelection
+
+// get the Analec corpus : stores the annotations and annotation structure
+
+def analecCorpus = URSCorpora.getCorpus(corpus)
+
+// get the annotations structure : stores the available annotation types, properties and values
+
+def structure = analecCorpus.getStructure()
+
+// get the annotations view : stores annotations and annotation structure display rules
+
+def view = URSCorpora.getVue(corpus)
+
+// set a default vue -> all is visible
+view.retablirVueParDefaut()
+
+// list the viewed types and properties
+for (def type : view.getTypesAVoir(Unite.class)) {
+	println "$type: "+view.getNomsChamps(Unite.class, type)
+}
+
+// manage the viewed&enabled type, properties ; the types and properties must be enabled to use the "view.setValeurChamp(TYPE, PROPERTY, VALUE)" method
+view.ajouterType(Unite.class, "EXEMPLE")
+view.ajouterProp(Unite.class, "EXEMPLE", "PEXEMPLE")
+
+// display annotations per Element type (Unite, Relation, Schema) and per type
+
+// Create annotation type
+
+structure.ajouterType(Unite.class, "EXEMPLE");
+//structure.ajouterType(Relation.class, "EXEMPLE");
+//structure.ajouterType(Schema.class, "EXEMPLE");
+println structure.getTypes(Unite.class)
+
+// Create annotation property
+
+structure.ajouterProp(Unite.class, "EXEMPLE", "PEXEMPLE")
+println structure.getNomsProps(Unite.class, "EXEMPLE")
+
+// Create annotation value
+
+structure.ajouterVal(Unite.class, "EXEMPLE", "PEXEMPLE", "oui")
+structure.ajouterVal(Unite.class, "EXEMPLE", "PEXEMPLE", "non")
+
+// Create annotations
+
+// Unite
+def u = analecCorpus.addUniteSaisie("EXEMPLE", 0, 10, ["PEXEMPLE":"oui"])
+def u2 = analecCorpus.addUniteSaisie("EXEMPLE", 12, 12, ["PEXEMPLE":"oui"])
+println u
+
+// Edit annotations
+
+u.getProps()["PEXEMPLE"] = "non"
+
+// Unit getters
+
+println u.getDeb() // start of unit
+println u.getFin() // end of unit
+
+println u.getProp("EXEMPLE")
+println u.getType()
+
+// Relation
+Relation relation = new Relation("REXEMPLE", u, u2)
+relation.getProps().put("PEXEMPLE", "oui")
+analecCorpus.addRelationLue(relation)  // add the new relation
+
+// Schema
+Schema schema = new Schema()
+schema.type = "SEXEMPLE"
+schema.props.put("PEXEMPLE", "oui")
+schema.ajouter(u) // insert one unit
+
+analecCorpus.addSchemaLu(schema)  // add the new schema
+
+// Browse Units
+
+println "Units:"
+for (String type : structure.getUnites()) {
+	def units = analecCorpus.getUnites(type)
+	if (units.size() > 0) {
+		println "	${units.size()} $type"
+	}
+}
+
+// Browse Relations
+
+println "Relations:"
+for (String type : structure.getRelations()) {
+	def relations = analecCorpus.getRelations(type)
+	if (relations.size() > 0) {
+		println "	${relations.size()} $type"
+	}
+}
+
+// Browse Schemas
+
+println "Schemas:"
+for (String type : structure.getSchemas()) {
+	def schemas = analecCorpus.getSchemas(type)
+	if (schemas.size() > 0) {
+		println "	${schemas.size()} $type"
+	}
+}
+
+// URS selections
+
+// select Schemas
+def debug = 0 // 1 2 for more logs
+def strict_inclusion = true
+def position = 0
+def minimum_schema_size = 1;
+def maximum_schema_size = 10;
+def schema_ursql = "SEXEMPLE"
+def unit_ursql = "EXEMPLE@PEXEMPLE=oui"
+def unit_type = "EXEMPLE" 
+println AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, strict_inclusion)
+
+
+// with URSQL
+println AnalecUtils.filterElements(debug, analecCorpus.getUnites(unit_type), unit_ursql)
+
+// with intersection with CQP corpus matches
+println AnalecUtils.filterUniteByInclusion(debug, analecCorpus.getUnites(unit_type), corpus.getMatches(), strict_inclusion, position)
+
+// by size
+println AnalecUtils.filterBySize(analecCorpus.getSchemas(schema_ursql), minimum_schema_size, maximum_schema_size)
+
+// Delete annotations
+
+analecCorpus.supUnite(u)
+analecCorpus.supUnite(u2)
+analecCorpus.supRelation(relation)
+analecCorpus.supSchema(schema)
+
+// Delete annotation value
+
+structure.supprimerVal(Unite.class, "EXEMPLE", "PEXEMPLE", "oui")
+structure.supprimerVal(Unite.class, "EXEMPLE", "PEXEMPLE", "non")
+
+// Delete annotation property
+
+structure.supprimerProp(Unite.class, "EXEMPLE", "PEXEMPLE")
+structure.supprimerProp(Relation.class, "REXEMPLE", "PEXEMPLE")
+structure.supprimerProp(Schema.class, "SEXEMPLE", "PEXEMPLE")
+
+// Delete annotation type
+
+structure.supprimerType(Unite.class, "EXEMPLE");
+structure.supprimerType(Relation.class, "REXEMPLE");
+structure.supprimerType(Schema.class, "SEXEMPLE");
+
+// Revert changes
+
+//URSCorpora.revert(corpus);
+
+// Save changes
+
+//URSCorpora.saveCorpus(corpus)
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasSummaryMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasSummaryMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasSummaryMacro.groovy	(revision 3653)
@@ -0,0 +1,116 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.exploit
+
+import org.apache.commons.lang.StringUtils
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.Toolbox
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.macro.urs.AnalecUtils
+import org.txm.searchengine.cqp.AbstractCqiClient
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+
+import visuAnalec.donnees.Structure
+import visuAnalec.elements.*
+
+def scriptName = this.class.getSimpleName()
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=true, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+		int maximum_schema_size
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+if (!ParametersDialog.open(this)) return
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+def allresults = new LinkedHashMap()
+def props = new HashSet()
+for (def corpus : selection) {
+
+	def word = corpus.getWordProperty()
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+	
+	def errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)
+	if (errors.size() > 0) {
+		println "** The $schema_ursql schema URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+		
+	for (def type : analecCorpus.getStructure().getSchemas())
+		props.addAll(analecCorpus.getStructure().getSchemaProperties(type));
+
+	def selectedSchemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, strict_inclusion);
+	if (selectedSchemas.size() > 0)
+		allresults[corpus] = selectedSchemas.sort(){it.getUnite0()};
+}
+
+// tabulate summary
+def keys = allresults.keySet().sort();
+println "Statistiques des schémas de "+corpusViewSelections.join(", ")
+println "\t"+keys.join("\t")
+
+// number of schemas
+print "Schemas"
+for (def k : keys) {
+	print "\t"+allresults[k].size();
+}
+println ""
+
+// Average length
+print "Average len"
+for (def k : keys) {
+	int total = 0;
+	for (Schema s : allresults[k]) total+= s.contenu.size();
+	
+	print "\t"+total / allresults[k].size()
+}
+println ""
+
+// median length
+print "Median len"
+for (def k : keys) {
+	print "\t"+allresults[k][(int)(allresults[k].size() / 2)].contenu.size();
+}
+println ""
+
+// number of properties values
+for (def p : props) {
+	print "$p"
+	for (def k : keys) {
+		def propsvalues = new HashSet()
+		for (def schema : allresults[k]) {
+			propsvalues.add(schema.getProp(p))
+		}
+		if (debug) println "k @p values="+propsvalues
+		print "\t"+propsvalues.size();
+	}
+	println ""
+}
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/CQPUtils.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/CQPUtils.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/CQPUtils.groovy	(revision 3653)
@@ -0,0 +1,396 @@
+// Copyright © 2017 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author sheiden
+
+package org.txm.macro.urs.exploit
+
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.rcp.views.corpora.*
+
+def refreshCorpusViewExpand(monitor, corpus) {
+	monitor.syncExec(new Runnable() {
+		public void run() {
+			CorporaView.refresh()
+			CorporaView.expand(corpus)
+		}
+	})
+}
+
+def getCorpusByName(name) {
+	def cl = CorpusManager.getCorpusManager().getCorpora()
+	def rc = cl.find {
+		it.getName() == name
+	}
+	
+	if (rc) return rc
+	
+	def rsc = null
+	rc = cl.find { c ->
+		def scl = c.getSubcorpora()
+		def rrsc = scl.find { sc ->
+			sc.getName() == name
+		}
+		rsc = rrsc
+	}
+
+	return rsc
+}
+
+def getCorpora(def script) {
+
+	def scriptName = this.class.getSimpleName()
+
+	if (script.binding.variables["args"]) {
+		def args = script.binding.variables["args"]
+		if (args["corpus"]) {
+			return [getCorpusByName(args["corpus"])]
+		} else if (args["corpora"]) {
+			return args["corpora"].tokenize(',').collect {
+				return getCorpusByName(it)
+			}
+		} else {
+			if (script.corpusViewSelection == null || !(script.corpusViewSelection instanceof Subcorpus || script.corpusViewSelection instanceof MainCorpus)) {
+				return null
+			}
+			return script.corpusViewSelections.findAll { it instanceof Subcorpus || it instanceof MainCorpus }
+		}
+	} else {
+		if (script.corpusViewSelection == null || !(script.corpusViewSelection instanceof Subcorpus || script.corpusViewSelection instanceof MainCorpus)) {
+			return null
+		}
+		return script.corpusViewSelections.findAll { it instanceof Subcorpus || it instanceof MainCorpus }
+	}
+
+}
+
+def newTestSubCorpusName(name) {
+	def cl = CorpusManager.getCorpusManager().getCorpora()
+	def rc = cl.find {
+		it.getName() == name
+	}
+	
+	if (!rc) {
+		println "** corpus '"+name+"' not found."
+		return null
+	}
+	
+	def scl = rc.getSubcorpora()
+	def n = 1
+	def loop = true
+	while (loop) {
+		def rsc = scl.find { sc ->
+			sc.getName() == "CORPUS"+n
+		}
+		if (rsc) n++ else loop = false
+	}
+
+	return "CORPUS"+n
+}
+
+def positions2cql(matches) {
+	// [0],[1],[2-3],[4-5],[6]
+	// 0,1,2-3,4-5,6
+	// "(n1:[])|(n2:[] []{1}) :: (n1 = 0)|(n1 = 1)|(n1 = 6)|(n2 = 2)|(n2 = 4)"
+
+	def singletons = []
+	def intervals = [:]
+	matches.tokenize(',').each { interval ->
+		if (interval.indexOf('-') != -1) { // start-end
+			(start, end) = interval.tokenize('-') as int[]
+			l = end-start
+			if (intervals[l]) {
+				intervals.put(l, intervals[l] << start)
+			} else {
+				intervals.put(l, [start])
+			}
+		} else { // singleton
+			singletons << interval.toInteger()
+		}
+	}
+	
+	def singletonPositions = ""
+	def intervalsCQLs = ""
+	def intervalsPositions = ""
+	
+	// "(n1:[])|(n2:[] []{1}) :: (n1 = 0)|(n1 = 1)|(n1 = 6)|(n2 = 2)|(n2 = 4)"
+
+	def firstSingleton = true
+	singletons.each {
+		if (!firstSingleton) singletonPositions += "|"
+		firstSingleton = false
+		singletonPositions += "n1="+it+""
+	}
+
+	def firstInterval = true
+	intervals.each { length, positions ->
+		if (!firstInterval) intervalsCQLs += "|"
+		if (!firstInterval) intervalsPositions += "|"
+		firstInterval = false
+		intervalsCQLs += "n"+(length+1)+":[][]{"+length+"}"
+		def firstPosition = true
+		positions.each {
+			if (!firstPosition) intervalsPositions += "|"
+			firstPosition = false
+			intervalsPositions += "n"+(length+1)+"="+it
+		}
+	}
+
+	def q = ""
+	if (singletons.size() > 0) {
+		q += "n1:[]"
+	}
+	if (singletons.size() > 0 && intervals.size() > 0) {
+		q += "|"
+	}
+	if (intervals.size() > 0) {
+		q += intervalsCQLs
+	}
+	q += "::"
+	if (singletons.size() > 0) {
+		q += singletonPositions
+	}
+	if (singletons.size() > 0 && intervals.size() > 0) {
+		q += "|"
+	}
+	if (intervals.size() > 0) {
+		q += intervalsPositions
+	}
+	
+	return q
+	
+}
+
+def positionsList2positions(positionsList, maxMatches, pretty) {
+	
+	def res = ""
+
+	if (positionsList.size() == 0) {
+		return "<empty>"
+	} else {
+		def first = 1
+		positionsList.take(maxMatches).each {
+			if (first) { first = 0 } else {
+				if (pretty) {
+					res += ", "
+				} else {
+					res += ","
+				}
+			}
+			// res += "["
+			start = it[0]
+			end = it[1]
+			if (start < end) {
+				res += start+"-"+end
+			} else {
+				res += start
+			}
+			// res += "]"
+		}
+	}
+
+	if (positionsList.size() > maxMatches) {
+		res += "..."
+	}
+	
+	return res
+}
+
+def corpus2positions(def corpus, def maxMatches, def pretty = false) {
+	
+	def res = ""
+	def matches = corpus.getMatches()
+
+	if (matches.size() == 0) {
+		return "<empty>"
+	} else {
+		def first = 1
+		matches.take(maxMatches).each {
+			if (first) { first = 0 } else {
+				if (pretty) {
+					res += ", "
+				} else {
+					res += ","
+				}
+			}
+			// res += "["
+			if (it.getStart() < it.getEnd()) {
+				res += it.getStart()+"-"+it.getEnd()
+			} else {
+				res += it.getStart()
+			}
+			// res += "]"
+		}
+	}
+
+	if (matches.size() > maxMatches) {
+		res += "..."
+	}
+	
+	return res
+}
+
+methods = this.getClass().declaredMethods.findAll { !it.synthetic }.name.sort().unique()
+methods.removeAll(['main', 'run'])
+println "** CQPUtils is not meant to be called directly.\nPlease import its methods ${methods}\nwith the following declaration:\nimport org.txm.macro.cqp.CQPUtilsMacro"
+
+/*
+	  ___           ___           ___           ___           ___           ___
+	 /\  \         /\__\         /\__\         /\  \         |\__\         /\  \
+	/::\  \       /::|  |       /::|  |       /::\  \        |:|  |       /::\  \
+   /:/\:\  \     /:|:|  |      /:|:|  |      /:/\:\  \       |:|  |      /:/\:\  \
+  /::\~\:\  \   /:/|:|  |__   /:/|:|  |__   /::\~\:\  \      |:|__|__   /::\~\:\  \
+ /:/\:\ \:\__\ /:/ |:| /\__\ /:/ |:| /\__\ /:/\:\ \:\__\ ____/::::\__\ /:/\:\ \:\__\
+ \/__\:\/:/  / \/__|:|/:/  / \/__|:|/:/  / \:\~\:\ \/__/ \::::/~~/~    \:\~\:\ \/__/
+	  \::/  /      |:/:/  /      |:/:/  /   \:\ \:\__\    ~~|:|~~|      \:\ \:\__\
+	  /:/  /       |::/  /       |::/  /     \:\ \/__/      |:|  |       \:\ \/__/
+	 /:/  /        /:/  /        /:/  /       \:\__\        |:|  |        \:\__\
+	 \/__/         \/__/         \/__/         \/__/         \|__|         \/__/
+
+
+
+0 1 2 3 4 5 6 7 8 9
+
++ + + +
+0 1 2 3 4 5 6 7 8 9
++0,+1,+2,+3
+n:[] :: n = 0|n = 1|n = 2|n = 3
+
+[ ] [ ]
+0 1 2 3 4 5 6 7 8 9
+0-1,2-3
+n:[] []{1} :: n = 0
+n:[] []{1} :: n = 2
+
+[   ] +
+0 1 2 3 4 5 6 7 8 9
+0-2,+3
+n:[] []{2} :: n = 0
+n:[] :: n = 3
+
+
+ */
+
+/*
+
+Touching intervals mergers
+==========================
+
+A) from http://stackoverflow.com/questions/31670849/merge-overlapping-intervals
+
+import java.util.*;
+
+public class Ideone
+{
+	public static void main (String[] args) throws java.lang.Exception
+	{
+		ArrayList<Interval> x = new ArrayList<>();
+
+		x.add(new Interval(1, 3));
+		x.add(new Interval(2, 6));
+		x.add(new Interval(8, 10));
+		x.add(new Interval(15, 18));
+		x.add(new Interval(17, 20));
+
+		x = merge(x);
+
+		for(Interval i : x)
+		{
+			System.out.println(i.getStart() + " " + i.getEnd());
+		}
+	}
+
+	public static ArrayList<Interval> merge(ArrayList<Interval> intervals) {
+
+		if(intervals.size() == 0 || intervals.size() == 1)
+			return intervals;
+
+		Collections.sort(intervals, new IntervalComparator());
+
+		Interval first = intervals.get(0);
+		int start = first.getStart();
+		int end = first.getEnd();
+
+		ArrayList<Interval> result = new ArrayList<Interval>();
+
+		for (int i = 1; i < intervals.size(); i++) {
+			Interval current = intervals.get(i);
+			if (current.getStart() <= end) {
+				end = Math.max(current.getEnd(), end);
+			} else {
+				result.add(new Interval(start, end));
+				start = current.getStart();
+				end = current.getEnd();
+			}
+		}
+
+		result.add(new Interval(start, end));
+		return result;
+	}
+}
+
+class Interval
+{
+	private int start;
+	private int end;
+
+	Interval() {
+		start = 0;
+		end = 0;
+	}
+
+	Interval(int s, int e)
+	{
+		start = s;
+		end = e;
+	}
+
+	public int getStart() {
+		return start;
+	}
+
+	public int getEnd() {
+		return end;
+	}
+}
+
+class IntervalComparator implements Comparator<Interval>
+{
+	public int compare(Interval i1, Interval i2)
+	{
+		return i1.getStart() - i2.getStart();
+	}
+}
+
+B) from http://www.programcreek.com/2012/12/leetcode-merge-intervals/
+
+public List<Interval> merge(List<Interval> intervals) {
+	List<Interval> result = new ArrayList<Interval>();
+ 
+	if(intervals==null||intervals.size()==0)
+		return result;
+ 
+	Collections.sort(intervals, new Comparator<Interval>(){
+		public int compare(Interval i1, Interval i2){
+			if(i1.start!=i2.start)
+				return i1.start-i2.start;
+			else
+				return i1.end-i2.end;
+		}
+	});
+ 
+	Interval pre = intervals.get(0);
+	for(int i=0; i<intervals.size(); i++){
+		Interval curr = intervals.get(i);
+		if(curr.start>pre.end){
+			result.add(pre);
+			pre = curr;
+		}else{
+			Interval merged = new Interval(pre.start, Math.max(pre.end, curr.end));
+			pre = merged;
+		}
+	}
+	result.add(pre);
+ 
+	return result;
+}
+ */
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasRatioMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasRatioMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasRatioMacro.groovy	(revision 3653)
@@ -0,0 +1,135 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.exploit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.macro.urs.AnalecUtils
+import visuAnalec.elements.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.Toolbox
+import org.txm.rcp.commands.*
+import org.txm.statsengine.r.core.RWorkspace
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=REGEX", widget="String", required=true, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="minimal schema size", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+		int maximum_schema_size
+@Field @Option(name="schema_property_display", usage="schema property to show", widget="String", required=true, def="REF")
+		String schema_property_display
+		
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=REGEX", widget="String", required=false, def="MENTION")
+		String unit_ursql
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+@Field @Option(name="position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int position_in_matches
+		
+@Field @Option(name="units_margin_ursql", usage="TYPE@PROP=REGEX", widget="String", required=false, def="MENTION")
+		String units_margin_ursql
+@Field @Option(name="margin_strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean margin_strict_inclusion
+@Field @Option(name="margin_position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int margin_position_in_matches
+		
+@Field @Option(name="sep", usage="choose between the len or freq columns", widget="Separator", metaVar="freq	len", required=false, def="")
+		def sep
+@Field @Option(name="sort_column", usage="choose between the len or freq columns", widget="StringArray", metaVar="score	name", required=true, def="score")
+		String sort_column
+@Field @Option(name="max_lines", usage="cut the number of lines shown. '0' means no cut", widget="Integer", required=false, def="0")
+		int max_lines
+//@Field @Option(name="output_graph", usage="Show chart", widget="Boolean", required=true, def="false")
+		output_graph = false
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+for (def corpus : selection) {
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+
+	def errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)
+	if (errors.size() > 0) {
+		println "** The $schema_ursql schema URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+
+	errors=AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, unit_ursql)
+	if (errors.size() > 0) {
+		println "** $unit_ursql unit URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+
+	def schemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, strict_inclusion);
+
+	int nSchemas = 0;
+
+	def scores = [:]
+	def fs = [:]
+	def fs_margin = [:]
+	for (def schema : schemas) {
+
+		def allUnites = schema.getUnitesSousjacentesNonTriees()
+		def units = AnalecUtils.filterElements(debug, allUnites, unit_ursql)
+		selectedUnits = AnalecUtils.filterUniteByInclusion(debug, units, corpus.getMatches(), strict_inclusion, position_in_matches)
+		
+		def units_margin = AnalecUtils.filterElements(debug, allUnites, units_margin_ursql)
+		selectedUnits_margin = AnalecUtils.filterUniteByInclusion(debug, units_margin, corpus.getMatches(), margin_strict_inclusion, margin_position_in_matches)
+		
+		if (!scores.containsKey(schema)) {
+			scores[schema] = 0;
+		}
+
+		scores[schema] = 0;
+		fs[schema] = selectedUnits.size();
+		fs_margin[schema] = selectedUnits_margin.size();
+		if (selectedUnits_margin.size() > 0) {
+			scores[schema] = (float)selectedUnits.size() / (float)selectedUnits_margin.size()
+		}
+		
+		nSchemas++;
+	}
+
+	if ("score".equals(sort_column)) {
+		scores = scores.sort { a, b -> -a.value <=> -b.value ?: -fs[a.key]<=> -fs[b.key] ?: a.key.getProps()[schema_property_display].compareTo(b.key.getProps()[schema_property_display]) }
+	} else {
+		scores = scores.sort { a, b -> a.key.getProps()[schema_property_display].compareTo(b.key.getProps()[schema_property_display]) ?: -a.value <=> -b.value ?: -fs[a.key]<=> -fs[b.key]}
+	}
+	
+	println "Schema scores in '$corpus'."
+	println "${schema_property_display}\tF\tF margin\tscore"
+	int nShown = 0;
+	for( def it : scores) {
+		println ""+it.key.getProps()[schema_property_display]+"\t"+fs[it.key]+"\t"+fs_margin[it.key]+"\t"+String.format( "%.2f", it.value * 100.0d )+"%"
+		nShown++
+		if (max_lines > 0 && nShown >= max_lines) {
+			println "... (${scores.size() - max_lines})"
+			break;
+		}
+	}
+
+	//return ["result":coef, "data":lens]
+}
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsReferentialDensityMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsReferentialDensityMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsReferentialDensityMacro.groovy	(revision 3653)
@@ -0,0 +1,70 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.exploit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import visuAnalec.elements.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.macro.urs.AnalecUtils
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="CHAINE")
+String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=false, def="3")
+int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=false, def="9999999")
+int maximum_schema_size
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+String unit_ursql
+@Field @Option(name="position_in_schema", usage="Unit distance in schema (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=false, def="0")
+int position_in_schema
+@Field @Option(name="cql_limit", usage="CQL to build structure limits", widget="Query", required=false, def="")
+cql_limit
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=false, def="true")
+strict_inclusion
+@Field @Option(name="position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=false, def="0")
+position_in_matches
+
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+debug
+
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+for (def corpus : selection) {
+	
+	def analecCorpus = URSCorpora.getCorpus(corpus);
+	
+	int nMots = corpus.getSize();
+	
+	def units = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size,
+	unit_ursql, position_in_schema, cql_limit, strict_inclusion, position_in_matches);
+	
+	int nUnites = units.size();
+	
+	coef = (nUnites /nMots)
+	rounded = String.format( "%.2f", coef * 100.0d )
+	println "$corpus referential density: nUnites/nMots = $nUnites/$nMots = $coef = ${rounded}%"
+	if (nUnites >= nMots) {
+		println "WARNING: possible encoding error in $corpus. Number of units ($nUnites) is greater than number of words ($nMots)"
+	}
+	//return ["result":coef, "data":["nUnites":nUnites, "nMots":nMots]]
+}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemaLengthsMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemaLengthsMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemaLengthsMacro.groovy	(revision 3653)
@@ -0,0 +1,189 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.exploit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.macro.urs.AnalecUtils
+import visuAnalec.elements.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.Toolbox
+import org.txm.rcp.commands.*
+import org.txm.statsengine.r.core.RWorkspace
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=REGEX", widget="String", required=true, def="CHAINE")
+		String schema_ursql
+
+@Field @Option(name="minimum_schema_size", usage="minimal schema size", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+		int maximum_schema_size
+@Field @Option(name="schema_property_display", usage="schema property to show", widget="String", required=true, def="REF")
+		String schema_property_display
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=REGEX", widget="String", required=false, def="MENTION")
+		String unit_ursql
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+@Field @Option(name="position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int position_in_matches
+@Field @Option(name="sep", usage="choose between the len or freq columns", widget="Separator", metaVar="freq	len", required=false, def="")
+		def sep
+@Field @Option(name="sort_column", usage="choose between the len or freq columns", widget="StringArray", metaVar="freq	len", required=true, def="freq")
+		String sort_column
+@Field @Option(name="max_lines", usage="cut the number of lines shown. '0' means no cut", widget="Integer", required=false, def="0")
+		int max_lines
+//@Field @Option(name="output_graph", usage="Show chart", widget="Boolean", required=true, def="false")
+		output_graph = false
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+for (def corpus : selection) {
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+
+	def errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)
+	if (errors.size() > 0) {
+		println "** The $schema_ursql schema URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+
+	errors=AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, unit_ursql)
+	if (errors.size() > 0) {
+		println "** $unit_ursql unit URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+
+	//println([debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, strict_inclusion])
+	def schemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, strict_inclusion);
+
+	int nSchemas = 0;
+
+	def lens = [:]
+	def lensnames = [:]
+	for (def schema : schemas) {
+
+		def allUnites = schema.getUnitesSousjacentesNonTriees()
+		
+		def units = AnalecUtils.filterElements(debug, allUnites, unit_ursql)
+		
+		selectedUnits = AnalecUtils.filterUniteByInclusion(debug, units, corpus.getMatches(), strict_inclusion, position_in_matches)
+		
+		int nUnites = selectedUnits.size();
+
+		if (!lens.containsKey(nUnites)) {
+			lens[nUnites] = 0;
+			lensnames[nUnites] = [];
+		}
+
+		lens[nUnites] = lens[nUnites] + 1;
+		String value = schema.getProp(schema_property_display);
+		//if (value.contains(",")) value = "\"$value\""
+		lensnames[nUnites] << value
+		nSchemas++;
+	}
+
+	//println "nSchemas=$nSchemas"
+	def freqs = lens.keySet();
+	freqs.sort();
+	int t = 0;
+	int n = 0;
+	//println "Fréquences ("+freqs.size()+")"
+	for (def f : freqs) {
+		t += f * lens[f]
+		n += lens[f]
+	}
+
+	if (n == 0) {
+		println "No units selected for schemas=$schema_ursql and units=$unit_ursql"
+		return false;
+	}
+	
+	coef = (t/n)
+	
+	def slens = null
+	if ("freq".equals(sort_column)) {
+		slens = lens.sort { a, b -> -a.value <=> -b.value ?: -a.key <=> -b.key }
+	} else {
+		slens = lens.sort { a, b -> -a.key <=> -b.key ?: -a.value <=> -b.value }
+	}
+	
+	def flens = []
+	slens.each { key, value -> value.times { flens << key } }
+	def nbins = flens.size()*2
+
+	def cfreq = 0
+	println "Schema lengths in '$corpus'. The average schema length is $t/$n = "+coef
+	println "Index:\nlen\tfreq\tcfreq"
+	int nShown = 0;
+	for( def it : slens) {
+		def names = lensnames[it.key]
+		names = names.sort()
+		println it.key+"	"+it.value+"	"+(cfreq+=it.value)+"	\""+names.join("\", \"")+"\""
+		nShown++
+		if (max_lines > 0 && nShown >= max_lines) {
+			println "... (${slens.size() - max_lines})"
+			break;
+		}
+	}
+
+	def slens2 = slens.sort { a, b -> -a.key <=> -b.key }
+	if (output_graph) {
+		def r = RWorkspace.getRWorkspaceInstance()
+
+		r.addVectorToWorkspace("len", slens2.keySet() as int[])
+		r.addVectorToWorkspace("freq", slens2.values() as int[])
+		r.addVectorToWorkspace("flen", flens as int[])
+
+		def corpusName = corpus.getName()
+		println "corpusName=$corpusName"
+		def PNGFile = File.createTempFile("txm_"+corpus.getID()+"_", ".png", new File(Toolbox.getTxmHomePath(), "results"))
+		def PNGFilePath = PNGFile.getAbsolutePath()
+		println "PNG file: "+PNGFilePath
+
+		def SVGFile = File.createTempFile("txm_"+corpus.getID()+"_", ".svg", new File(Toolbox.getTxmHomePath(), "results"))
+		def SVGFilePath = SVGFile.getAbsolutePath()
+		println "SVG file: "+SVGFilePath
+
+		/// BEGINNING OF R SCRIPT
+		def script ="""
+hist(flen, xaxt='n', col="gray", xlab="Length", breaks=$nbins, main="$corpusName Longueur des chaînes ($nbins bins)")
+axis(side=1, at=len)
+dev.off()
+"""
+		/// END OF R SCRIPT
+
+		// execute R script
+		r.plot(PNGFile, "png(file = \"${PNGFilePath}\"); "+script)
+		r.plot(SVGFile, "svg(file = \"${SVGFilePath}\"); "+script)
+
+		//display the SVG results graphic
+		monitor.syncExec(new Runnable() {
+					@Override
+					public void run() { OpenBrowser.openfile(SVGFile.getAbsolutePath(), corpusName+" Longueur des chaînes") }
+				})
+	}
+	//return ["result":coef, "data":lens]
+}
+
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsReferentialStabilityMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsReferentialStabilityMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsReferentialStabilityMacro.groovy	(revision 3653)
@@ -0,0 +1,145 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.exploit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+import org.apache.commons.lang.StringUtils;
+import org.txm.macro.urs.AnalecUtils
+import visuAnalec.elements.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=REGEX", widget="String", required=true, def="CHAINE")
+String schema_ursql
+
+@Field @Option(name="minimum_schema_size", usage="minimal schema size", widget="Integer", required=true, def="3")
+int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+int maximum_schema_size
+@Field @Option(name="schema_display_property_name",usage="", widget="String", required=false, def="REF")
+String schema_display_property_name
+
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=REGEX", widget="String", required=false, def="MENTION")
+String unit_ursql
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+boolean strict_inclusion
+@Field @Option(name="word_property", usage="", widget="String", required=false, def="word")
+String word_property
+
+@Field @Option(name="show_values", usage="", widget="Boolean", required=false, def="false")
+boolean show_values
+
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+debug
+
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+
+for (def corpus : selection) {
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+	
+	def errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)
+	if (errors.size() > 0) {
+		println "** The $schema_ursql schema URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+	
+	errors=AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, unit_ursql)
+	if (errors.size() > 0) {
+		println "** $unit_ursql unit URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+	def CQI = CQPSearchEngine.getCqiClient()
+	
+	def prop = corpus.getProperty(word_property)
+	if (prop == null) { // no CQP property called $word_property
+		errors=AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, AnalecUtils.getFilterParameters(unit_ursql)[0], word_property)
+		if (errors.size() > 0) {
+			println "** $word_property unit property cannot be computed in the corpus with types: $errors."
+			return;
+		}
+	}
+	def schemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, strict_inclusion);
+	allFormesSet = new HashSet();
+	def coefs = []
+	int n = 1
+	
+	int nUnitesAllSchemas = 0
+	int nUnitesTotalSchemas = 0
+	
+	println "** $corpus schemas: "
+	for (def schema : schemas) {
+		def formesSet = new HashSet(); // contient toutes les formes du CR courant
+		nUnitesTotal = 0;
+		
+		def allUnites = schema.getUnitesSousjacentesNonTriees()
+	
+		def units = AnalecUtils.filterElements(debug, allUnites, unit_ursql)
+		def nUnites = schema.getUnitesSousjacentes().size()
+		def nUnitesTotal = units.size()
+		for (def unit : units) {
+		
+			String forme =  null;
+			if (prop == null) { // word_property is the analec unit property to use
+				forme = unit.getProp(word_property)
+			} else {
+				int[] pos = null;
+				if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+				else pos = unit.getDeb()..unit.getFin()
+					
+				forme = StringUtils.join(CQI.cpos2Str(prop.getQualifiedName(), pos), " ") // ids is enough
+			}
+			
+			formesSet.add(forme)
+		}
+		
+		if (formesSet.size() == 0 || nUnitesTotal == 0) {
+			coef = "NA"
+		} else {
+			coef = (nUnitesTotal/formesSet.size())
+		}
+		coefs << coef
+		allFormesSet.addAll(formesSet)
+		
+		if (schema_display_property_name != null && schema_display_property_name.length() > 0) {
+			print schema.getProp(schema_display_property_name)
+		} else {
+			print schema_ursql+"-"+n+" : "
+		}
+		
+		println " ($nUnites units) : $nUnitesTotal selected units / ${formesSet.size()} ${word_property}s = $coef"
+		if (show_values) {
+			println "\t${word_property}s="+formesSet
+		}
+		n++
+		
+		nUnitesAllSchemas += nUnites
+		nUnitesTotalSchemas += nUnitesTotal
+	}
+	
+	coef = nUnitesTotalSchemas/allFormesSet.size()
+	//println "ALL : ($nUnitesAllSchemas units) : $nUnitesTotalSchemas selected units / ${allFormesSet.size()} ${word_property}s = $coef"
+	
+//	return ["result":coefs, "data":["nUnitesTotal":nUnitesTotalSchemas, "allFormesSet":allFormesSet], "coef":(coef)]
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/Units2SubCorpusMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/Units2SubCorpusMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/Units2SubCorpusMacro.groovy	(revision 3653)
@@ -0,0 +1,91 @@
+package org.txm.macro.urs.exploit
+
+// Copyright © 2021 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author sheiden
+
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.*
+import org.txm.*
+import org.txm.rcpapplication.views.*
+//import org.txm.macro.cqp.CQPUtils
+import org.txm.annotation.urs.URSCorpora
+import org.txm.macro.urs.AnalecUtils
+
+// BEGINNING OF PARAMETERS
+
+// Declare each parameter here
+// (available widget types: Query, File, Folder, String, Text, Boolean, Integer, Float and Date)
+
+@Field @Option(name="subcorpus_name", usage="name of the subcorpus result", widget="String", required=true, def="subcorpus1")
+def subcorpus_name
+
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+String unit_ursql
+
+@Field @Option(name="debug", usage="Show debug information", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=false, def="OFF")
+debug
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return false
+
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+def scriptName = this.class.getSimpleName()
+
+def utils = new CQPUtils()
+
+corpora = utils.getCorpora(this)
+
+if ((corpora == null) || corpora.size() > 1) {
+	println "** $scriptName: please select a corpus in the Corpus view or provide a corpus name. Aborting."
+	return false
+}
+
+corpus = corpora[0].getMainCorpus()
+corpusName = corpus.getName()
+
+if (!URSCorpora.isAnnotationStructureReady(corpus)) {
+	println "** URS Annotation Structure of "+corpusName+" is not ready. Aborting."
+	return
+}
+
+def analecCorpus = URSCorpora.getCorpus(corpus)
+	
+def selectedUnits = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, null, 0, 1000000, unit_ursql, 0, null, false, 0)
+
+nUnits = selectedUnits.size()
+query = ""
+
+if (nUnits == 0) {
+	println "No units selected, no subcorpus created."
+	return
+} else {
+	println nUnits+" units selected."
+	positionsList = selectedUnits.collect {
+		[it.getDeb(), it.getFin()]
+	}
+	query = utils.positions2cql(utils.positionsList2positions(positionsList, 20, false))
+}
+
+String resultCqpId = CqpObject.subcorpusNamePrefix + CQPCorpus.getNextSubcorpusCounter()
+String queryString = "$resultCqpId=$query;"
+
+CQI.query(queryString)
+
+def subcorpus = corpora[0].createSubcorpus(new CQLQuery("$query;"), subcorpus_name)
+
+if (binding.variables["monitor"]) {
+	utils.refreshCorpusViewExpand(monitor, subcorpus.getParent())
+}
+
+return true
+
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsIndexMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsIndexMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsIndexMacro.groovy	(revision 3653)
@@ -0,0 +1,308 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.exploit
+
+import groovy.transform.Field
+
+import org.apache.commons.lang.StringUtils
+import org.kohsuke.args4j.*
+import org.txm.Toolbox
+import org.txm.annotation.urs.*
+import org.txm.lexicaltable.core.functions.LexicalTable
+import org.txm.lexicaltable.core.statsengine.r.data.LexicalTableImpl
+import org.txm.macro.urs.*
+import org.txm.rcp.commands.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.rcp.views.corpora.CorporaView
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.txm.statsengine.r.core.RWorkspace
+
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import cern.colt.matrix.DoubleFactory2D
+import cern.colt.matrix.DoubleMatrix2D
+
+def scriptName = this.class.getSimpleName()
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=false, def="3")
+		int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=false, def="9999999")
+		int maximum_schema_size
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+		String unit_ursql
+@Field @Option(name="unit_property_display_list", usage="Unit property to count", widget="String", required=false, def="CATEGORIE")
+		def unit_property_display_list
+@Field @Option(name="word_property_display", usage="Word property to display instead of the unit property", widget="String", required=false, def="")
+		String word_property_display
+@Field @Option(name="position_in_schema", usage="Unit distance in schema (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=false, def="0")
+		int position_in_schema
+@Field @Option(name="cql_limit", usage="CQL to build structure limits", widget="Query", required=false, def="")
+		cql_limit
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=false, def="true")
+		strict_inclusion
+@Field @Option(name="position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=false, def="0")
+		position_in_matches
+//@Field @Option(name="output_2D", usage="output barplot or 3D plot", widget="Boolean", required=true, def="true")
+		output_2D = true
+@Field @Option(name="output_showlegend", usage="output barplot or 3D plot", widget="Boolean", required=false, def="true")
+		output_showlegend
+@Field @Option(name="output_fmin", usage="minimal frequency displayed", widget="Integer", required=false, def="0")
+		output_fmin
+@Field @Option(name="output_histogram", usage="show or not a histogram of the result", widget="Boolean", required=false, def="true")
+		output_histogram
+@Field @Option(name="output_lexicaltable", usage="create or not a lexical table with the result", widget="Boolean", required=false, def="false")
+		output_lexicaltable
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=false, def="OFF")
+		debug
+		
+if (!ParametersDialog.open(this)) return
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+unit_property_display_list =  unit_property_display_list.split(",") as List
+unit_property_display_list.removeAll("")
+
+if (word_property_display != null && word_property_display.length() > 0 && unit_property_display_list != null && unit_property_display_list.size() > 0) {
+	println "Warning: both unit_property_display_list=$unit_property_display_list and word_property_display=$word_property_display are set. The index will be computed with the $word_property_display CQP property."
+}
+
+if (word_property_display.length() == 0 && unit_property_display_list.size() == 0) {
+	println "Error: no analysis property specified in unit_property_display_list or word_property_display. Aborting."
+	return
+}
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+def allresults = [:]
+for (def corpus : selection) {
+
+	def word = corpus.getWordProperty()
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+
+	def errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)
+	if (errors.size() > 0) {
+		println "** The $schema_ursql schema URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+	
+	errors=AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, unit_ursql)
+	if (errors.size() > 0) {
+		println "** $unit_ursql unit URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+	
+	for (def unit_property_display : unit_property_display_list) {
+		println "testing '$unit_property_display'"
+		errors = AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, AnalecUtils.getFilterParameters(unit_ursql)[0], unit_property_display).size()
+		if (errors > 0) {
+			println "Error: some Unit types don't contain the $unit_property_display property: $errors"
+			return
+		}
+	}
+
+	def selectedUnits = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size,
+			unit_ursql, position_in_schema, cql_limit, strict_inclusion, position_in_matches);
+	selectedUnits = new HashSet(selectedUnits)
+	def counts = null
+	if (word_property_display != null && word_property_display.length() > 0) {
+		Property p = corpus.getProperty(word_property_display)
+		int[] pos = null
+		counts = [:]
+		for (def unit : selectedUnits) {
+
+			if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+			else pos = (unit.getDeb()..unit.getFin())
+
+			String s = StringUtils.join(CQI.cpos2Str(p.getQualifiedName(), pos), " ")
+			if (!counts.containsKey(s)) counts[s] = 0
+			counts[s] = counts[s] + 1
+		}
+	} else { // use Analec unit property
+		counts = selectedUnits.countBy { 
+			def values = []
+			for (def unit_property_display : unit_property_display_list) {
+				
+				if (it.getProp(unit_property_display) == null)  {
+					values << "<null>"
+				} else {
+					values << it.getProp(unit_property_display)
+				}
+			}
+			return values.join(" ")
+		}
+	}
+	
+	if (counts.containsKey("")) counts["<empty>"] = counts[""];
+	counts.remove("")
+	
+	if (debug) {
+		println "\n*** Statistics: "
+		for (def k : counts.keySet()) {
+			if (k.size() > 0) { println "$k\t"+counts[k] }else{ println "N/A\t"+counts[k] }
+		}
+	}
+
+	allresults[corpus] = counts
+}
+if (debug) println "RESULTS=$allresults"
+def keys = new HashSet();
+for (def corpus : allresults.keySet()) keys.addAll(allresults[corpus].keySet())
+if (keys.size() == 0) {
+	println "No values for $unit_property_display property"
+	return
+}
+keys = keys.sort()
+mFactory = DoubleFactory2D.dense
+matrix = mFactory.make(keys.size(), selection.size())
+
+if (debug) println "KEYS=$keys"
+
+def corpus = null
+if (corpusViewSelection instanceof Partition) { corpus = corpusViewSelection.getCorpus() }
+else { corpus = corpusViewSelection }
+
+def title = "${corpus.getMainCorpus()}.${corpusViewSelection} ${unit_ursql}"
+title += "[${position_in_matches}]."
+if (word_property_display.length() > 0) title += "${word_property_display} frequencies"
+else if (unit_property_display_list.size() > 0) title += "${unit_property_display_list.join(' ')} frequencies"
+if (cql_limit != null && !cql_limit.getQueryString().equals("\"\"")) title += "\n(${cql_limit} limits)"
+
+if (word_property_display.length() > 0) println "Index de la propriété $word_property_display des mots des unités $unit_ursql[$position_in_matches] de ${corpus.getMainCorpus()}.${corpusViewSelection}"
+else println "Index de la propriété ${unit_property_display_list.join(' ')} des unités $unit_ursql[$position_in_matches] de ${corpus.getMainCorpus()}.${corpusViewSelection}"
+println "${unit_property_display_list.join(' ')}\t"+selection.join("\t")
+
+keys.eachWithIndex { prop_val, i ->
+	String line = ""
+	if (prop_val.size() > 0) {
+		line += prop_val
+	} else {
+		line += "N/A"
+	}
+
+	int min = 0;
+	allresults.keySet().eachWithIndex { c, j ->
+		def freq = allresults[c][prop_val]
+		if (freq == null) freq = 0
+
+		matrix.set(i, j, freq)
+		line += "\t"+freq
+		if (min < freq) min = freq
+	}
+	if (min >= output_fmin)
+		println "$line"
+}
+props = keys
+
+
+
+def resultsDir = new File(Toolbox.getTxmHomePath(), "results")
+resultsDir.mkdirs()
+def file = File.createTempFile("txm", ".svg", resultsDir)
+
+
+//if (corpusViewSelection.getClass() == org.txm.searchengine.cqp.corpus.Partition) { corpus = corpusViewSelection.getParent() } else { corpus = corpusViewSelection }
+if (output_histogram) {
+	
+	def r = RWorkspace.getRWorkspaceInstance()
+	def colnames = selection as String[]
+	r.addVectorToWorkspace("texts", colnames)
+	def rownames = props as String[]
+	r.addVectorToWorkspace("props", rownames)
+	r.addMatrixToWorkspace("textpropfreqs", matrix as DoubleMatrix2D)
+	r.eval("rownames(textpropfreqs) = props")
+	r.eval("colnames(textpropfreqs) = texts")
+	
+	def plotScript
+	String legend = "rownames(textpropfreqs)"
+	if (!output_showlegend) legend = "NULL"
+
+	if (output_2D) {
+		plotScript = """rez <- barplot(height=textpropfreqs, main="${title}", xlab="Parties", legend=${legend}, beside=TRUE, col=rainbow(length(rownames(textpropfreqs))))"""
+	} else {
+		plotScript = """
+		   library(latticeExtra)
+		   library(lattice)
+		   cloud(value~col+row, ..., panel.3d.cloud=panel.3dbars, col.facet='grey', xbase=0.4, ybase=0.4, scales=list(arrows=FALSE, col=1), par.settings = list(axis.line = list(col = "transparent")))
+		   """
+	}
+
+	// execute R script
+	r.eval("library(RColorBrewer);")
+	r.plot(file, plotScript)
+	
+	//display the SVG results graphic	
+}
+
+def lt = null;
+if (output_lexicaltable) {
+	def parent = selection[0]
+	println "parent="+parent.getClass()
+	if (parent instanceof Part) {
+		println "part="+parent
+		parent = parent.getParent()
+		println "partition="+parent
+		lt = new LexicalTable(parent);
+		lt.setData(new LexicalTableImpl(matrix as DoubleMatrix2D, rownames, colnames))
+
+	} else {
+		lt = new LexicalTable(parent);
+		lt.setData(new LexicalTableImpl(matrix as DoubleMatrix2D, rownames, colnames))
+	}
+	lt.setUserName(schema_ursql+">"+unit_ursql)
+}
+
+if (file.exists() && file.getTotalSpace() > 0) {
+	println "SVG file: "+file.getAbsolutePath()
+
+	monitor.syncExec(new Runnable() {
+				@Override
+				public void run() { try {
+						if (UnitsIndexMacro.this.output_histogram) {
+							OpenBrowser.openfile(file.getAbsolutePath())
+						}
+						if (UnitsIndexMacro.this.output_lexicaltable) {
+							CorporaView.refreshObject(corpus)
+							CorporaView.expand(lt)
+						}
+					} catch (e) { println "** ERROR: "+e }}
+			})
+} else {
+	println "Error: cannot show histogram result with $file"
+}
+
+
+/*
+ d <- read.table(text=' x   y     z
+ t1   5   high
+ t1   2   low
+ t1   4   med
+ t2   8   high
+ t2   1   low
+ t2   3   med
+ t3  50   high
+ t3  12   med
+ t3  35   low', header=TRUE)
+ library(latticeExtra)
+ cloud(y~x+z, d, panel.3d.cloud=panel.3dbars, col.facet='grey',
+ xbase=0.4, ybase=0.4, scales=list(arrows=FALSE, col=1),
+ par.settings = list(axis.line = list(col = "transparent")))
+ */
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasIndexMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasIndexMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasIndexMacro.groovy	(revision 3653)
@@ -0,0 +1,149 @@
+// Copyright © 2019 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.exploit
+
+import groovy.transform.Field
+
+import org.apache.commons.lang.StringUtils
+import org.kohsuke.args4j.*
+import org.txm.Toolbox
+import org.txm.annotation.urs.*
+import org.txm.lexicaltable.core.functions.LexicalTable
+import org.txm.lexicaltable.core.statsengine.r.data.LexicalTableImpl
+import org.txm.macro.urs.*
+import org.txm.rcp.commands.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.rcp.views.corpora.CorporaView
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.txm.statsengine.r.core.RWorkspace
+
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import cern.colt.matrix.DoubleFactory2D
+import cern.colt.matrix.DoubleMatrix2D
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=true, def="CHAINE")
+String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="minimal schema size", widget="Integer", required=true, def="3")
+int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+int maximum_schema_size
+@Field @Option(name="schema_property_display", usage="schema property to show", widget="String", required=true, def="REF")
+String schema_property_display
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+String unit_ursql
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+boolean strict_inclusion
+@Field @Option(name="output_fmin", usage="minimal frequency displayed", widget="Integer", required=false, def="0")
+output_fmin
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+debug
+
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+def allresults = [:]
+for (def corpus : selection) {
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+	
+	def errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)
+	if (errors.size() > 0) {
+		println "** The $schema_ursql schema URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+	
+	errors=AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_property_display)
+	if (errors.size() > 0) {
+		println "** $schema_property_display schema property not found in the corpus with types: $errors."
+		return;
+	}
+	
+	errors = AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, unit_ursql)
+	if (errors.size() > 0) {
+		println "** $unit_ursql unit URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+	
+	def CQI = CQPSearchEngine.getCqiClient()
+		
+	def schemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, strict_inclusion);
+	schemas.sort() {it.getProps()}
+	
+	def counts = schemas.countBy { if (it.getProp(schema_property_display) == null) "<null>" else it.getProp(schema_property_display) }
+	
+	if (counts.containsKey("")) counts["<empty>"] = counts[""];
+	counts.remove("")
+	
+	if (debug) {
+		println "\n*** Statistics: "
+		for (def k : counts.keySet()) {
+			if (k.size() > 0) { println "$k\t"+counts[k] }else{ println "N/A\t"+counts[k] }
+		}
+	}
+
+	allresults[corpus] = counts
+}
+
+if (debug) println "RESULTS=$allresults"
+def keys = new HashSet();
+for (def corpus : allresults.keySet()) keys.addAll(allresults[corpus].keySet())
+if (keys.size() == 0) {
+	println "No values for $schema_property_display property"
+	return
+}
+keys = keys.sort()
+mFactory = DoubleFactory2D.dense
+matrix = mFactory.make(keys.size(), selection.size())
+
+if (debug) println "KEYS=$keys"
+
+
+
+def title = "${selection}\n${unit_ursql}"
+title += " ${schema_property_display} frequencies"
+
+println "Index de la propriété $schema_property_display des schemas $schema_ursql de ${selection}"
+println "$schema_property_display\t"+selection.join("\t")
+
+keys.eachWithIndex { prop_val, i ->
+	String line = ""
+	if (prop_val.size() > 0) {
+		line += prop_val
+	} else {
+		line += "N/A"
+	}
+
+	int min = 0;
+	allresults.keySet().eachWithIndex { c, j ->
+		def freq = allresults[c][prop_val]
+		if (freq == null) freq = 0
+
+		matrix.set(i, j, freq)
+		line += "\t"+freq
+		if (min < freq) min = freq
+	}
+	if (min >= output_fmin)
+		println "$line"
+}
+props = keys
+
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasProgressionMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasProgressionMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasProgressionMacro.groovy	(revision 3653)
@@ -0,0 +1,255 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.exploit
+
+import groovy.transform.Field
+
+import org.jfree.chart.JFreeChart
+import org.jfree.chart.editor.ChartEditor
+import org.kohsuke.args4j.*
+import org.txm.Toolbox
+import org.txm.annotation.urs.*
+import org.txm.chartsengine.core.preferences.ChartsEnginePreferences
+import org.txm.chartsengine.r.core.RChartsEngine
+import org.txm.macro.urs.AnalecUtils
+import org.txm.progression.core.chartsengine.jfreechart.themes.highcharts.renderers.ProgressionItemSelectionRenderer
+import org.txm.progression.core.functions.Progression
+import org.txm.rcp.Application
+import org.txm.rcp.IImageKeys
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+import org.txm.chartsengine.rcp.*;
+import visuAnalec.elements.*
+
+def scriptName = this.class.getSimpleName()
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="sep", usage="Schemas and units selection part", widget="Separator", required=false, def="Selection")
+String sep
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=true, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+		int maximum_schema_size
+@Field @Option(name="schema_property_display", usage="PROP", widget="String", required=true, def="REF")
+		String schema_property_display
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="")
+		String unit_ursql
+@Field @Option(name="position_in_schema", usage="Unit distance in schema (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int position_in_schema
+@Field @Option(name="cql_limit", usage="CQL to build structure limits", widget="Query", required=false, def="")
+		cql_limit
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+@Field @Option(name="position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int position_in_matches
+@Field @Option(name="sep2", usage="Progression command parameters", widget="Separator", required=false, def="Progression")
+		String sep2
+@Field @Option(name="struct_name", usage="Structure to display", widget="String", required=true, def="div")
+		String struct_name
+@Field @Option(name="struct_prop", usage="Structure property to display", widget="String", required=true, def="n")
+		String struct_prop
+@Field @Option(name="line_width", usage="line width", widget="Integer", required=true, def="1")
+		int line_width = 1
+@Field @Option(name="cummulative", usage="bande width", widget="Boolean", required=true, def="true")
+		Boolean cummulative = true
+@Field @Option(name="bande_width", usage="bande width", widget="Float", required=true, def="0.02f")
+		float bande_width = 0.02f
+//@Field @Option(name="show_lines", usage="Show progression lines", widget="Boolean", required=true, def="true")
+//		Boolean show_lines
+@Field @Option(name="show_title", usage="Show progression title", widget="Boolean", required=true, def="true")
+		Boolean show_title
+@Field @Option(name="show_legend", usage="Show progression legend", widget="Boolean", required=true, def="true")
+		Boolean show_legend
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+if (!ParametersDialog.open(this)) return
+	if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+def queries = []
+def queryResults = []
+def informations = []
+def styles = []
+for (def corpus : selection) {
+
+	def cql_limit_matches = null;
+	if (cql_limit != null && !cql_limit.getQueryString().equals("\"\"")) {
+		def limitssubcorpus = corpus.createSubcorpus(cql_limit, corpus.getName().toUpperCase())
+		cql_limit_matches = limitssubcorpus.getMatches();
+		limitssubcorpus.delete();
+	} else {
+		cql_limit_matches = corpus.getMatches()
+	}
+	
+	def word = corpus.getWordProperty()
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+
+	def errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)
+	if (errors.size() > 0) {
+		println "** The $schema_ursql schema URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+	
+	if (schema_property_display.length() > 0) {
+		errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, AnalecUtils.getFilterParameters(schema_ursql)[0], schema_property_display).size()
+		if (errors > 0) {
+			println "Error: some Schema types don't contain the $schema_property_display property: $errors"
+			return
+		}
+	}
+
+	def allUnits = [:]
+	def allHighlightedUnits = [:]
+	def allSchemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, strict_inclusion)
+
+	if (allSchemas.size() == 0) {
+		println "No schema match for '$schema_ursql' selection. Aborting"
+		return
+	}
+
+	allUnits = AnalecUtils.groupAllUnitesInElements(debug, allSchemas)
+	if ((unit_ursql != null && unit_ursql.length() > 0) || (cql_limit != null && !cql_limit.getQueryString().equals("\"\""))) {
+		if (debug) println "Building selection of units to highlight..."
+		allHighlightedUnits = AnalecUtils.groupAllUnitesInElements(debug, allSchemas, unit_ursql)
+	}
+
+	if (position_in_schema > 0) allHighlightedUnits = AnalecUtils.filterUniteByInclusionInSchema(debug, allSchemas, position_in_schema)
+
+	if (allUnits.size() == 0) {
+		println "No unit match for '$unit_ursql' selection. Aborting"
+		return
+	}
+
+	if (debug) println "allUnits=${allUnits.size()}"
+
+	for (Schema schema : allSchemas) {
+		//println "schema="+schema.getProps()
+		def selectedUnits = allUnits[schema]
+
+		if (selectedUnits.size() == 0) continue;
+		if (debug) println "all schema units size: "+selectedUnits.size()
+
+		selectedUnits = AnalecUtils.filterUniteByInclusion(debug, selectedUnits, corpus.getMatches(), strict_inclusion, 0)
+
+		if (selectedUnits.size() == 0) continue;
+		if (debug) println "all schema units in corpus size: "+selectedUnits.size()
+
+		def selectedAndHighlightedUnits = new HashSet() // faster to find items
+		if (allHighlightedUnits != null && allHighlightedUnits.containsKey(schema)) selectedAndHighlightedUnits.addAll(allHighlightedUnits[schema])
+
+		if (cql_limit_matches != null) {
+			if (debug) println "corpus matches: "+corpus.getMatches()
+			if (debug) println "filter cql_limit_matches=${cql_limit_matches} with "+selectedAndHighlightedUnits.size()+" units."
+			selectedAndHighlightedUnits = AnalecUtils.filterUniteByInclusion(debug, selectedAndHighlightedUnits, cql_limit_matches, strict_inclusion, position_in_matches)
+			if (debug) println "selectedAndHighlightedUnits=${selectedAndHighlightedUnits.size()}"
+		}
+
+		def query = schema.getProp(schema_property_display)
+		if (query == null) query = "<null>"
+		if (query.length() == 0) query = "<empty>"
+
+		query = new CQLQuery(query)
+
+		int[] starts = new int[selectedUnits.size()];
+		int[] ends = new int[selectedUnits.size()];
+		def unitsinformations = []
+		def unitsstyles = []
+		int n = 0;
+		for (Unite unite : selectedUnits) {
+			starts[n] = unite.getDeb()
+			ends[n] = unite.getFin()
+			unitsinformations << AnalecUtils.toString(CQI, word, unite);
+
+			if (selectedAndHighlightedUnits.contains(unite)) unitsstyles << 1.3d // bigger
+			else unitsstyles << null;
+
+			n++
+		}
+
+		def queryResult = new FakeQueryResult(corpus.getID(), corpus, query, starts, ends, null)
+
+		queries << query
+		queryResults << queryResult
+		informations << unitsinformations
+		styles << unitsstyles
+	}
+	
+	try {
+		def struct = corpus.getStructuralUnit(struct_name);
+		def struct_p = null;
+		if (struct != null) {
+			struct_p = struct.getProperty(struct_prop)
+		}
+		
+		def testSet = new HashSet(queries)
+		if (testSet.size() != queries.size()) {
+			println "Warning: can't draw Progression with duplicate names: $queries"
+			continue
+		}
+		Progression progression = new Progression(corpus);
+		progression.setParameters(queries,
+				struct, struct_p,	".*",
+				cummulative, line_width, false, bande_width)
+	
+		progression.setQueryResults(queryResults); // new
+		progression.setParameter(ChartsEnginePreferences.SHOW_LEGEND, show_legend);
+		progression.setParameter(ChartsEnginePreferences.SHOW_TITLE, show_title);
+		
+		progression.compute()
+		if (!progression.stepStructuralUnits() || monitor.isCanceled())	return
+			monitor.worked(20)
+		if (!progression.stepFinalize() || monitor.isCanceled()) return
+			monitor.worked(20)
+	
+		monitor.syncExec(new Runnable() {
+					@Override
+					public void run() {
+						try {
+							//def charteditorpart = org.txm.chartsengine.rcp.SWTChartsComponentsProvider.openEditor(Application.swtComponentProvider.createProgressionChartEditorPart(IImageKeys.getImage(IImageKeys.ACTION_PROGRESSION), progression, progression.isMonochrome(), progression.isMonostyle(), progression.isDoCumulative()))
+							def charteditorpart = org.txm.chartsengine.rcp.editors.ChartEditor.openEditor(progression);
+							JFreeChart chart = charteditorpart.getChart()
+							def plot = chart.getXYPlot()
+	
+							ProgressionItemSelectionRenderer renderer = plot.getRenderer();
+							//renderer.setBaseItemLabelsVisible(true)
+							//renderer.setBaseLinesVisible(false)
+							//renderer.setBaseSeriesVisible(SchemasProgressionMacro.this.show_lines, true);
+							//renderer.setItemLabelsVisible(true)
+							//renderer.setLinesVisible(false)
+							renderer.setAdditionalLabelInformation(informations)
+							renderer.setAdditionalShapeScales(styles)
+							chart.getLegend().setVisible(SchemasProgressionMacro.this.show_legend)
+							chart.getTitle().setVisible(SchemasProgressionMacro.this.show_title)
+	
+						} catch(Exception e) {e.printStackTrace()}
+					}
+				})
+	} catch(Exception e) {
+		e.printStackTrace()
+		return false
+	}
+}
+
+//println ""+queries.size()+" selected schemas: "+queries
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsListMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsListMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsListMacro.groovy	(revision 3653)
@@ -0,0 +1,205 @@
+// Copyright © 2016, 2021 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.exploit
+
+import org.apache.commons.lang.StringUtils
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.Toolbox
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.concordance.core.functions.Concordance
+import org.txm.concordance.rcp.editors.ConcordanceEditor
+import org.txm.concordance.rcp.handlers.*
+import org.txm.macro.urs.AnalecUtils
+import org.txm.searchengine.cqp.AbstractCqiClient
+import org.txm.searchengine.cqp.ReferencePattern
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+import org.txm.searchengine.cqp.CQPSearchEngine
+
+import visuAnalec.donnees.Structure
+import visuAnalec.elements.*
+
+def scriptName = this.class.getSimpleName()
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=true, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+		int maximum_schema_size
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+		String unit_ursql
+@Field @Option(name="position_in_schema", usage="Unit distance in schema (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int position_in_schema
+@Field @Option(name="cql_limit", usage="CQL to build structure limits", widget="Query", required=false, def="")
+		cql_limit
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+@Field @Option(name="position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int position_in_matches
+@Field @Option(name="output_mode", usage="If selected units properties and words are shown", widget="StringArray", metaVar="FORMATED	TABULATED	COUNT	CQL	CONCORDANCE", required=true, def="FORMATED")
+		output_mode
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+
+@Field @Option(name="outputFile", usage="set outputFile to ' ' (space) to write in console", widget="CreateFile", required=false, def=" ")
+File outputFile
+
+if (!ParametersDialog.open(this)) return
+
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+if (outputFile != null) {
+	println "Outputing to $outputFile"
+	outStream = new PrintStream(outputFile)
+} else {
+	outStream = System.out
+}
+
+//corpus = corpusViewSelection
+def allResults = [:]
+for (def corpus : selection) {
+
+	def word = corpus.getWordProperty()
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+
+	def selectedUnits = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size,
+			unit_ursql, position_in_schema, cql_limit, strict_inclusion, position_in_matches);
+
+	def n = 1
+
+	allResults[corpus] = selectedUnits
+}
+
+if (output_mode == "FORMATED") {
+	for (def corpus : allResults.keySet()) {
+		def word = corpus.getWordProperty()
+		def selectedUnits = allResults[corpus]
+		println "$corpus units: "+selectedUnits.size()
+		def n = 1
+		for (def unit : selectedUnits) {
+			int[] pos = null
+			if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+			else pos = (unit.getDeb()..unit.getFin())
+			def form = StringUtils.join(CQI.cpos2Str(word.getQualifiedName(), pos), " ")
+
+			def props = unit.getProps().sort()
+			outStream << sprintf("#%4d, %d-%d, \"%s\" %s", n, unit.getDeb(), unit.getFin(), form, props)
+			outStream << "\n"
+			n++
+		}
+	}
+} else if (output_mode == "TABULATED") {
+
+	for (def corpus : allResults.keySet()) {
+		def word = corpus.getWordProperty()
+		def selectedUnits = allResults[corpus]
+		
+		println ""+selectedUnits.size()+" units in $corpus.\n"
+		
+		if (selectedUnits.size() > 0) {
+			def n = 1
+		
+			outStream << "#\tstart\tend\tform"
+			def keys = selectedUnits[0].getProps().keySet().sort()
+			keys.each { outStream << "\t"+it }
+			outStream << "\n"
+		
+			for (def unit : selectedUnits) {
+				int[] pos = null
+				if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+				else pos = (unit.getDeb()..unit.getFin())
+				def form = StringUtils.join(CQI.cpos2Str(word.getQualifiedName(), pos), " ")
+				def props = unit.getProps()
+			
+				outStream << sprintf("%d\t%d\t%d\t%s", n, unit.getDeb(), unit.getFin(), form)
+				for (def k : keys) {
+					if (props.get(k) == null) {
+						outStream << "\t"
+					} else {
+						outStream << "\t"+props.get(k)
+					}
+					
+				}
+				outStream << "\n"
+			
+				n++
+			}
+		}
+	}
+} else if (output_mode == "COUNT") {
+	for (def corpus : allResults.keySet()) {
+		def selectedUnits = allResults[corpus]
+		println "$corpus units: "+selectedUnits.size()
+	}
+} else if (output_mode == "CQL") {
+	for (def corpus : allResults.keySet()) {
+		def selectedUnits = allResults[corpus]
+		println "$corpus units: "+selectedUnits.size()
+		println AnalecUtils.getCQL(corpus.getID(), selectedUnits)
+	}
+} else if (output_mode == "CONCORDANCE") {
+
+	for (def corpus : allResults.keySet()) {
+		def word = corpus.getProperty("word")
+		def text_id = corpus.getStructuralUnit("text").getProperty("id")
+		def selectedUnits = allResults[corpus]
+		def query = ""
+		if (schema_ursql != null) query+= " $schema_ursql"
+		if (unit_ursql != null) query+= " $unit_ursql"
+		def ret  = AnalecUtils.getStartsEndsTargetsArrays(selectedUnits)
+		def starts = ret[0]
+		def ends = ret[1]
+		def targets = ret[2]
+		FakeQueryResult fqr = new FakeQueryResult("Fake", corpus, new CQLQuery(query), starts, ends, targets)
+
+		Concordance concordance = new Concordance(corpus);
+		concordance.setParameters(new CQLQuery(""), [word],[word],[word],
+		[word],[word],[word],
+		new ReferencePattern(text_id), new ReferencePattern(text_id), 7, 10)
+		concordance.setQueryResult(fqr)
+
+		if (monitor == null) {
+			println "Error: cannot open concordance editor: null monitor"
+			return
+		}
+		monitor.syncExec(new Runnable() {
+					public void run() {
+						try {
+							concordance.compute(); // skip the CQI.query step
+
+							ConcordanceEditor editor = ComputeConcordance.openEditor(concordance);
+
+						} catch(Throwable error) {
+							println "Error: "+error;
+							error.printStackTrace();
+						}
+					}
+				});
+	}
+}
+
+return allResults
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasCoverageMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasCoverageMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasCoverageMacro.groovy	(revision 3653)
@@ -0,0 +1,205 @@
+// Copyright © 2019 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.exploit
+
+import groovy.transform.Field
+
+import org.jfree.chart.JFreeChart
+import org.jfree.chart.editor.ChartEditor
+import org.kohsuke.args4j.*
+import org.txm.Toolbox
+import org.txm.annotation.urs.*
+import org.txm.chartsengine.core.preferences.ChartsEnginePreferences
+import org.txm.chartsengine.r.core.RChartsEngine
+import org.txm.macro.urs.AnalecUtils
+import org.txm.progression.core.chartsengine.jfreechart.themes.highcharts.renderers.ProgressionItemSelectionRenderer
+import org.txm.progression.core.functions.Progression
+import org.txm.rcp.Application
+import org.txm.rcp.IImageKeys
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+import org.txm.chartsengine.rcp.*;
+import visuAnalec.elements.*
+
+def scriptName = this.class.getSimpleName()
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=true, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="schema_property_display", usage="PROP", widget="String", required=true, def="REF")
+		String schema_property_display
+		
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="")
+		String unit_ursql
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+
+@Field @Option(name="structure_properties", usage="name_prpperty,name2_property2,name3_property", widget="String", required=true, def="div_n,p_n")
+		String structure_properties
+@Field @Option(name="write_properties_values", usage="name_prpperty,name2_property2,name3_property", widget="Boolean", required=true, def="false")
+		Boolean write_properties_values
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+if (!ParametersDialog.open(this)) return
+
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+if (structure_properties.length() == 0) return;
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+for (def corpus : selection) {
+
+	def properties = [corpus.getStructuralUnit("text").getProperty("id")]
+	
+	// build structural unit properties list from the "structure_properties" parameter
+	for (def name : structure_properties.split(",")) {
+		name = name.trim()
+		String[] split = name.split("_", 2);
+		if (split.length == 2) {
+			def su = corpus.getStructuralUnit(split[0])
+			if (su == null) {
+				println "No Structure for name=$name"
+			} else {
+				def p = su.getProperty(split[1])
+				if (p == null) {
+					println "No Structure property for name=$name"
+				} else {
+					properties << p
+				}
+			}
+		} else {
+			println "Wrong structural unit name format: $name"
+		}
+	}
+	def cql_limit_matches = corpus.getMatches()
+	
+	def word = corpus.getWordProperty()
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+	AnalecUtils.defineProperty(Schema.class, analecCorpus, schema_ursql, "LOCALISATION")
+	URSCorpora.getVue(corpus).initVueParDefaut()
+
+	def errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)
+	if (errors.size() > 0) {
+		println "** The $schema_ursql schema URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+	
+	errors = AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, unit_ursql)
+	if (errors.size() > 0) {
+		println "** The $unit_ursql unit URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+	
+	if (schema_property_display.length() > 0) {
+		errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, AnalecUtils.getFilterParameters(schema_ursql)[0], schema_property_display).size()
+		if (errors > 0) {
+			println "Error: some Schema types don't contain the $schema_property_display property: $errors"
+			return
+		}
+	}
+
+	def allUnits = [:]
+	def allHighlightedUnits = [:]
+	def allSchemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, 0, 99999999, strict_inclusion)
+
+	if (allSchemas.size() == 0) {
+		println "No schema match for '$schema_ursql' selection. Aborting"
+		return
+	}
+
+	if (debug) println "Building selection of units to highlight..."
+	allHighlightedUnits = AnalecUtils.groupAllUnitesInElements(debug, allSchemas, unit_ursql)
+
+	if (allHighlightedUnits.size() == 0) {
+		println "No schema&unit match for '$schema_ursql' and '$unit_ursql' selection. Aborting"
+		return
+	}
+	if (debug) println "allHighlightedUnits=${allHighlightedUnits.size()}"
+
+	def selectedSchemas = []
+	for (Schema schema : allSchemas) {
+		if (debug) println "	schema="+schema.getProps()
+		def selectedUnits = allHighlightedUnits[schema]
+
+		if (selectedUnits.size() == 0) continue;
+		selectedUnits = AnalecUtils.filterUniteByInclusion(debug, selectedUnits, corpus.getMatches(), strict_inclusion, 0)
+
+		if (selectedUnits.size() == 0) continue;
+
+		if (selectedUnits.size() < minimum_schema_size) {
+			schema.getProps()["LOCALISATION"] = "N/A"
+			if (debug) println schema.getProp(schema_property_display)+" -> N/A"
+			continue; // no need to go further, process next selected eleemnt of corpora view
+		}
+		selectedSchemas << schema
+	}
+	
+	println "annotating ${selectedSchemas.size()} schemas..." 
+	for (Schema schema : selectedSchemas) {
+		if (debug) println "	schema="+schema.getProps()
+		def selectedUnits = allHighlightedUnits[schema]
+
+		if (selectedUnits.size() == 0) continue;
+		selectedUnits = AnalecUtils.filterUniteByInclusion(debug, selectedUnits, corpus.getMatches(), strict_inclusion, 0)
+
+		if (selectedUnits.size() == 0) continue;
+
+		if (selectedUnits.size() < minimum_schema_size) {
+			schema.getProps()["LOCALISATION"] = "N/A"
+			if (debug) println schema.getProp(schema_property_display)+" -> N/A"
+			continue; // no need to go further, process next selected eleemnt of corpora view
+		}
+
+
+		if (debug) println "		selectedUnits=${selectedUnits.size()}"
+
+		// get all positions for the selected units
+		def positions = new TreeSet()
+		for (def unit : selectedUnits) {
+			positions.addAll(unit.getDeb()..unit.getFin())
+		}
+		int[] positions_array = positions
+		if (debug) println "		positions=${positions.size()}"
+		
+		// test each property indexes
+		for (def property : properties) {
+			if (debug) println "		testing $property..."
+			def idx = CQI.cpos2Struc(property.getQualifiedName(), positions_array)
+			def hash = new HashSet()
+			hash.addAll(idx)
+			if (debug) println "		hash=$hash"
+			if (hash.size() == 1) { // the units are only in ONE structure
+				int[] struct = hash
+				def ref = CQI.struc2Str(property.getQualifiedName(), struct)[0]
+				if (debug) println schema.getProp(schema_property_display)+" (${selectedUnits.size} units) -> "+property.getFullName()+" "+ref
+				if (write_properties_values) {
+					schema.getProps()["LOCALISATION"] = property.getFullName()+" "+ref
+				} else {
+					schema.getProps()["LOCALISATION"] = property.getFullName()
+				}
+			} 
+		}
+	}
+}
+
+//println ""+queries.size()+" selected schemas: "+queries
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasListMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasListMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasListMacro.groovy	(revision 3653)
@@ -0,0 +1,145 @@
+// Copyright © 2019 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.exploit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import visuAnalec.elements.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.macro.urs.AnalecUtils
+import org.txm.Toolbox
+import org.txm.rcp.commands.*
+import org.apache.commons.lang.StringUtils
+import org.txm.searchengine.cqp.CQPSearchEngine
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=true, def="CHAINE")
+String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="minimal schema size", widget="Integer", required=true, def="3")
+int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+int maximum_schema_size
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+String unit_ursql
+@Field @Option(name="cql_limit", usage="CQL to build structure limits", widget="Query", required=false, def="")
+cql_limit
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+boolean strict_inclusion
+@Field @Option(name="position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+int position_in_matches
+@Field @Option(name="word_property", usage="", widget="StringArray", metaVar="word	lemma	frlemma	frolemma	#forme#	id", required=false, def="word")
+String word_property
+@Field @Option(name="separator", usage="", widget="String", required=true, def=", ")
+String separator
+@Field @Option(name="buildCQL", usage="générer la requête des unités", widget="Boolean", required=true, def='false')
+def buildCQL
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+debug
+
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+for (def corpus : selection) {
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+	
+	def errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)
+	if (errors.size() > 0) {
+		println "** The $schema_ursql schema URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+	
+	errors = AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, unit_ursql)
+	if (errors.size() > 0) {
+		println "** $unit_ursql unit URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+	
+	def CQI = CQPSearchEngine.getCqiClient()
+	
+	def word_prop = null
+	if (buildCQL) {
+		word_prop = corpus.getProperty("id")
+	} else {
+		word_prop = corpus.getProperty(word_property)
+	}
+	
+	def schemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, strict_inclusion);
+	schemas.sort() {it.getProps()}
+	
+	println "$corpus schemas (${schemas.size()}): "
+	for (def schema : schemas) {
+	
+		def allUnites = schema.getUnitesSousjacentesNonTriees()
+		def units = AnalecUtils.filterElements(debug, allUnites, unit_ursql)
+		units = AnalecUtils.filterUniteByInclusion(debug, allUnites, corpus.getMatches(), false, 0)
+
+		if (cql_limit != null) {
+			def cql_limit_matches = null;
+			if (cql_limit != null && !cql_limit.getQueryString().equals("\"\"")) {
+				def limitssubcorpus = corpus.createSubcorpus(cql_limit, corpus.getName().toUpperCase())
+				cql_limit_matches = limitssubcorpus.getMatches();
+				limitssubcorpus.delete();
+			} else {
+				cql_limit_matches = corpus.getMatches()
+			}
+			units = AnalecUtils.filterUniteByInclusion(debug, units, cql_limit_matches, strict_inclusion, position_in_matches)
+		}
+		
+		print schema.getProps().toString()+ " ("+units.size()+"/"+allUnites.size()+"): "
+		def first = true
+		def values = new HashSet()
+		for (def unit : units) {
+	
+			String forme =  null;
+	
+			if (buildCQL) {
+				int[] pos = null
+				if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+				else pos = (unit.getDeb()..unit.getFin())
+				def first2= true
+				q = ""
+				pos.each {
+					if (first2) { first2 = false } else { q = q+" " }
+					int[] pos2 = [it]
+					q = q+"["+word_prop+"=\""+CQI.cpos2Str(word_prop.getQualifiedName(), pos2)[0]+"\"]"
+				}
+				if (first) { first = false } else { print "|" }
+				print "("+q+")"
+			} else {
+				if (word_prop == null) { // word_property is the analec unit property to use
+					forme = unit.getProp(word_property)
+				} else {
+					int[] pos = null
+					if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+					else pos = (unit.getDeb()..unit.getFin())
+					
+					forme = StringUtils.join(CQI.cpos2Str(word_prop.getQualifiedName(), pos), " ") // ids is enough
+				}
+	
+				values << forme
+			}
+		}
+		
+		println values.join(separator)
+	}
+}
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsInterdistanceMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsInterdistanceMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsInterdistanceMacro.groovy	(revision 3653)
@@ -0,0 +1,118 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.exploit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.*
+import org.txm.macro.urs.AnalecUtils
+import visuAnalec.elements.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+import org.apache.commons.lang.StringUtils;
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=REGEX", widget="String", required=true, def="CHAINE")
+String schema_ursql
+
+@Field @Option(name="minimum_schema_size", usage="minimal schema size", widget="Integer", required=true, def="3")
+int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+int maximum_schema_size
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=REGEX", widget="String", required=false, def="MENTION")
+String unit_ursql
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+boolean strict_inclusion
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+debug
+
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+for (def corpus : selection) {
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+	
+	def errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)
+	if (errors.size() > 0) {
+		println "** The $schema_ursql schema URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+	
+	errors=AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, unit_ursql)
+	if (errors.size() > 0) {
+		println "** $unit_ursql unit URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+	
+	def schemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, strict_inclusion);
+	def distances = [];
+	def nDistances = 0
+	def cadences = [];
+	for (def schema : schemas) {
+		
+		def allUnites = schema.getUnitesSousjacentesNonTriees()
+	
+		def units = AnalecUtils.filterElements(debug, allUnites, unit_ursql)
+		
+		Collections.sort(units)
+			
+		for (int i = 0 ; i < units.size() ; i++) {
+			int d1 = 9999999;
+			int d2 = 9999999;
+			
+			
+			if (i < units.size()-1) d1 = units[i+1].getDeb() - units[i].getFin() - 1;
+			if (d1 < 0) {
+				//println "D1 "+units[i+1].getDeb()+" - "+units[i].getFin()+" = "+d1
+				d1 = 0; // the first unit pass the next one ?
+			}
+			if (i > 0) {
+				d2 = units[i].getDeb() - units[i-1].getFin() - 1;
+				distances << d2
+				nDistances++
+			}
+			if (d2 < 0) {
+				//println "D2 "+units[i].getDeb()+" - "+units[i-1].getFin()+" = "+d2
+				d2 = 0; // the first unit pass the next one ?
+			}
+			
+			if (d1 < d2) cadences << d1 else cadences << d2
+		}
+	}
+	distances = distances.sort()
+	cadences = cadences.sort()
+	
+	int distances_total = distances.sum()
+	int cadences_total = cadences.sum()
+	coef = (distances_total / nDistances)
+	cadence = (cadences_total / nDistances)
+	
+	println "$corpus distances:"
+	if (debug > 0) println "distances $distances"
+	println "distance moyenne : $distances_total / ${distances.size()} = $coef"
+	println "distance medianne : "+distances[(int)(distances.size() / 2)]
+	println "distance quartils : "+distances[0]+" "+distances[(int)(distances.size() / 4)] + " "+distances[(int)(distances.size() / 2)]+" "+distances[(int)(3*distances.size() / 4)]+" "+distances[(int)(distances.size() -1)]
+	if (debug > 0) println "cadences $cadences"
+	println "cadence moyenne : $cadences_total / ${cadences.size()} = $cadence"
+	println "cadence medianne : "+cadences[(int)(cadences.size() / 2)]
+	println "cadence quartils : "+cadences[0]+" "+cadences[(int)(cadences.size() / 4)] + " "+cadences[(int)(cadences.size() / 2)]+" "+cadences[(int)(3*cadences.size() / 4)]+" "+cadences[(int)(cadences.size() -1)]
+	
+	//return ["result":coef, "result2":cadence, "data":["distances":distances, "nDistances":nDistances, "cadences":cadences]]
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsSummaryMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsSummaryMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/UnitsSummaryMacro.groovy	(revision 3653)
@@ -0,0 +1,103 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.exploit
+
+import org.apache.commons.lang.StringUtils
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.Toolbox
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.macro.urs.AnalecUtils
+import org.txm.searchengine.cqp.AbstractCqiClient
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+
+import visuAnalec.donnees.Structure
+import visuAnalec.elements.*
+
+def scriptName = this.class.getSimpleName()
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=true, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+		int maximum_schema_size
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+		String unit_ursql
+@Field @Option(name="position_in_schema", usage="Unit distance in schema (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int position_in_schema
+@Field @Option(name="cql_limit", usage="CQL to build structure limits", widget="Query", required=false, def="")
+		cql_limit
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=false, def="true")
+		boolean strict_inclusion
+@Field @Option(name="position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int position_in_matches
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+if (!ParametersDialog.open(this)) return
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+def allresults = new LinkedHashMap()
+def props = new HashSet()
+for (def corpus : selection) {
+
+	def word = corpus.getWordProperty()
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+	for (def type : analecCorpus.getStructure().getUnites())
+		props.addAll(analecCorpus.getStructure().getUniteProperties(type));
+
+	def selectedUnits = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, 
+	unit_ursql, position_in_schema, cql_limit, strict_inclusion, position_in_matches);
+
+	if (debug) println "found ${selectedUnits.size()} units in $corpus}"
+	allresults[corpus] = selectedUnits;
+}
+
+// tabulate summary
+def keys = allresults.keySet().sort();
+println "Statistiques des unités de "+corpusViewSelections.join(",")
+println "\t"+keys.join("\t")
+print "Units"
+for (def k : keys) {
+	print "\t"+allresults[k].size();
+}
+println ""
+for (def p : props) {
+	print "$p"
+	for (def k : keys) {
+		def propsvalues = new HashSet()
+		for (def u : allresults[k]) {
+			propsvalues.add(u.getProp(p))
+		}
+		print "\t"+propsvalues.size();
+		def values = []
+		values.addAll(propsvalues)
+		values = values.sort()
+		if (debug) print "\t\""+values.join("\", \"")+"\"";
+	}
+	println ""
+}
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/ConcordanceToUnitsMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/ConcordanceToUnitsMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/ConcordanceToUnitsMacro.groovy	(revision 3653)
@@ -0,0 +1,139 @@
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.edit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.rcp.editors.concordances.*
+import org.txm.searchengine.cqp.corpus.CQPCorpus
+import org.txm.searchengine.cqp.corpus.MainCorpus
+import org.txm.functions.concordances.*
+import org.txm.annotation.urs.*
+import org.txm.concordance.core.functions.Concordance
+import org.txm.concordance.rcp.editors.ConcordanceEditor
+import visuAnalec.elements.Unite
+import visuAnalec.vue.Vue
+
+// BEGINNING OF PARAMETERS
+
+@Field @Option(name="unit_type", usage="The unit type to create", widget="String", required=true, def="MENTION")
+def unit_type
+
+@Field @Option(name="move_start", usage="move the start position", widget="Integer", required=true, def="0")
+def move_start
+
+@Field @Option(name="move_end", usage="move the end position", widget="Integer", required=true, def="0")
+def move_end
+
+@Field @Option(name="create_only_if_new", usage="Create the unit if not already annotated", widget="Boolean", required=true, def="true")
+def create_only_if_new
+
+@Field @Option(name="property_name", usage="prop", widget="String", required=true, def="REF")
+def property_name
+
+@Field @Option(name="property_value", usage="default value", widget="String", required=true, def="NAME")
+def property_value
+
+// END OF PARAMETERS
+
+// get a Concordance from 1) current Concordance editor or 2) CorporaView selection
+Concordance concordance
+if (editor instanceof ConcordanceEditor) {
+	concordance = editor.getConcordance()
+} else if (corpusViewSelection instanceof Concordance) {
+	concordance = corpusViewSelection
+} else {
+	println "You must select a concordance or open a concordance result to run this macro."
+	return false
+}
+
+if (concordance == null) {
+	println "You must compute a concordance before."
+	return
+}
+
+// check the analec corpus is ready
+CQPCorpus corpus = concordance.getCorpus().getMainCorpus();
+String name = corpus.getID()
+if (!URSCorpora.isAnnotationStructureReady(corpus)) {
+	println "Annotation structure is not ready."
+	return
+}
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) {
+	println "User canceled parameters"
+	return;
+}
+
+// check the corpus structure has the unit_type provided
+def analecCorpus = URSCorpora.getCorpus(corpus)
+if (!analecCorpus.getStructure().getUnites().contains(unit_type)) {
+	//println "The corpus structure does not contains unit with type=$unit_type"
+	//return;
+	analecCorpus.getStructure().ajouterType(Unite.class, unit_type);
+}
+
+if (!analecCorpus.getStructure().getNomsProps(Unite.class, unit_type).contains(property_name)) {
+	//println "The corpus structure does not contains unit with type=$unit_type"
+	//return;
+	analecCorpus.getStructure().ajouterProp(Unite.class, unit_type, property_name)
+}
+
+if (!analecCorpus.getStructure().getValeursProp(Unite.class, unit_type, property_name).contains(property_value)) {
+	//println "The corpus structure does not contains unit with type=$unit_type"
+	//return;
+	analecCorpus.getStructure().ajouterVal(Unite.class, unit_type, property_name, property_value)
+}
+
+Vue vue = URSCorpora.getVue(corpus)
+if (!vue.getTypesAVoir(Unite.class).contains(unit_type)) {
+	vue.ajouterType(Unite.class, unit_type)
+}
+if (!vue.getNomsChamps(Unite.class, unit_type).contains(property_name)) {
+	vue.ajouterProp(Unite.class, unit_type, property_name)
+}
+
+// browse lines and check
+def units = analecCorpus.getUnites(unit_type)
+def lines = concordance.getLines()
+
+println "Annotating ${lines.size()} lines."
+int n = 0
+for (int iLine = 0 ; iLine < lines.size() ; iLine++) {
+	int iUnit = 0
+	def line = lines[iLine]
+	def m = line.getMatch()
+	def start = m.getStart()+move_start
+	def end = m.getEnd()+move_end
+	
+	def do_create = true
+	if (create_only_if_new && iUnit < units.size()) { // test only if create_only_if_new == true
+		def unit = null
+		//TODO don't iterates over all units
+		while (iUnit < units.size() ) { //&& units[iUnit].getDeb() < start) {
+			if (iUnit < units.size()) {
+				unit = units[iUnit++]
+				if (unit.getDeb() == start && unit.getFin() == end) { // skip and print the line
+					println("skiping concordance line '"+line.keywordToString()+"' at "+line.getViewRef().toString()+" ("+unit.getDeb()+ ", "+unit.getFin()+")")
+					do_create = false
+					continue
+				}
+			}
+		}
+	}
+	if (do_create) {
+		n++
+		def props = [:]
+		props[property_name] = property_value
+		Unite u = analecCorpus.addUniteSaisie(unit_type, start, end, props)
+		//	println "$props -> "+u.getProps()
+	}
+}
+if (property_name != null) {
+	println "$n $unit_type created with $property_name='$property_value'."
+} else {
+	println "$n $unit_type created."
+}
+
+if (n > 0) corpus.setIsModified(true);
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/CloneUnitPropertyMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/CloneUnitPropertyMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/CloneUnitPropertyMacro.groovy	(revision 3653)
@@ -0,0 +1,189 @@
+package org.txm.macro.urs.edit
+
+// Copyright © 2021 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author sheiden
+
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.*
+import org.txm.*
+import org.txm.rcpapplication.views.*
+import org.txm.macro.cqp.*
+import org.txm.annotation.urs.URSCorpora
+import org.txm.macro.urs.AnalecUtils
+import visuAnalec.elements.Unite
+
+
+// BEGINNING OF PARAMETERS
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	scriptName = this.class.getSimpleName()
+	println "** $scriptName: please select a corpus in the Corpus view or provide a corpus name (current selection is $corpusViewSelection). Aborting."
+	return false
+}
+// Declare each parameter here
+// (available widget types: Query, File, Folder, String, Text, Boolean, Integer, Float and Date)
+
+@Field @Option(name="unit_type", usage="Unit Type", widget="String", required=false, def="Biblical Reference")
+def unit_type
+
+@Field @Option(name="unit_ursql", usage="TYPE or TYPE@PROP or TYPE@PROP=<regex>", widget="String", required=false, def="Biblical Reference")
+def unit_ursql
+
+@Field @Option(name="propertyToClone", usage="name of the property to clone", widget="String", required=true, def="")
+def propertyToClone
+
+@Field @Option(name="newProperty", usage="name of the new property", widget="String", required=true, def="")
+def newProperty
+
+@Field @Option(name="debug", usage="Show debug information", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=false, def="OFF")
+def debug
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return false
+
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+// check availability of the corpus
+
+CQI = CQPSearchEngine.getCqiClient()
+
+scriptName = this.class.getSimpleName()
+
+corpus = corpusViewSelection
+corpusName = corpus.getName()
+
+// check availability of every information needed in the corpus
+
+if (!URSCorpora.isAnnotationStructureReady(corpus)) {
+	println "** URS Annotation Structure of "+corpusName+" is not ready. Aborting."
+	return false
+}
+
+analecCorpus = URSCorpora.getCorpus(corpus)
+
+if (analecCorpus == null) {
+	println "** no URS Annotations for "+corpusName+" corpus. Aborting."
+	return false
+}
+
+// select Units
+
+selectedUnits = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, null, null, null, unit_ursql, 0, null, false, 0)
+
+nUnits = selectedUnits.size()
+
+if (nUnits == 0) {
+	println "No units selected, no property cloned."
+	return
+}
+
+// check availability of every information needed in the corpus
+
+corpus_units = analecCorpus.getUnites(unit_type)
+
+if (corpus_units == null) {
+	println "** no URS Annotations '"+unit_type+"' corpus unit type in corpus "+corpusName+". Aborting."
+	return false
+}
+
+struct = analecCorpus.getStructure()
+
+if (struct == null) {
+	println "** no URS Annotations structure in corpus "+corpusName+". Aborting."
+	return false
+}
+
+struct_units = struct.getUnites()
+
+if (struct_units == null) {
+	println "** no URS Annotations structure units in corpus "+corpusName+". Aborting."
+	return false
+}
+
+if (debug > 0) {
+
+println "unit types: "+struct_units
+println unit_type+" properties: "+struct.getNomsProps(Unite.class, unit_type)
+
+}
+
+// check Unit type
+props = struct.getNomsProps(Unite.class, unit_type)
+
+// if necessary, add new property to unit type
+
+if ((props == null) || (!props.contains(newProperty))) {
+	struct.ajouterProp(Unite.class, unit_type, newProperty)
+}
+
+// verify that the property is added to unit_type unit type
+props = struct.getNomsProps(Unite.class, unit_type)
+
+if (props == null) {
+	println "** impossible to add new property '"+newProperty+"' to '"+unit_type+"' unit type in corpus "+corpusName+". Aborting."
+	return false
+}
+	
+if (!props.contains(newProperty)) {
+	println "** impossible to add new property '"+newProperty+"' to '"+unit_type+"' unit type in corpus "+corpusName+". Aborting."
+	return false
+}
+
+// check Vue
+vue = URSCorpora.getVue(corpus)
+
+if (vue == null) {
+	println "** no URS 'vue' for corpus "+corpusName+". Aborting."
+	return false
+}
+
+vue_units = vue.getTypesUnitesAVoir()
+
+if (vue_units == null) {
+	println "** no URS Annotations vue units in corpus "+corpusName+". Aborting."
+	return false
+}
+
+props = vue.getNomsChamps(Unite.class, unit_type)
+
+if (debug > 0) {
+	println "vue unit types: "+vue_units
+	println unit_type+" vue fields: "+props
+}
+
+// if necessary, add the new property to unit_type unit type in vue
+
+if ((props == null) || (!props.contains(newProperty))) {
+	vue.ajouterProp(Unite.class, unit_type, newProperty)
+}
+
+// verify that the property is added to unit_type unit type in vue
+props = vue.getNomsChamps(Unite.class, unit_type)
+
+if (props == null) {
+	println "** impossible to add properties to '"+unit_type+"' unit type in vue of corpus "+corpusName+". Aborting."
+	return false
+}
+
+if (!props.contains(newProperty)) {
+		println "** impossible to add property '"+newProperty+"' to '"+unit_type+"' unit type in vue of corpus "+corpusName+". Aborting."
+		return false
+}
+
+selectedUnits.each { unit ->
+	def val = unit.getProp(propertyToClone)
+   	vue.setValeurChamp(unit, newProperty, val)
+}
+
+println nUnits+" properties cloned (but not saved)."
+
+corpus.setIsModified(true)
+
+return true
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/UnitsDeleteMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/UnitsDeleteMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/UnitsDeleteMacro.groovy	(revision 3653)
@@ -0,0 +1,91 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.edit
+
+import org.apache.commons.lang.StringUtils
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.Toolbox
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.macro.urs.AnalecUtils
+import org.txm.searchengine.cqp.AbstractCqiClient
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+
+import visuAnalec.donnees.Corpus
+import visuAnalec.donnees.Structure
+import visuAnalec.elements.*
+import visuAnalec.vue.Vue
+
+def scriptName = this.class.getSimpleName()
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=true, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+		int maximum_schema_size
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+		String unit_ursql
+@Field @Option(name="position_in_schema", usage="Unit distance in schema (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int position_in_schema
+@Field @Option(name="cql_limit", usage="CQL to build structure limits", widget="Query", required=true, def="<div> [] expand to div")
+		cql_limit
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+@Field @Option(name="position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int position_in_matches
+
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+if (!ParametersDialog.open(this)) return
+	if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+//corpus = corpusViewSelection
+def allResults = [:]
+def errors = new HashSet()
+for (def corpus : selection) {
+	println "Deleting '$unit_ursql' units of '$schema_ursql' schemas in the '$corpus' corpus..."
+
+	def word = corpus.getWordProperty()
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+	Vue analecView = URSCorpora.getVue(corpus)
+	Structure structure = analecCorpus.getStructure()
+
+	def selectedUnits = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size,
+			unit_ursql, position_in_schema, cql_limit, strict_inclusion, position_in_matches);
+		
+	def n = 0
+	def nerrors = 0
+	for (Unite unit : selectedUnits) {
+		analecCorpus.supUnite(unit);
+		n++
+	}
+	
+	corpus.getMainCorpus().setIsModified(true)
+	allResults[corpus] = selectedUnits
+	allResults["n"] = n
+	println " $n units deleted"
+}
+
+return allResults
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/ResetAllAnnotationsMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/ResetAllAnnotationsMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/ResetAllAnnotationsMacro.groovy	(revision 3653)
@@ -0,0 +1,63 @@
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.edit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.elements.*
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+def corpus = corpusViewSelection
+if (!URSCorpora.isAnnotationStructureReady(corpus)) {
+	println "** URS Annotation Structure of "+corpusViewSelection+" is not ready. Aborting."
+	return
+}
+
+@Field @Option(name="CONFIRMATION", usage="select to confirm the annotations reset", widget="Boolean", required=false, def="false")
+def CONFIRMATION
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return;
+
+if (!CONFIRMATION) {
+	println "Aborting: CONFIRMATION was no checked."
+	return;
+}
+
+
+def analecCorpus = URSCorpora.getCorpus(corpus);
+def structure = analecCorpus.getStructure()
+
+Class[] classes = [Unite.class, Relation.class, Schema.class]
+println "Removing unites..."
+for (String type : structure.getTypes(Unite.class)) {
+	for (Unite unite : analecCorpus.getUnites(type).toArray(new Unite[0])) {
+		analecCorpus.supUnite(unite)
+	}
+//	fireMessage(new StructureEvent(analecCorpus, TypeModifStructure.SUPPR_TYPE, Unite.class, type));
+}
+
+println "Removing relations..."
+for (String type : structure.getTypes(Relation.class)) {
+	for (Relation relation : analecCorpus.getRelations(type).toArray(new Relation[0])) {
+		analecCorpus.supRelation(relation)
+	}
+//	fireMessage(new StructureEvent(analecCorpus, TypeModifStructure.SUPPR_TYPE, Relation.class, type));
+}
+
+println "Removing schemas..."
+for (String type : structure.getTypes(Schema.class)) {
+	for (Schema schema : analecCorpus.getSchemas(type).toArray(new Schema[0])) {
+		analecCorpus.supSchema(schema)
+	}
+//	fireMessage(new StructureEvent(analecCorpus, TypeModifStructure.SUPPR_TYPE, Schema.class, type));
+}
+
+println "Done. Save the corpus to finish the annotations reset."
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/UnitsAnnotateMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/UnitsAnnotateMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/UnitsAnnotateMacro.groovy	(revision 3653)
@@ -0,0 +1,118 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.edit
+
+import org.apache.commons.lang.StringUtils
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.Toolbox
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.macro.urs.AnalecUtils
+import org.txm.searchengine.cqp.AbstractCqiClient
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+
+import visuAnalec.donnees.Corpus
+import visuAnalec.donnees.Structure
+import visuAnalec.elements.*
+import visuAnalec.vue.Vue
+
+def scriptName = this.class.getSimpleName()
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=true, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+		int maximum_schema_size
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+		String unit_ursql
+@Field @Option(name="position_in_schema", usage="Unit distance in schema (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int position_in_schema
+@Field @Option(name="cql_limit", usage="CQL to build structure limits", widget="Query", required=false, def="<div> [] expand to div")
+		cql_limit
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+@Field @Option(name="position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int position_in_matches
+@Field @Option(name="property_name", usage="PROP", widget="String", required=false, def="TESTPROP")
+		String property_name
+@Field @Option(name="property_value", usage="VALUE", widget="String", required=false, def="TESTVALUE")
+		String property_value
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+if (!ParametersDialog.open(this)) return
+	if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+if (property_name.length() == 0) {
+	println "property_name not set: aborting."
+}
+
+//corpus = corpusViewSelection
+def allResults = [:]
+def errors = new HashSet()
+for (def corpus : selection) {
+	println "Annotating $corpus..."
+
+	def word = corpus.getWordProperty()
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+	Vue analecView = URSCorpora.getVue(corpus)
+	def typesAVoir = analecView.getTypesAVoir(Unite.class)
+	
+	Structure structure = analecCorpus.getStructure()
+
+	AnalecUtils.defineProperty(Unite.class, analecCorpus, unit_ursql, property_name)
+
+	def selectedUnits = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size,
+			unit_ursql, position_in_schema, cql_limit, strict_inclusion, position_in_matches);
+		
+	println " "+selectedUnits.size()+" units to annotate..."
+	def n = 0
+	def nerrors = 0
+	for (Unite unit : selectedUnits) {
+		String unit_type = unit.getType()
+		// ensure the unit_type & property_name are declared in the Vue
+		if (!typesAVoir.contains(unit_type)) {
+			analecView.ajouterType(Unite.class, unit_type)
+		}
+		if (!analecView.getNomsChamps(Unite.class, unit_type).contains(property_name)) {
+			analecView.ajouterProp(Unite.class, unit_type, property_name)
+		}
+		if (!analecView.setValeurChamp(unit, property_name, property_value)) {
+			errors << ""+unit.getDeb()+"->"+unit.getFin()
+			nerrors++
+		} else {
+			n++
+		}
+	}
+	
+	corpus.getMainCorpus().setIsModified(true)
+	allResults[corpus] = selectedUnits
+	println " $n valeurs affectées à $corpus"
+	println " $nerrors erreurs lors de l'annotation de $corpus"
+}
+if (errors.size() > 0) {
+	println " Errors while annotating $property_name=$property_value"
+	println errors.join("\n")
+}
+return allResults
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/ResetViewMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/ResetViewMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/edit/ResetViewMacro.groovy	(revision 3653)
@@ -0,0 +1,64 @@
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.edit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.elements.*
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+def corpus = corpusViewSelection
+if (!URSCorpora.isAnnotationStructureReady(corpus)) {
+	println "** URS Annotation Structure of "+corpusViewSelection+" is not ready. Aborting."
+	return
+}
+
+@Field @Option(name="CONFIRMATION", usage="select to confirm the annotations reset", widget="Boolean", required=false, def="false")
+def CONFIRMATION
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return;
+
+if (!CONFIRMATION) {
+	println "Aborting: CONFIRMATION was no checked."
+	return;
+}
+
+def analecCorpus = URSCorpora.getCorpus(corpus);
+//def structure = analecCorpus.getStructure()
+def vue = URSCorpora.getVue(corpus)
+
+/*
+Class[] classes = [Unite.class, Relation.class, Schema.class]
+println "Removing unites..."
+for (String type : vue.getTypes(Unite.class)) {
+	for (Unite unite : analecCorpus.getUnites(type).toArray(new Unite[0])) {
+		analecCorpus.supUnite(unite)
+	}
+}
+
+println "Removing relations..."
+for (String type : vue.getTypes(Relation.class)) {
+	for (Relation relation : analecCorpus.getRelations(type).toArray(new Relation[0])) {
+		analecCorpus.supRelation(relation)
+	}
+}
+
+println "Removing schemas..."
+for (String type : vue.getTypes(Schema.class)) {
+	for (Schema schema : analecCorpus.getSchemas(type).toArray(new Schema[0])) {
+		analecCorpus.supSchema(schema)
+	}
+}
+*/
+
+vue.retablirVueParDefaut();
+
+println "Done. Save the corpus to finish the annotations reset."
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/AnalecUtils.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/AnalecUtils.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/AnalecUtils.groovy	(revision 3653)
@@ -0,0 +1,552 @@
+package org.txm.macro.urs
+
+import org.txm.searchengine.cqp.corpus.Property
+import org.txm.searchengine.cqp.corpus.Subcorpus
+import org.txm.searchengine.cqp.corpus.query.Match
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+
+import org.apache.commons.lang.StringUtils
+
+
+static def isPropertyDefined(Class clazz, Corpus analecCorpus, String ursql) {
+	if (ursql == null || ursql.length() == 0) return new HashSet()
+	def params = getFilterParameters(ursql)
+	def typeRegexp = params[0]
+	def propRegexp = params[1]
+	return isPropertyDefined(clazz, analecCorpus, typeRegexp, propRegexp)
+}
+
+static def isPropertyDefined(Class clazz, Corpus analecCorpus, String typeRegexp, String propRegexp) {
+	def errors = new HashSet()
+	if (propRegexp == null || propRegexp.length() == 0) return errors;
+	Structure structure = analecCorpus.getStructure();
+	for (def type : structure.getTypes(clazz)) {
+		if (!type.matches(typeRegexp)) continue; // test only types matching with typeRegexp
+
+		def props = structure.getNomsProps(clazz, type);
+		boolean contains = false;
+		for (def p : props) {
+			if (p.matches(propRegexp)) {
+				contains = true
+			}
+		}
+		if (!contains) errors << type
+	}
+
+	return errors
+}
+
+static def defineProperty(Class clazz, Corpus analecCorpus, String ursql, String newProperty) {
+	def params = getFilterParameters(ursql)
+	def typeRegexp = params[0]
+	Structure structure = analecCorpus.getStructure();
+	for (def type : structure.getTypes(clazz)) {
+		if (!type.matches(typeRegexp)) continue; // test only types matching with typeRegexp
+		def props = structure.getNomsProps(clazz, type)
+		if (!props.contains(newProperty)) {
+			structure.ajouterProp(clazz, type, newProperty)
+		}
+	}
+}
+
+static def selectSchemas(def debug, Corpus analecCorpus, String schema_ursql, Integer minimum_schema_size, Integer maximum_schema_size) {
+	if (maximum_schema_size <= 0) maximum_schema_size = Integer.MAX_VALUE;
+	if (minimum_schema_size < 0) minimum_schema_size = 0;
+	def allSchemas = []
+
+	if (schema_ursql != null && schema_ursql.length() > 0) allSchemas = AnalecUtils.findAllInCorpus(debug, analecCorpus, Schema.class, schema_ursql)
+	else allSchemas = analecCorpus.getTousSchemas()
+
+	if (debug >= 2) println "allSchemas=${allSchemas.size()}"
+	allSchemas = AnalecUtils.filterBySize(allSchemas, minimum_schema_size, maximum_schema_size);
+
+	return allSchemas
+}
+
+static def selectSchemasInCorpus(def debug, Corpus analecCorpus, org.txm.searchengine.cqp.corpus.CQPCorpus corpus,
+		String schema_ursql, Integer minimum_schema_size, Integer maximum_schema_size, boolean strictInclusion) {
+
+	if (maximum_schema_size <= 0) maximum_schema_size = Integer.MAX_VALUE;
+	if (minimum_schema_size < 0) minimum_schema_size = 0;
+
+	def allSchemas = []
+	if (schema_ursql != null && schema_ursql.length() > 0) allSchemas = AnalecUtils.findAllInCorpus(debug, analecCorpus, Schema.class, schema_ursql)
+	else allSchemas = analecCorpus.getTousSchemas()
+
+	def selectedSchemas = []
+	for (Schema schema : allSchemas) {
+		def selectedUnits = AnalecUtils.filterUniteByInclusion(debug, schema.getUnitesSousjacentes(), corpus.getMatches(), strictInclusion, 0)
+
+		if (minimum_schema_size <= selectedUnits.size() && selectedUnits.size() <= maximum_schema_size ) {
+			selectedSchemas << schema
+		}
+	}
+
+	return selectedSchemas
+}
+
+/**
+ * select units from a selection of schema. If no schema critera are given, select all units then apply units critera
+ * 
+ * @param debug
+ * @param analecCorpus
+ * @param corpus
+ * @param schema_ursql
+ * @param minimum_schema_size
+ * @param maximum_schema_size
+ * @param unit_ursql
+ * @param cql_limit
+ * @param strict_inclusion
+ * @param position
+ * @return
+ */
+static def selectUnitsInSchema(def debug, Corpus analecCorpus, org.txm.searchengine.cqp.corpus.CQPCorpus corpus,
+		String schema_ursql, Integer minimum_schema_size, Integer maximum_schema_size,
+		String unit_ursql, Integer position_in_schema, CQLQuery cql_limit, Boolean strict_inclusion, int position_in_matches) {
+	def groupedUnits = []
+	if (schema_ursql != null && schema_ursql.length() > 0) {
+		def allSchema = null;
+
+		if (schema_ursql != null && schema_ursql.length() > 0) allSchema = AnalecUtils.findAllInCorpus(debug, analecCorpus, Schema.class, schema_ursql)
+		else allSchema = analecCorpus.getTousSchemas()
+		if (debug >= 2) println "allSchema=${allSchema.size()}"
+
+		groupedUnits = AnalecUtils.groupAllUnitesInElements(debug, allSchema, unit_ursql)
+		if (debug >= 2) println "groupedUnits=${groupedUnits.size()}"
+		
+		groupedUnits = AnalecUtils.filterUniteByInclusionInSchema(debug, groupedUnits, position_in_schema)
+		if (debug >= 2) println "groupedUnits=${groupedUnits.size()}"
+
+
+	} else {
+		groupedUnits = ["all":AnalecUtils.findAllInCorpus(debug, analecCorpus, Unite.class, unit_ursql)]
+	}
+	if (debug >= 2) println "groupedUnits=${groupedUnits.size()}"
+
+	// limit units to corpus or cql_limit matches
+	def matches = null
+	if (cql_limit != null && !cql_limit.getQueryString().equals("\"\"")) {
+		Subcorpus limitssubcorpus = corpus.createSubcorpus(cql_limit, corpus.getID().toUpperCase())
+		matches = limitssubcorpus.getMatches();
+		limitssubcorpus.delete();
+	} else {
+		matches = corpus.getMatches()
+	}
+	if (debug >= 2) println "matches=${matches}"
+	def allUnits = []
+	for (def k : groupedUnits.keySet()) {
+		def selectedUnits = AnalecUtils.filterUniteByInclusion(debug, groupedUnits[k], matches, strict_inclusion, position_in_matches)
+
+		if (schema_ursql == null || schema_ursql.length() == 0 || (minimum_schema_size <= selectedUnits.size() && selectedUnits.size() <= maximum_schema_size)) {
+			allUnits.addAll(selectedUnits)
+		}
+	}
+	if (debug >= 2) println "selectedUnits=${allUnits.size()}"
+
+	Collections.sort(allUnits)
+
+	return allUnits
+}
+
+/**
+ * filter groups elements with the elements positions
+ * 
+ * 
+ * @param groups [schema:units list]
+ * @param distance 0=no selection, 1=first, 2=second, -1 last, -2 last-last
+ * @return
+ */
+static def filterUniteByInclusionInSchema(def debug, def groups, Integer distance) {
+	if (distance == 0) return groups;
+	if (distance > 0) distance = distance-1;
+	def newGroups = [:]
+	for (def k : groups.keySet()) {
+		def group = groups[k]
+		if (group.size() == 0) {
+			newGroups[k] = group;
+			continue;
+		}
+		def indexes = null
+		if (distance >= 0) {
+			indexes = 0..Math.min(distance, group.size())
+		} else {
+			indexes = Math.max(distance, -group.size())..-1
+		}
+
+		newGroups[k] = group[indexes];
+	}
+	return newGroups
+}
+
+static def getStartsEndsTargetsArrays(def selectedUnits) {
+	int[] starts = new int[selectedUnits.size()]
+	int[] ends = new int[selectedUnits.size()]
+	int n = 0;
+	for (def unite : selectedUnits) {
+		starts[n] = unite.getDeb();
+		ends[n] = unite.getFin();
+		n++
+	}
+	return [starts, ends, null]
+}
+
+static int[] toIntArray(Unite u) {
+	if (u.getDeb() > u.getFin()) // error
+		return (u.getFin()..u.getDeb()).toArray(new int[u.getDeb()-u.getFin()])
+	else
+		return (u.getDeb()..u.getFin()).toArray(new int[u.getFin()-u.getDeb()])
+}
+
+static String toString(Element e) {
+	Schema r = null;
+
+	if (e.getClass() == Unite.class)
+		return sprintf("%d-%d, %s", e.getDeb(), e.getFin(), e.getProps().sort())
+	else if (e.getClass() == Relation.class)
+		return sprintf("%s=%s -> %s", toString(e.getElt1()), toString(e.getElt2()), e.getProps().sort())
+	else if (e.getClass() == Schema.class)
+		return sprintf("%s=%d", e.getContenu().size(), e.getProps().sort())
+}
+
+static String toString(def CQI, def wordProperty, Element e) {
+	Schema r = null;
+
+	if (e.getClass() == Unite.class) {
+		def form = StringUtils.join(CQI.cpos2Str(wordProperty.getQualifiedName(), toIntArray(e)), " ")
+		return sprintf("%s %d-%d, %s", form, e.getDeb(), e.getFin(), e.getProps().sort())
+	} else if (e.getClass() == Relation.class) {
+		def form1 = StringUtils.join(CQI.cpos2Str(wordProperty.getQualifiedName(), toIntArray(e.getElt1())), " ")
+		def form2 = StringUtils.join(CQI.cpos2Str(wordProperty.getQualifiedName(), toIntArray(e.getElt2())), " ")
+		return sprintf("%s=%s -> %s", form1+" "+toString(e.getElt1()), form2+" "+toString(e.getElt2()), e.getProps().sort())
+	} else if (e.getClass() == Schema.class) {
+		return sprintf("%s=%d", e.getContenu().size(), e.getProps().sort())
+	}
+}
+
+static def findAllInCorpus(def debug, def analecCorpus, Class elemClazz, String URSQL) {
+	def params = getFilterParameters(URSQL)
+	if (debug >= 2) println "PARAMS=$params"
+	return findAllInCorpus(debug, analecCorpus, elemClazz, params[0], params[1], params[2], params[3])
+}
+
+static def findAllInCorpus(def debug, Corpus analecCorpus, Class elemClazz, String typeRegex, String propName, boolean eq, String valueRegex) {
+	def allElements = null;
+
+	if (elemClazz != null) {
+		if (elemClazz == Unite.class)
+			allElements = analecCorpus.getToutesUnites()
+		else if (elemClazz == Relation.class)
+			allElements = analecCorpus.getToutesRelations()
+		else if (elemClazz == Schema.class)
+			allElements = analecCorpus.getTousSchemas()
+	} else {
+		allElements = [];
+		allElements.addAll(analecCorpus.getToutesUnites())
+		allElements.addAll(analecCorpus.getToutesRelations())
+		allElements.addAll(analecCorpus.getTousSchemas())
+	}
+
+	return filterElements(debug, allElements, typeRegex, propName, eq, valueRegex);
+}
+
+static def filterBySize(def elements, Integer minimum_schema_size, Integer maximum_schema_size) {
+	if (maximum_schema_size == null || maximum_schema_size <= 0) maximum_schema_size = Integer.MAX_VALUE;
+	if (minimum_schema_size == null || minimum_schema_size < 0) minimum_schema_size = 0;
+
+	def filteredElements = []
+	for (Element e : elements) {
+		Unite[] selectedUnits = e.getUnitesSousjacentes();
+		int size = selectedUnits.length;
+		if (minimum_schema_size <= selectedUnits.size() && selectedUnits.size() <= maximum_schema_size ) {
+			filteredElements << e
+		}
+	}
+	return filteredElements
+}
+
+/**
+ * group units by CQP match
+ * 
+ * units are sorted for faster processing
+ * 
+ * @param allUnites
+ * @param matches
+ * @param strict_inclusion
+ * @return
+ */
+static def groupByMatch(def debug, def allUnites, def matches, boolean strict_inclusion) {
+	if (debug >= 2) println "group "+allUnites.size()+" units with "+matches.size()+" strict=$strict_inclusion"
+	//println allUnites.collect() {it -> it.getDeb()}
+	allUnites = allUnites.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+	//println allUnites.collect() {it -> it.getDeb()}
+	def unitsSize = allUnites.size()
+	def iCurrentUnit = 0
+	def selectedUnits = []
+
+	def matchesSize = matches.size()
+	def iCurrentMatch = 0
+
+	def selectedUnitsPerMatch = new LinkedHashMap()
+	selectedUnitsPerMatch[iCurrentMatch] = selectedUnits
+
+	while (iCurrentMatch < matchesSize && iCurrentUnit < unitsSize) {
+		if (debug >= 3) println "** M $iCurrentMatch < $matchesSize && U $iCurrentUnit < $unitsSize"
+
+		Unite unit = allUnites[iCurrentUnit]
+		Match match = matches[iCurrentMatch]
+		if (debug >= 3) println ""+unit.getDeb()+"->"+unit.getFin()+"	"+match.getStart()+"->"+match.getEnd()
+		if (unit.getFin() < match.getStart()) {
+			if (debug >= 3) "println next unit"
+
+				iCurrentUnit++
+		} else if (unit.getDeb() > match.getEnd()) {
+			if (debug >= 3) "println next match"
+
+				iCurrentMatch++
+			selectedUnits = []
+			selectedUnitsPerMatch[iCurrentMatch] = selectedUnits
+		} else {
+			if (debug >= 3) println "iCurrentUnit=$iCurrentUnit	iCurrentMatch=$iCurrentMatch"
+			if (strict_inclusion) {
+
+				if (debug >= 3) println "m.start ${match.getStart()} <= u.deb ${unit.getDeb()} && u.fin ${unit.getFin()} <= m.end ${match.getEnd()}"
+				if (match.getStart() <= unit.getDeb() && unit.getFin() <= match.getEnd()) {
+					selectedUnits << unit
+				}
+			} else {
+				selectedUnits << unit
+			}
+
+			iCurrentUnit++
+		}
+	}
+	return selectedUnitsPerMatch
+}
+
+static def filterUniteByInclusion(def debug, def allUnites, def matches, boolean strict_inclusion, int position) {
+
+	def selectedUnitsPerMatch = groupByMatch(debug, allUnites, matches, strict_inclusion);
+	//println "selectedUnitsPerMatch size="+selectedUnitsPerMatch.size()
+	def selectedUnits = []
+	if (position != 0) {
+		if (position > 0) position--
+
+		for (def m : selectedUnitsPerMatch.keySet()) {
+			if (selectedUnitsPerMatch[m].size() > position && selectedUnitsPerMatch[m].size() > 0) {
+				def units = selectedUnitsPerMatch[m]
+				//println "$m -> "+units.collect() {it -> it.getDeb()}
+				units = units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+				//println "$m -> "+units.collect() {it -> it.getDeb()}
+				selectedUnits << units[position]
+				if (debug >=3) println "dist select: "+units[position].getDeb()
+			}
+		}
+	} else {
+		for (def m : selectedUnitsPerMatch.keySet()) selectedUnits.addAll(selectedUnitsPerMatch[m])
+	}
+
+	return selectedUnits
+}
+
+static def findAllUnitesInElements(def debug, def elements, String URSQL) {
+	def params = getFilterParameters(URSQL)
+	return findAllUnitesInElements(debug, elements, params[0], params[1], params[2], params[3])
+}
+
+static def findAllUnitesInElements(def debug, def elements, String typeRegex, String propName, boolean eq, String valueRegex) {
+	def allElements = []
+
+	for (Element element : elements) {
+		allElements.addAll(filterElements(debug, element.getUnitesSousjacentes(), typeRegex, propName, eq, valueRegex));
+	}
+
+	return allElements;
+}
+
+/**
+ * group all units without selection
+ * 
+ * @param elements
+ * @return
+ */
+static def groupAllUnitesInElements(def debug, def elements) {
+	return groupAllUnitesInElements(debug, elements, "","",true, "")
+}
+
+/**
+ * group all units with URSQL selection
+ * 
+ * @param elements
+ * @param URSQL
+ * @return
+ */
+static def groupAllUnitesInElements(def debug, def elements, String URSQL) {
+	def params = getFilterParameters(URSQL)
+	return groupAllUnitesInElements(debug, elements, params[0], params[1], params[2], params[3])
+}
+
+static def groupAllUnitesInElements(def debug, def elements, String typeRegex, String propName, boolean eq, String valueRegex) {
+	def allElements = [:]
+
+	for (Element element : elements) {
+		allElements[element] = filterElements(debug, element.getUnitesSousjacentes(), typeRegex, propName, eq, valueRegex);
+	}
+
+	return allElements;
+}
+
+static def getFilterParameters(String URSQL) {
+
+	String type = "";
+	String prop = "";
+	String value = "";
+
+	int atidx = URSQL.indexOf("@");
+	int equal_start_idx = URSQL.indexOf("=");
+	int equal_end_idx = equal_start_idx
+	int differentidx = URSQL.indexOf("!=");
+	boolean eq = differentidx < 0 || differentidx != equal_start_idx-1
+	if (!eq) {
+		equal_start_idx--
+	}
+
+	if (atidx >= 0 && equal_start_idx >= 0 && atidx < equal_start_idx) { // TYPE@PROP=VALUE
+		type = URSQL.substring(0, atidx)
+		prop = URSQL.substring(atidx+1, equal_start_idx)
+		value = URSQL.substring(equal_end_idx+1)
+	} else if (atidx >= 0) { // TYPE@PROP
+		type = URSQL.substring(0, atidx)
+		prop = URSQL.substring(atidx+1)
+	} else if (equal_start_idx >= 0) { // TYPE=VALUE -> not well formed
+		type = URSQL.substring(0, equal_start_idx)
+		value = URSQL.substring(equal_end_idx+1)
+	} else { // TYPE
+		type = URSQL;
+	}
+	//	println(["'"+type+"'", "'"+prop+"'", "'"+value+"'"])
+
+	return [type, prop, eq, value]
+}
+
+static def filterElements(def debug, def allElements, String URSQL) {
+	def params = getFilterParameters(URSQL)
+	return filterElements(debug, allElements, params[0], params[1], params[2], params[3])
+}
+
+static def filterElements(def debug, def allElements, String typeRegex, String propName, boolean eq, String valueRegex) {
+	if (debug >= 3) println "filtering "+allElements.size()+" elements with typeRegex='$typeRegex' propName='$propName' and valueRegex='$valueRegex'"
+	if (typeRegex != null && typeRegex.length() > 0) {
+		def filteredElements = []
+		def matcher = /$typeRegex/
+		for (Element element : allElements) {
+			if (element.getType() ==~ matcher) {
+				filteredElements << element
+			}
+		}
+
+		allElements = filteredElements;
+	}
+	if (debug >= 3) println " type step result: "+allElements.size()
+
+	if (propName != null && propName.length() > 0) {
+		def filteredElements = []
+		if (valueRegex != null && valueRegex.length() > 0) {  // select only elements with the prop&value
+			def matcher = /$valueRegex/
+			for (Element element : allElements) {
+				def value = element.getProp(propName)
+				if (value ==~ matcher) {
+					if (eq)	filteredElements << element
+				} else {
+					if (!eq) filteredElements << element
+				}
+			}
+		} else { // select only elements with the prop
+			for (Element element : allElements) {
+				if (element.getProps().containsKey(propName)) {
+					filteredElements << element
+				}
+			}
+		}
+
+		allElements = filteredElements;
+	}
+	if (debug >= 3) println " prop&value step result: "+allElements.size()
+	return allElements;
+}
+
+static def getCQL(String name, def unites) {
+	return getCQL(name, unites, false, true)
+}
+
+/**
+ * 
+ * @param name
+ * @param unites
+ * @param onePosition to return 1 token per patch
+ * @return
+ */
+static def getCQL(String name, def unites, boolean onePosition, boolean limitNumberOfUnit) {
+	//println "GETCQL of $name"
+	def letters = "abcdefghijklmnopqrstuvwxz"//vwxyz0123456789"
+	def MAXCQLQUERYSIZE = 1200 // 1150 // 1200 in fact
+
+	HashSet<Integer> sizes = new HashSet<>()
+
+	for (Unite unite : unites) {
+		int size = unite.getFin() - unite.getDeb()+1
+		if (size > letters.length()) size = letters.length()-1
+		sizes.add(size)
+	}
+
+	int n = 0
+
+	String totalleftquery = ""
+	String totalrightquery = ""
+	unites.sort() { it.getDeb() }
+	def declaredsizes = []
+	for (Unite unite : unites) {
+		int size = unite.getFin() - unite.getDeb() + 1
+		if (size < 0) {
+			println sprintf("** Warning: incoherent unit %s [%d, %d], size = "+size, unite.getProps(),unite.getDeb(), unite.getFin())
+			continue
+		}
+		if (onePosition) size = 1 // hack only the 1st position is needed for the Progression
+		if (size > letters.length()) size = letters.length()-1
+		String letter = ""+letters.charAt(size-1)
+		String rightquery = letter+"="+unite.getDeb()
+
+		String leftquery = ""
+		if (!declaredsizes.contains(size)) {
+			declaredsizes << size
+
+			if (size == 1)
+				leftquery = letter+":[]"
+			else if (size == 2)
+				leftquery = letter+":[][]"
+			else if (size == 3)
+				leftquery = letter+":[][][]"             // [][][][]
+			else
+				leftquery = letter+":[][]{"+(size-1)+"}" // [][]{4}
+		}
+
+		if ((totalleftquery.length() + totalrightquery.length() + 2
+		+ leftquery.length() + rightquery.length()) >= MAXCQLQUERYSIZE) {
+			System.out.println("** $name : trop d'éléments pour la requête. Seuls les "+n+" premiers éléments sur ${unites.size()} seront affichés dans le graphique de progression.")
+			break
+		}
+
+		if (n > 0) {
+			if (leftquery.length() > 0) totalleftquery += "|"
+			totalrightquery += "|"
+		}
+		if (leftquery.length() > 0) totalleftquery += leftquery
+		totalrightquery += rightquery
+
+		n += 1
+	}
+	String query = totalleftquery+"::"+totalrightquery
+	//println query
+	return query
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherSupprimer.txt
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherSupprimer.txt	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherSupprimer.txt	(revision 3653)
@@ -0,0 +1,15 @@
+Macro ChercherSupprimer
+Auteur : Matthieu QUIGNARD
+Version : 05 Février 2019
+
+Supprime de façon **DEFINITIVE** les mentions qui ont une certaine valeur de propriété.
+Comme pour ChercherRemplacer, on peut choisir d'inclure aussi 
+les mentions qui ont une valeur vide pour la propriété donnée.
+
+Par exemple : 
+    CATEGORIE=ERREUR
+    CHECK=
+    REF=NON_REF (suppression des mentions non référentielles)
+    REF=SI (suppression de tous les singletons)
+    
+    
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherSupprimer.txt
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesMacro.groovy	(revision 3653)
@@ -0,0 +1,48 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.misc
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_type",usage="", widget="String", required=true, def="MENTION")
+String schema_type
+
+if (!ParametersDialog.open(this)) return;
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus);
+def map = new HashMap()
+def unitesInSchema = []
+def n = 0
+for (def schema : analecCorpus.getSchemas(schema_type)) {
+	def unites = schema.getUnitesSousjacentes()
+	unitesInSchema.addAll(unites)
+	n += unites.size()
+}
+
+def counts = unitesInSchema.countBy() { it };
+for (def c : counts.keySet()) {
+	if (counts[c] > 1) println "ERROR UNIT IN MULTIPLE SCHEMA["+c.getDeb()+", "+c.getFin()+"]="+c.getProps()+" in "+c.getSchemas().collect() {it.getProps()}
+}
+
+def set = new HashSet()
+set.addAll(unitesInSchema)
+for (def s : set.collect { it.getType() }) {
+	if (!map.containsKey(s)) map[s] = 0;
+	map[s] = map[s] +1
+}
+
+println "Unites types: "+map.sort() { it -> map[it]}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitsCorrelationMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitsCorrelationMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitsCorrelationMacro.groovy	(revision 3653)
@@ -0,0 +1,201 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.misc
+
+import org.apache.commons.lang.StringUtils
+import org.txm.rcp.views.corpora.CorporaView
+import groovy.transform.Field
+
+import org.kohsuke.args4j.*
+import org.txm.Toolbox
+import org.txm.annotation.urs.*
+import org.txm.lexicaltable.core.statsengine.r.data.LexicalTableImpl
+import org.txm.macro.urs.*
+import org.txm.rcp.commands.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.CQLQuery;
+import org.txm.statsengine.r.core.RWorkspace
+
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import cern.colt.matrix.DoubleFactory2D
+import cern.colt.matrix.DoubleMatrix2D
+
+def scriptName = this.class.getSimpleName()
+def parent
+def selection = []
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "** $scriptName please select a Corpus to run the macro"
+}
+
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+		int maximum_schema_size
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+		String unit_ursql
+@Field @Option(name="limit_distance_in_schema", usage="Unit distance in schema (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int limit_distance_in_schema
+@Field @Option(name="limit_cql", usage="CQL to build structure limits", widget="Query", required=true, def="<div> [] expand to div")
+		limit_cql
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+@Field @Option(name="limit_distance", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int limit_distance
+@Field @Option(name="unit_prop1", usage="PROP1", widget="String", required=false, def="PROP1")
+		String unit_prop1
+@Field @Option(name="unit_prop2", usage="PROP2", widget="String", required=false, def="PROP2")
+		String unit_prop2
+@Field @Option(name="corr_method", usage="try them all", widget="StringArray", metaVar="pearson	spearman	kendall", required=false, def="pearson")
+		String corr_method
+@Field @Option(name="corr_style", usage="try them all", widget="StringArray", metaVar="circle	square	ellipse	number	shade	color	pie", required=false, def="number")
+		String corr_style
+@Field @Option(name="corr_layout", usage="try them all", widget="StringArray", metaVar="full	lower	upper", required=false, def="upper")
+		String corr_layout
+@Field @Option(name="corr_order", usage="try them all", widget="StringArray", metaVar="AOE	FPC	hclust	alphabet", required=false, def="hclust")
+		String corr_order
+@Field @Option(name="output_lexicaltable", usage="create or not a lexical table with the result", widget="Boolean", required=true, def="false")
+		output_lexicaltable
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+if (!ParametersDialog.open(this)) return
+	if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+def correlations = [:]
+def values1 = new HashSet()
+def values2 = new HashSet()
+def corpus = corpusViewSelection
+
+mainCorpus = corpus.getMainCorpus()
+
+def word = mainCorpus.getWordProperty()
+def analecCorpus = URSCorpora.getCorpus(mainCorpus)
+
+
+
+def selectedUnits = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size,
+		unit_ursql, limit_distance_in_schema, limit_cql, strict_inclusion, limit_distance);
+
+for (def unit : selectedUnits) {
+	def value1 = unit.getProp(unit_prop1)
+	if (value1 == null) value1 = "<null>"
+	if (value1.length() == 0) value1 = "<empty>"
+	def value2 = unit.getProp(unit_prop2)
+	if (value2 == null) value2 = "<null>"
+	if (value2.length() == 0) value2 = "<empty>"
+
+	values1 << value1
+	values2 << value2
+
+	if (!correlations.containsKey(value1)) correlations[value1] = [:]
+	def line = correlations[value1]
+	if (!line.containsKey(value2)) line[value2] = 0
+	line[value2] += 1
+}
+
+def matrix = new int[values1.size()][values2.size()];
+println "\t"+values2.join("\t")
+int i = 0;
+for (def value1 : values1) {
+	print value1
+	int j = 0;
+	for (def value2 : values2) {
+		if (correlations[value1][value2] == null) correlations[value1][value2] = 0;
+		print "\t"+correlations[value1][value2]
+
+		matrix[i][j] = correlations[value1][value2]
+		j++
+	}
+	println ""
+	i++
+}
+
+def r = RWorkspace.getRWorkspaceInstance()
+r.addVectorToWorkspace("corrlines", values1 as String[])
+r.addVectorToWorkspace("corrcols", values2 as String[])
+r.addMatrixToWorkspace("corrmatrix", matrix)
+r.eval("rownames(corrmatrix) = corrlines")
+r.eval("colnames(corrmatrix) = corrcols")
+
+def resultsDir = new File(Toolbox.getTxmHomePath(), "results")
+resultsDir.mkdirs()
+file = File.createTempFile("txm_corr_pairs_", ".svg", resultsDir)
+
+def title = "${corpus.getMainCorpus()}.${corpus}\n${unit_ursql}"
+if (limit_distance > 1) title += "[${limit_distance}]."
+if (limit_cql != null && !limit_cql.getQueryString().equals("\"\"")) title += "\n(${limit_cql} limits)"
+title += "\t P1=$unit_prop1 P2=unit_prop2"
+
+def plotScript = """
+
+r1 = cor(corrmatrix, use="complete.obs", method="$corr_method");
+r2 = cov(corrmatrix, use="complete.obs") ;
+
+corrplot(r1, type="$corr_layout", order="$corr_order", method="$corr_style")
+"""
+
+
+// execute R script
+if (!output_lexicaltable) {
+	try {
+		r.eval("library(corrplot)")
+		try {
+			r.plot(file, plotScript)
+		} catch (Exception e) {
+			println "** Error: "+e
+		}
+	} catch (Exception e) {
+		println "** The 'corrplot' R package is not installed. Start R ("+RWorkspace.getExecutablePath()+") and run 'install.packages(\"corrplot\");'."
+	}
+}
+title = "$unit_prop1 $corr_method correlations"
+
+
+def lt = null;
+if (output_lexicaltable) {
+	mFactory = DoubleFactory2D.dense
+	dmatrix = mFactory.make(values1.size(), values2.size())
+	for (int ii = 0 ; ii < values1.size() ; ii++) {
+		for (int jj = 0 ; jj < values2.size() ; jj++) {
+			dmatrix.set(ii, jj, matrix[ii][jj])
+		}
+	}
+	if (corpusViewSelection instanceof Partition) {
+		lt = new LexicalTableImpl(dmatrix, corpusViewSelection, corpusViewSelection.getCorpus().getProperty("word"),
+				values1 as String[], values2 as String[])
+		lt.setCorpus(corpusViewSelection.getCorpus());
+		corpusViewSelection.storeResult(lt)
+	} else {
+		lt = new LexicalTableImpl(dmatrix, corpus.getProperty("word"),
+				values1 as String[], values2 as String[])
+		lt.setCorpus(corpus);
+		corpus.storeResult(lt)
+	}
+}
+
+monitor.syncExec(new Runnable() {
+			@Override
+			public void run() { try {
+
+					if (output_lexicaltable) {
+						CorporaView.refreshObject(corpus)
+						CorporaView.expand(lt)
+					} else {
+						OpenBrowser.openfile(file.getAbsolutePath(), "Correlations Units")
+					}
+				} catch (e) { e.printStackTrace() }}
+		})
+
+return correlations
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/SchemaTypesMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/SchemaTypesMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/SchemaTypesMacro.groovy	(revision 3653)
@@ -0,0 +1,28 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.misc
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus);
+
+def schemas = analecCorpus.getTousSchemas()
+def set = new HashMap()
+for (def s : schemas.collect { it.getType() }) {
+	if (!set.containsKey(s)) set[s] = 0;
+	set[s] = set[s] +1
+}
+println "Schemas types: "+set.sort() { it -> set[it]}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherRemplacer.txt
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherRemplacer.txt	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherRemplacer.txt	(revision 3653)
@@ -0,0 +1,13 @@
+Macro ChercherRemplacer
+Auteur : Matthieu QUIGNARD
+Version : 05 Février 2019
+
+Retouche la valeur d'une propriété pour la remplacer par une autre.
+Par exemple : CATEGORIE=PRO.CHECK => CATEGORIE=ERREUR
+
+Possibilité d'inclure aussi les mentions dont la valeur initiale est vide.
+Par exemple : CATEGORIE=          => CATEGORIE=ERREUR
+
+NB : on peut utiliser cette macro pour retoucher le nom des référents.
+Exemple : REF=roi de france       => REF=Le Roi de France
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherRemplacer.txt
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherSupprimerMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherSupprimerMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherSupprimerMacro.groovy	(revision 3653)
@@ -0,0 +1,97 @@
+// ChercherSupprimer
+// Auteur Matthieu Quignard
+// Date : 14 janvier 2019
+
+/**********
+Sert à supprimer des mentions qui une valeur particulière attribuée
+Par exemple : CATEGORIE=ERREUR
+ou bien : REF=NON_REF
+ou encore : CHECK=
+
+ATTENTION : CETTE MACRO N'EST PAS REVERSIBLE
+***********/
+
+package org.txm.macro.urs.prototypes.misc
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.analec.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="Unité", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="prop_name", usage="Propriété", widget="String", required=true, def="CATEGORIE")
+def prop_name
+@Field @Option(name="val_cherche", usage="Valeur recherchée", widget="String", required=true, def="")
+def val_cherche
+@Field @Option(name="inclureVides", usage="Inclure les valeurs vides", widget="Boolean", required=true, def="true")
+def inclureVides
+
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+analecCorpus = AnalecCorpora.getCorpus(corpus.getName())
+vue = AnalecCorpora.getVue(corpus.getName())
+structure = analecCorpus.getStructure()
+
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Erreur : le corpus ne contient d'unité de type $unit_type"
+	println "Script terminé"
+	return
+}
+
+if (!structure.getUniteProperties(unit_type).contains(prop_name)) { 
+	println "Erreur : les unités $unit_type n'ont pas de propriété $prop_name"
+	println "Script terminé"
+	return
+}
+
+println "Option 'inclure les valeurs vides' : $inclureVides"
+
+def nDeleted = 0
+def nIgnored = 0
+
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+
+def garbageBin = []
+
+for (Unite unit : units) { // process all units
+    def val = unit.getProp( prop_name )
+    
+    if ( (val == val_cherche) || ( inclureVides && (val == "")) ) {
+    	garbageBin.add( unit )
+    	nDeleted++
+    } else {
+    	nIgnored++
+    }
+}
+
+// Suppression effective des unités ciblées
+garbageBin.each {
+   analecCorpus.supUnite( it )
+}
+
+if (nDeleted > 0) corpus.setIsModified(true);
+
+println "Result:"
+println "- $nDeleted units of type $unit_type have been deleted."
+println "- $nIgnored units of type $unit_type have not been modified."
+
+AnalecCorpora.getVue(analecCorpus).retablirVueParDefaut()
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/CompUnitPropertiesMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/CompUnitPropertiesMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/CompUnitPropertiesMacro.groovy	(revision 3653)
@@ -0,0 +1,66 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.misc
+
+import org.apache.commons.lang.StringUtils;
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.Toolbox;
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.AbstractCqiClient;
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.Unite;
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type",usage="", widget="String", required=true, def="MENTION")
+String unit_type
+
+@Field @Option(name="print_diff",usage="", widget="Boolean", required=true, def="true")
+boolean print_diff
+
+@Field @Option(name="unit_property_name1", usage="", widget="String", required=false, def="CATEGORIE")
+String unit_property_name1
+
+@Field @Option(name="unit_property_name2", usage="", widget="String", required=false, def="CATEGORIE_ORIG")
+String unit_property_name2
+
+if (!ParametersDialog.open(this)) return;
+
+int n = 1;
+int nDiff = 0;
+MainCorpus corpus = corpusViewSelection
+AbstractCqiClient CQI = CQPSearchEngine.getCqiClient();
+def word = corpus.getWordProperty()
+def analecCorpus = URSCorpora.getCorpus(corpus);
+
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+for (Unite unit : units) {
+	int[] pos = null
+	if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+	else pos = (unit.getDeb()..unit.getFin())
+	def form = StringUtils.join(CQI.cpos2Str(word.getQualifiedName(), pos), " ")
+	def props = unit.getProps()
+	def v1 = props.get(unit_property_name1);
+	def v2 = props.get(unit_property_name2);
+	
+	if (v1 != v2) {
+		if (print_diff) println "$n - ${unit.getDeb()} -> ${unit.getFin()} - $props : $form"
+		nDiff++
+	}
+	n++
+}
+
+if (nDiff == 0) println "$unit_property_name1 and $unit_property_name2 have the same values."
+else println "$unit_property_name1 and $unit_property_name2 have $nDiff/$n different values."
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/RelationsListMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/RelationsListMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/RelationsListMacro.groovy	(revision 3653)
@@ -0,0 +1,71 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.misc
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.tools.ant.types.resources.selectors.InstanceOf;
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.Toolbox;
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.AbstractCqiClient;
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.Relation
+import visuAnalec.elements.Unite;
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="relation_type",usage="", widget="String", required=true, def="ANAPHORE")
+String relation_type
+
+if (!ParametersDialog.open(this)) return;
+
+MainCorpus corpus = corpusViewSelection
+AbstractCqiClient CQI = CQPSearchEngine.getCqiClient();
+def word = corpus.getWordProperty()
+visuAnalec.donnees.Corpus analecCorpus = URSCorpora.getCorpus(corpus);
+
+int n = 1;
+def relations = null
+if (relation_type.length() > 0) {
+	relations = []
+	for (String type : analecCorpus.getStructure().getTypes(Relation.class))
+		relations.addAll(analecCorpus.getRelations(type))
+} else {
+	relations = analecCorpus.getToutesRelations()
+}
+
+for (Relation relation : relations) {
+	def unit1 = relation.getElt1();
+	def unit2 = relation.getElt2();
+	def props = relation.getProps()
+	if (unit1 instanceof Unite && unit2 instanceof Unite) {
+		int[] pos1 = null
+		if (unit1.getDeb() == unit1.getFin()) pos1 = [unit1.getDeb()]
+		else pos1 = (unit1.getDeb()..unit1.getFin())
+		def form1 = StringUtils.join(CQI.cpos2Str(word.getQualifiedName(), pos1), " ")
+		
+		int[] pos2 = null
+		if (unit2.getDeb() == unit2.getFin()) pos2 = [unit2.getDeb()]
+		else pos2 = (unit2.getDeb()..unit2.getFin())
+		def form2 = StringUtils.join(CQI.cpos2Str(word.getQualifiedName(), pos2), " ")
+		
+		println "$n - $props : $form1 -> $form2"
+	} else {
+		println "$n - $props"
+	}
+	n++
+}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesInSchemaMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesInSchemaMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesInSchemaMacro.groovy	(revision 3653)
@@ -0,0 +1,48 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.misc
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_type",usage="", widget="String", required=true, def="CHAINE")
+String schema_type
+
+if (!ParametersDialog.open(this)) return;
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus);
+def map = new HashMap()
+def unitesInSchema = []
+def n = 0
+for (def schema : analecCorpus.getSchemas(schema_type)) {
+	def unites = schema.getUnitesSousjacentes()
+	unitesInSchema.addAll(unites)
+	n += unites.size()
+}
+
+def counts = unitesInSchema.countBy() { it };
+for (def c : counts.keySet()) {
+	if (counts[c] > 1) println "ERROR UNIT IN MULTIPLE SCHEMA["+c.getDeb()+", "+c.getFin()+"]="+c.getProps()+" in "+c.getSchemas().collect() {it.getProps()}
+}
+
+def set = new HashSet()
+set.addAll(unitesInSchema)
+for (def s : set.collect { it.getType() }) {
+	if (!map.containsKey(s)) map[s] = 0;
+	map[s] = map[s] +1
+}
+
+println "Unites types: "+map.sort() { it -> map[it]}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesNotInSchemaMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesNotInSchemaMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesNotInSchemaMacro.groovy	(revision 3653)
@@ -0,0 +1,42 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.misc
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_type",usage="", widget="String", required=true, def="CHAINE")
+String schema_type
+if (!ParametersDialog.open(this)) return;
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus);
+
+def unitesInSchema = new HashSet()
+for (def schema : analecCorpus.getSchemas(schema_type)) {
+	unitesInSchema.addAll(schema.getUnitesSousjacentes())
+}
+println "unites: "+analecCorpus.getToutesUnites().size()
+println "unites in schema: "+unitesInSchema.size()
+
+def set = new HashMap()
+for (def u : analecCorpus.getToutesUnites()) {
+	if (unitesInSchema.contains(u)) continue;
+	
+	if (!set.containsKey(u.getType())) set[u.getType()] = 0;
+	set[u.getType()] = set[u.getType()] +1
+}
+
+println "unites not in schema: "+set.sort() { it -> set[it]}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitsProgressionMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitsProgressionMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitsProgressionMacro.groovy	(revision 3653)
@@ -0,0 +1,178 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.misc
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils
+import org.jfree.chart.JFreeChart
+import org.jfree.chart.plot.XYPlot
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.Toolbox
+import org.txm.progression.core.chartsengine.jfreechart.themes.highcharts.renderers.ProgressionItemSelectionRenderer
+import org.txm.progression.core.functions.Progression
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.chartsengine.rcp.editors.ChartEditor
+import org.txm.macro.urs.AnalecUtils
+import org.txm.searchengine.cqp.AbstractCqiClient
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.Match;
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+import org.txm.rcp.Application
+import org.txm.rcp.IImageKeys
+
+import visuAnalec.donnees.Structure
+import visuAnalec.elements.*
+
+def scriptName = this.class.getSimpleName()
+def parent
+def selection = []
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "** $scriptName please select a Corpus to run the macro"
+}
+selection << corpusViewSelection
+parent = corpusViewSelection
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+		int maximum_schema_size
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+		String unit_ursql
+@Field @Option(name="limit_distance_in_schema", usage="Unit distance in schema (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int limit_distance_in_schema
+@Field @Option(name="limit_cql", usage="CQL to build structure limits", widget="Query", required=true, def="<div> [] expand to div")
+		limit_cql
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+@Field @Option(name="limit_distance", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int limit_distance
+@Field @Option(name="unit_property_display", usage="Unit property to count", widget="String", required=true, def="CATEGORIE")
+		String unit_property_display
+@Field @Option(name="struct_name", usage="Structure to display", widget="String", required=true, def="div")
+		String struct_name
+@Field @Option(name="struct_prop", usage="Structure property to display", widget="String", required=true, def="n")
+		String struct_prop
+@Field @Option(name="line_width", usage="line width", widget="Integer", required=true, def="1")
+		int line_width = 2
+@Field @Option(name="bande_width", usage="bande width", widget="Float", required=true, def="1.0f")
+		float bande_width = 1.0f
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+if (!ParametersDialog.open(this)) return
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+
+	def CQI = CQPSearchEngine.getCqiClient()
+
+def queries = []
+def queryResults = []
+def informations = []
+for (def corpus : selection) {
+	
+	mainCorpus = corpus.getMainCorpus()
+
+	def word = mainCorpus.getWordProperty()
+	def analecCorpus = URSCorpora.getCorpus(mainCorpus.getName())
+
+	def selectedUnits = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, 
+	unit_ursql, limit_distance_in_schema, limit_cql, strict_inclusion, limit_distance);
+
+	def query = ""
+	if (limit_cql != null && !limit_cql.getQueryString().equals("\"\"")) query += limit_cql
+	if (schema_ursql != null && schema_ursql.length() > 0) { if (query.length() > 0) query += " & "; query += ""+schema_ursql+ " >"}
+	if (unit_ursql != null && unit_ursql.length() > 0) query += " "+unit_ursql
+	query = new CQLQuery(query)
+	int[] starts = new int[selectedUnits.size()];
+	int[] ends = new int[selectedUnits.size()];
+	def unitsinformations = []
+	int n = 0;
+	for (Unite unite : selectedUnits) {
+		starts[n] = unite.getDeb()
+		ends[n] = unite.getFin()
+		unitsinformations << AnalecUtils.toString(CQI, word, unite);
+		n++
+	}
+	def queryResult = new FakeQueryResult(corpus.getID(), corpus, query, starts, ends, null)
+	queries << query
+	queryResults << queryResult
+	informations << unitsinformations
+
+	if (unit_property_display != null && unit_property_display.length() > 0) {
+		def propvalues = [:]
+		for (def unit : selectedUnits) {
+			def v = unit.getProp(unit_property_display)
+			if (v == null) v = "<null>"
+			else if (v.length() == 0) v = "<empty>"
+			
+			if (!propvalues.containsKey(v))propvalues[v] = []
+			propvalues[v] << unit
+		}
+		
+		for (def v : propvalues.keySet().sort()) {
+			selectedUnits = propvalues[v]
+			query = corpus.getID()+" "+limit_cql
+			query = new CQLQuery(v)
+			starts = new int[selectedUnits.size()];
+			ends = new int[selectedUnits.size()];
+			unitsinformations = []
+			n = 0;
+			for (Unite unite : selectedUnits) {
+				starts[n] = unite.getDeb()
+				ends[n] = unite.getFin()
+				unitsinformations << AnalecUtils.toString(CQI, word, unite);
+				n++
+			}
+			queryResult = new FakeQueryResult(corpus.getID(), corpus, query, starts, ends, null)
+			queries << query
+			queryResults << queryResult
+			informations << unitsinformations
+		}
+	}
+}
+
+corpus = parent
+try {
+	def struct = corpus.getStructuralUnit(struct_name)
+	def struct_p = struct.getProperty(struct_prop)
+
+	Progression progression = new Progression(corpus, queries,
+			struct, struct_p,	".*",
+			true, false, false,
+			line_width, false, bande_width)
+
+	progression.stepQueries(queryResults); // new
+
+	if (!progression.stepStructuralUnits() || monitor.isCanceled())	return
+		monitor.worked(20)
+	if (!progression.stepFinalize() || monitor.isCanceled()) return
+		monitor.worked(20)
+
+	monitor.syncExec(new Runnable() {
+				@Override
+				public void run() {
+					try {
+						ChartEditor charteditorpart = SWTChartsComponentProvider.openEditor(Application.swtComponentProvider.createProgressionChartEditorPart(IImageKeys.getImage(IImageKeys.ACTION_PROGRESSION), progression, progression.isMonochrome(), progression.isMonostyle(), progression.isDoCumulative()))
+						JFreeChart chart = charteditorpart.getChart()
+						def plot = chart.getXYPlot()
+						ProgressionItemSelectionRenderer renderer = plot.getRenderer();
+						renderer.setAdditionalLabelInformation(informations)
+					} catch(Exception e) {e.printStackTrace()}
+				}
+			})
+
+} catch(Exception e) {
+	e.printStackTrace()
+	return false
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherRemplacerMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherRemplacerMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherRemplacerMacro.groovy	(revision 3653)
@@ -0,0 +1,92 @@
+// ChercherRemplacer
+// Auteur Matthieu Quignard
+// Date : 14 janvier 2019
+
+/**********
+Sert à retoucher une valeur attribuée à une mention et la remplacer par une autre
+Par exemple : CATEGORIE=PRO.CHECK => CATEGORIE=PRO.PER
+ou bien : REF=roi de France => REF=Le Roi de France
+ou encore : REF=      => REF=<EMPTY>
+***********/
+
+package org.txm.macro.urs.prototypes.misc
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.analec.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="Unité", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="prop_name", usage="Propriété", widget="String", required=true, def="CATEGORIE")
+def prop_name
+@Field @Option(name="val_cherche", usage="Valeur recherchée", widget="String", required=true, def="")
+def val_cherche
+@Field @Option(name="val_remplace", usage="Valeur de remplacement", widget="String", required=true, def="")
+def val_remplace
+@Field @Option(name="inclureVides", usage="Inclure les valeurs vides", widget="Boolean", required=true, def="true")
+def inclureVides
+
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+analecCorpus = AnalecCorpora.getCorpus(corpus.getName())
+vue = AnalecCorpora.getVue(corpus.getName())
+structure = analecCorpus.getStructure()
+
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Erreur : le corpus ne contient d'unité de type $unit_type"
+	println "Script terminé"
+	return
+}
+
+if (!structure.getUniteProperties(unit_type).contains(prop_name)) { 
+	println "Erreur : les unités $unit_type n'ont pas de propriété $prop_name"
+	println "Script terminé"
+	return
+}
+
+println "Option 'inclure les valeurs vides' : $inclureVides"
+
+def nModified = 0
+def nIgnored = 0
+
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+
+for (Unite unit : units) { // process all units
+    def val = unit.getProp( prop_name )
+    
+    if ( (val == val_cherche) || ( inclureVides && (val == "")) ) {
+    	vue.setValeurChamp(unit, prop_name, val_remplace)
+    	nModified++
+    } else {
+    	nIgnored++
+    }
+}
+
+
+
+if (nModified > 0) corpus.setIsModified(true);
+
+println "Result:"
+println "- $nModified units of type $unit_type have been modified."
+println "- $nIgnored units of type $unit_type have not been modified."
+
+AnalecCorpora.getVue(analecCorpus).retablirVueParDefaut()
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/SchemasListOldMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/SchemasListOldMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/SchemasListOldMacro.groovy	(revision 3653)
@@ -0,0 +1,181 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.misc
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.Toolbox
+import org.txm.rcp.commands.*
+import org.apache.commons.lang.StringUtils
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_type",usage="", widget="String", required=true, def="CHAIE")
+String schema_type
+
+@Field @Option(name="minimum_schema_size",usage="", widget="Integer", required=true, def="3")
+int minimum_schema_size
+
+@Field @Option(name="schema_property_name",usage="", widget="String", required=false, def="")
+String schema_property_name
+
+@Field @Option(name="schema_property_value",usage="", widget="String", required=false, def=".*")
+String schema_property_value
+
+@Field @Option(name="unit_type",usage="", widget="String", required=false, def="MENTION")
+String unit_type
+
+@Field @Option(name="unit_property_name", usage="", widget="String", required=false, def="")
+String unit_property_name
+
+@Field @Option(name="unit_property_value", usage="", widget="String", required=false, def=".*")
+String unit_property_value
+
+@Field @Option(name="word_property", usage="", widget="StringArray", metaVar="word	lemma	frlemma	frolemma	#forme#	id", required=false, def="word")
+String word_property
+
+@Field @Option(name="separator", usage="", widget="String", required=true, def=", ")
+String separator
+
+@Field @Option(name="buildCQL", usage="générer la requête des unités", widget="Boolean", required=true, def='false')
+def buildCQL
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpus view selection is not a Corpus"
+	return;
+}
+
+if (!ParametersDialog.open(this)) return;
+// END OF PARAMETERS
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus)
+
+// check Schema parameters
+if (!analecCorpus.getStructure().getSchemas().contains(schema_type)) {
+	println "No schema with name=$schema_type"
+	return;
+} else {
+	if (schema_property_name.length() > 0 && schema_property_value.length() > 0) {
+		// test property existance
+		def props = analecCorpus.getStructure().getSchemaProperties(schema_type);
+		if (!props.contains(schema_property_name)) {
+			println "Schema $schema_type has no property named $schema_property_name"
+			return;
+		}
+	}
+}
+
+// check unit parameters
+if (!analecCorpus.getStructure().getUnites().contains(unit_type)) {
+	println "No unit with name=$unit_type"
+	return;
+} else {
+	if (unit_property_name.length() > 0 && unit_property_value.length() > 0) {
+		// test property existance
+		def props = analecCorpus.getStructure().getUniteProperties(unit_type);
+		if (!props.contains(unit_property_name)) {
+			println "Unit $unit_type has no property named $unit_property_name"
+			return;
+		}
+	}
+}
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+if (buildCQL) {
+	word_prop = corpus.getProperty("id")
+} else {
+	word_prop = corpus.getProperty(word_property)
+}
+
+def schemas = analecCorpus.getSchemas(schema_type)
+schemas.sort() {it.getProps()}
+def nSchemas = 0
+
+def lens = [:]
+for (def schema : schemas) {
+
+	if (schema_property_name.length() > 0 && schema_property_value.length() > 0) {
+		if (!schema.getProp(schema_property_name).matches(schema_property_value)) {
+			// ignoring this schema
+			continue
+		}
+	}
+	
+	def nUnites = 0
+	for (def unit : schema.getUnitesSousjacentes()) {
+		if (unit_type.length() > 0) {
+			if (!unit.getType().equals(unit_type)) {
+				continue
+			}
+		}
+		
+		if (unit_property_name.length() > 0 && unit_property_value.length() > 0) {
+			if (!unit.getProp(unit_property_name).matches(unit_property_value)) {
+				// ignoring this schema
+				continue
+			}
+		}
+
+		nUnites++
+	}
+
+	if (nUnites < minimum_schema_size) continue
+
+	print schema.getProps().toString()+ ": "
+	def first = true
+	for (def unit : schema.getUnitesSousjacentes()) {
+		if (unit_type.length() > 0) {
+			if (!unit.getType().equals(unit_type)) {
+				continue
+			}
+		}
+		
+		if (unit_property_name.length() > 0 && unit_property_value.length() > 0) {
+			if (!unit.getProp(unit_property_name).matches(unit_property_value)) {
+				// ignoring this schema
+				continue
+			}
+		}
+
+		String forme =  null;
+
+		if (buildCQL) {
+			int[] pos = null
+			if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+			else pos = (unit.getDeb()..unit.getFin())
+			def first2= true
+			q = ""
+			pos.each {
+				if (first2) { first2 = false } else { q = q+" " }
+				int[] pos2 = [it]
+				q = q+"["+word_prop+"=\""+CQI.cpos2Str(word_prop.getQualifiedName(), pos2)[0]+"\"]"
+			}
+			if (first) { first = false } else { print "|" }
+			print "("+q+")"
+		} else {
+			if (word_prop == null) { // word_property is the analec unit property to use
+			forme = unit.getProp(word_property)
+			} else {
+			int[] pos = null
+			if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+			else pos = (unit.getDeb()..unit.getFin())
+				
+			forme = StringUtils.join(CQI.cpos2Str(word_prop.getQualifiedName(), pos), " ") // ids is enough
+			}
+
+			if (first) { first = false } else { print separator }
+			print forme
+		}
+	}
+	println ""
+
+	nSchemas++
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/EmptyPropValuesMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/EmptyPropValuesMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/EmptyPropValuesMacro.groovy	(revision 3653)
@@ -0,0 +1,75 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.misc
+
+import org.apache.commons.lang.StringUtils
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.Toolbox
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.macro.urs.AnalecUtils
+import org.txm.searchengine.cqp.AbstractCqiClient
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+
+import visuAnalec.donnees.Structure
+import visuAnalec.elements.*
+
+def scriptName = this.class.getSimpleName()
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=true, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+		String unit_ursql
+@Field @Option(name="limit_cql", usage="CQL to build structure limits", widget="Query", required=true, def="<div> [] expand to div")
+		limit_cql
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+@Field @Option(name="limit_distance", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int limit_distance
+@Field @Option(name="debug", usage="Show internal variable content", widget="Boolean", required=true, def="false")
+		debug
+if (!ParametersDialog.open(this)) return
+
+	def CQI = CQPSearchEngine.getCqiClient()
+
+//corpus = corpusViewSelection
+for (def corpus : selection) {
+
+	mainCorpus = corpus.getMainCorpus()
+
+	def word = mainCorpus.getWordProperty()
+	def analecCorpus = URSCorpora.getCorpus(mainCorpus.getName())
+
+	def selectedUnits = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, Integer.MAX_VALUE,
+			unit_ursql, limit_cql, strict_inclusion, limit_distance);
+
+	for (def unit : selectedUnits) {
+		def props = unit.getProps();
+		for (def k : props.keySet()) {
+			if (props[k] == null) {
+				println "$corpus\t"+unit.getDeb()+"->"+unit.getFin()+"\t"+k
+			}
+		}
+	}
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/URSUnits2CQPStructMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/URSUnits2CQPStructMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/URSUnits2CQPStructMacro.groovy	(revision 3653)
@@ -0,0 +1,135 @@
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.cqp
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.annotation.urs.*
+import org.txm.importer.ValidateXml
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.elements.*
+
+// BEGINNING OF PARAMETERS
+
+// Open the parameters input dialog box
+//if (!ParametersDialog.open(this)) return;
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Selection must be a Corpus"
+	return
+}
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus)
+
+def texts = corpus.getCorpusTextIdsList();
+def texts_startlimits = corpus.getTextStartLimits()
+def texts_endlimits = corpus.getTextEndLimits()
+
+for (int i = 0 ; i < texts.size() ; i++) {
+
+	println "Processing annotations of "+texts[i]+"..."
+
+	def text_id = texts[i]
+	def text_start = texts_startlimits[i]
+	def text_end = texts_endlimits[i]
+
+	File xmltxmFile = new File(corpus.getProject().getProjectDirectory(), "txm/"+corpus.getID()+"/"+text_id+".xml")
+	File xmltxmFileCopy = new File(corpus.getProject().getProjectDirectory(), text_id+"_copy.xml")
+
+	if (!xmltxmFile.exists()) {
+		println "Warning: no text file found: "+xmltxmFile
+		continue
+	}
+
+	// WRITE MILESTONES UNITS
+
+	println "-> MILESTONES UNITS"
+
+	def units = []
+	for (String unit_type : analecCorpus.getStructure().getTypes(Unite.class)) {
+		def corpus_units = []
+		ArrayList<Unite> all_units = analecCorpus.getUnites(unit_type)
+		corpus_units = all_units.findAll() {
+			it.getProp("type") != null && it.getProp("type").trim().length() > 0 && "yes".equals(it.getProp("milestone")) && text_start <= it.getDeb() && it.getFin() < text_end && !("true".equals(it.getProp("written")))
+		}
+		units.addAll(corpus_units)
+	}
+
+	if (units.size()== 0) {
+		println "No milestones to write"
+	} else {
+		try {
+			println "processing milestones Units ${text_id} and its units "+units.size()
+			MileStoneInserter inserter = new MileStoneInserter(corpus, xmltxmFile, units);
+			if (inserter.process(xmltxmFileCopy) && ValidateXml.test(xmltxmFileCopy)) {
+				xmltxmFile.delete()
+				xmltxmFileCopy.renameTo(xmltxmFile)
+
+				for (Unite unit : units) {
+					unit.getProps()["written"] = "true"
+				}
+				URSCorpora.saveCorpus(corpus);
+				println "Done, "+units.size()+ " milestones written"
+
+			} else {
+				println "Error while processing milestones $xmltxmFile file"
+				File error = new File(corpus.getProject().getProjectDirectory(), "error/"+xmltxmFile.getName())
+				error.getParentFile().mkdirs()
+				println "	moving created file to $error"
+				error.delete()
+				xmltxmFileCopy.renameTo(error)
+			}
+		} catch(Exception e) {
+			println "Error while processing milestones $xmltxmFile file: "+e
+			File error = new File(corpus.getProject().getProjectDirectory(), "error/"+xmltxmFile.getName())
+			error.getParentFile().mkdirs()
+			println "	moving created file to $error"
+			error.delete()
+			xmltxmFileCopy.renameTo(error)
+		}
+	}
+	// WRITE NON MILESTONES UNITS
+	println "-> OTHER UNITS"
+
+	for (String unit_type : analecCorpus.getStructure().getTypes(Unite.class)) {
+		
+		def corpus_units = []
+		ArrayList<Unite> all_units = analecCorpus.getUnites(unit_type)
+		corpus_units = all_units.findAll() {
+			it.getProp("type") != null && it.getProp("type").trim().length() > 0 && !"no".equals(it.getProp("milestone")) && text_start <= it.getDeb() && it.getFin() < text_end && !("true".equals(it.getProp("written")))
+		}
+
+		if (corpus_units.size() == 0) continue;
+		
+		println "processing Units ${text_id} and its $unit_type units "+corpus_units.size()
+		UnitsInserter inserter2 = new UnitsInserter(corpus, xmltxmFile, corpus_units, unit_type);
+		try {
+			if (inserter2.process(xmltxmFileCopy) && ValidateXml.test(xmltxmFileCopy)) {
+				xmltxmFile.delete()
+				xmltxmFileCopy.renameTo(xmltxmFile)
+
+				for (Unite unit : corpus_units) {
+					unit.getProps()["written"] = "true"
+				}
+				URSCorpora.saveCorpus(corpus);
+				println "Done, "+corpus_units.size()+ " units written"
+
+			} else {
+				println "Error while processing milestones $xmltxmFile file"
+				File error = new File(corpus.getProject().getProjectDirectory(), "error/"+xmltxmFile.getName())
+				error.getParentFile().mkdirs()
+				println "	moving created file to $error"
+				error.delete()
+				xmltxmFileCopy.renameTo(error)
+			}
+		} catch(Exception e) {
+			println "Error while processing milestones $xmltxmFile file: "+e
+			File error = new File(corpus.getProject().getProjectDirectory(), "error/"+xmltxmFile.getName())
+			error.getParentFile().mkdirs()
+			println "	moving created file to $error"
+			error.delete()
+			xmltxmFileCopy.renameTo(error)
+		}
+	}
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/WordUnitsInserter.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/WordUnitsInserter.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/WordUnitsInserter.groovy	(revision 3653)
@@ -0,0 +1,172 @@
+package org.txm.macro.urs.prototypes.cqp
+
+import java.io.IOException
+import java.util.Date
+import java.util.LinkedHashMap
+
+import javax.xml.stream.XMLStreamException
+
+import org.txm.Toolbox
+import org.txm.importer.StaxIdentityParser
+import org.txm.macro.urs.AnalecUtils
+import org.txm.scripts.importer.GetAttributeValue
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.txm.searchengine.cqp.corpus.MainCorpus
+import visuAnalec.elements.Unite
+
+public class WordUnitsInserter extends StaxIdentityParser {
+
+	List<Unite> units
+	String[] ids
+	File inputFile
+	def id2Units = [:]
+	def unit_properties // "*" or list (String)
+	def unit_internal_properties = false
+	def unit_word // ALL START END
+	LinkedHashMap<String, String> anaValues = new LinkedHashMap<String, String>();
+
+	public WordUnitsInserter(MainCorpus corpus, File inputFile, List<Unite> units, String unit_properties, String unit_word, boolean unit_internal_properties) {
+		super(inputFile)
+		this.inputFile = inputFile
+		
+		this.unit_internal_properties = unit_internal_properties
+		this.unit_properties = unit_properties
+		this.unit_word = unit_word
+		if (!("*".equals(unit_properties))) {
+			this.unit_properties = this.unit_properties.split(",")
+		}
+
+		this.units = units
+		this.units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+
+		for (int i = 0 ; i < units.size() ; i++) {
+			Unite u = units[i]
+			int[] positions = null;
+			if ("START".equals(unit_word)) {
+				positions = [u.getDeb()] as int[]
+			} else if ("END".equals(unit_word)) {
+				positions = [u.getFin()] as int[]
+			} else {
+				positions = u.getDeb()..u.getFin()
+			}
+
+			ids = CQPSearchEngine.getCqiClient().cpos2Str(corpus.getProperty("id").getQualifiedName(), positions)
+
+			for (String id : ids) {
+				if (!id2Units.containsKey(id)) {
+					id2Units[id] = []
+				}
+				id2Units[id] << u
+			}
+		}
+	}
+
+	boolean inAna = false
+	String ana_type, ana_resp, ana_value
+	boolean inW = false
+	String word_id = null
+
+	protected void processStartElement() throws XMLStreamException, IOException {
+
+		if ("w".equals(localname)) {
+			
+			inW = true
+			word_id = this.getParserAttributeValue("id")
+
+			if (id2Units.containsKey(word_id)) {
+				for (Unite u : id2Units[word_id]) {
+					def props = u.getProps()
+					
+					def propNames = props.keySet();
+					if (!("*".equals(unit_properties))) {
+						propNames = unit_properties
+					}				
+					
+					for (String p : propNames) {
+						
+						if (!anaValues.containsKey(p)) {
+							anaValues[p] = ""
+							ana_resp = "#urs"
+						}
+						anaValues[p] = (anaValues[p]+" "+props.get(p)).trim()
+					}
+					if (unit_internal_properties) {
+	
+						anaValues["urs-type"] = u.getType()
+						anaValues["urs-start"] = ""+u.getDeb()
+						anaValues["urs-end"] = ""+u.getFin()
+					}
+				}
+				if (anaValues.size() > 0) println anaValues
+			}
+
+			super.processStartElement(); // write the tag
+			
+		} else if ("ana".equals(localname) && inW) {
+			
+			inAna = true
+			ana_type = this.getParserAttributeValue("type").substring(1)
+			ana_resp = this.getParserAttributeValue("resp")
+			ana_value = ""
+			
+		} else {
+			super.processStartElement()
+		}
+	}
+
+	@Override
+	public void processCharacters() throws XMLStreamException {
+		if (inAna) {
+			ana_value += parser.getText().trim()
+		} else {
+			super.processCharacters()
+		}
+	}
+
+	protected void processEndElement() throws XMLStreamException {
+
+		if ("w".equals(localname)) {
+			
+			// write the last values
+			for (String ana_type : anaValues.keySet()) {
+				writer.writeStartElement("txm:ana")
+				writer.writeAttribute("type", "#" + ana_type)
+				writer.writeAttribute("resp", "#txm") // change
+				writer.writeCharacters(anaValues[ana_type])
+				writer.writeEndElement()
+			}
+			
+			anaValues.clear()
+			super.processEndElement() // finally write word then close annotations
+			inW = false
+			
+		} else if ("ana".equals(localname) && inW) {
+
+			if (!anaValues.containsKey(ana_type)) {
+				anaValues[ana_type] = ana_value.trim()
+			} else {
+				ana_resp = "#txm" // set the resp to txm since anaValues update the ana value
+				anaValues[ana_type] = (anaValues[ana_type]+" "+ana_value.trim()).trim()
+			}
+
+			String value = anaValues[ana_type]
+
+			writer.writeStartElement("txm:ana")
+			writer.writeAttribute("type", "#" + ana_type)
+			writer.writeAttribute("resp", ana_resp) // change
+			writer.writeCharacters(value)
+			writer.writeEndElement()
+			
+			anaValues.remove(ana_type)
+			
+			inAna = false
+			ana_type = null
+			ana_resp = null
+			ana_value = null
+
+			// write ana later
+		} else {
+			super.processEndElement()
+		}
+	}
+}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/MileStoneInserter.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/MileStoneInserter.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/MileStoneInserter.groovy	(revision 3653)
@@ -0,0 +1,94 @@
+package org.txm.macro.urs.prototypes.cqp
+
+import java.io.IOException
+
+import javax.xml.stream.XMLStreamException
+
+import org.txm.importer.StaxIdentityParser
+import org.txm.macro.urs.AnalecUtils
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.txm.searchengine.cqp.corpus.MainCorpus
+import visuAnalec.elements.Unite
+
+public class MileStoneInserter extends StaxIdentityParser {
+	
+	List<Unite> units
+	String[] ids
+	File inputFile
+	def id2Units = [:]
+	
+	public MileStoneInserter(MainCorpus corpus, File inputFile, List<Unite> units) {
+		super(inputFile);
+		this.inputFile = inputFile;
+		
+		this.units = units;
+		this.units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+		
+		int[] positions = new int[units.size()];
+		for( int i = 0 ; i < units.size() ; i++) {
+			positions[i] = units.get(i).getDeb();
+		}
+		
+		ids = CQPSearchEngine.getCqiClient().cpos2Str(corpus.getProperty("id").getQualifiedName(), positions);
+		
+		for (int i = 0 ; i < ids.length ; i++) {
+			String id = ids[i]
+			if (id != null) {
+				if (!id2Units.containsKey(id)) id2Units[id] = []
+				
+				id2Units[id] << units[i]
+			}
+		}
+	}
+	
+	boolean start = false;
+	String word_id = null;
+	@Override
+	protected void processStartElement() throws XMLStreamException, IOException {
+		
+		if ("text".equals(localname)) {
+			start = true;
+		} else if ("w".equals(localname) && start) {
+			word_id = getParserAttributeValue("id");
+			if (word_id == null) {
+				println "Warning: found <w> without id at line "+parser.getLocation().getLineNumber()+" in "+inputFile
+			} else {
+				writeAllUnits(word_id, "before")
+			}
+		}
+		
+		super.processStartElement();
+	}
+	
+	protected void writeAllUnits(String id, String position) {
+		
+		def units = id2Units[id]
+		if (units == null) return; // no units to write
+		
+		for (Unite currentUnit : units) {
+			
+			if (!position.equals(currentUnit.getProp("position"))) return;
+				
+			writer.writeStartElement(currentUnit.getProp("type"));
+			HashMap props = currentUnit.getProps();
+			for (String p : props.keySet()) {
+				if (p.equals("type")) continue; // ignore the type since written in tag name
+				writer.writeAttribute(p, ""+props.get(p));
+			}
+			writer.writeEndElement();
+		}
+	}
+	
+	@Override
+	protected void processEndElement() throws XMLStreamException {
+		super.processEndElement();
+	
+		if ("w".equals(localname) && start && word_id != null) {
+			writeAllUnits(word_id, "after")
+		}
+		
+		if ("w".equals(localname)) {
+			word_id = null;
+		}
+	}
+}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/UnitsInserter.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/UnitsInserter.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/UnitsInserter.groovy	(revision 3653)
@@ -0,0 +1,170 @@
+package org.txm.macro.urs.prototypes.cqp
+
+import java.io.IOException
+
+import javax.xml.stream.XMLStreamException
+
+import org.txm.importer.StaxIdentityParser
+import org.txm.macro.urs.AnalecUtils
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.txm.searchengine.cqp.corpus.MainCorpus
+import visuAnalec.elements.Unite
+
+public class UnitsInserter extends StaxIdentityParser {
+
+	List<Unite> units
+	String[] ids
+	File inputFile
+	def open_id2Units = [:]
+	def close_id2Units = [:]
+	def writing_units = []
+	def writing_stacks = []
+	
+	def stack = "";
+
+	def writing_start, writing_end;
+	
+	def positions2id = [:] // used to relocate end of units
+
+	public UnitsInserter(MainCorpus corpus, File inputFile, List<Unite> units, String type) {
+		super(inputFile);
+		this.inputFile = inputFile;
+		this.units = units;
+		
+		this.units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: b.getFin() <=> a.getFin() }
+
+		// get words id limits
+		int[] positions = new int[units.size()];
+		for( int i = 0 ; i < units.size() ; i++) {
+			positions[i] = units.get(i).getDeb();
+		}
+		ids = CQPSearchEngine.getCqiClient().cpos2Str(corpus.getProperty("id").getQualifiedName(), positions);
+		for (int i = 0 ; i < ids.length ; i++) {
+			String id = ids[i]
+			
+			if (id != null) {
+				positions2id[positions[i]] = id
+				if (!open_id2Units.containsKey(id)) open_id2Units[id] = []
+				open_id2Units[id] << units[i]
+			}
+		}
+
+		positions = new int[units.size()];
+		for( int i = 0 ; i < units.size() ; i++) {
+			positions[i] = units.get(i).getFin();
+		}
+		ids = CQPSearchEngine.getCqiClient().cpos2Str(corpus.getProperty("id").getQualifiedName(), positions);
+		for (int i = 0 ; i < ids.length ; i++) {
+			String id = ids[i]
+			if (id != null) {
+				positions2id[positions[i]] = id
+				if (!close_id2Units.containsKey(id)) close_id2Units[id] = new HashSet<Unite>()
+				close_id2Units[id] << units[i]
+			}
+		}
+	}
+
+	boolean start = false;
+	String word_id = null;
+	@Override
+	protected void processStartElement() throws XMLStreamException, IOException {
+
+		stack += "/"+localname
+
+		if ("text".equals(localname)) {
+			start = true;
+		} else if ("w".equals(localname) && start) {
+			word_id = getParserAttributeValue("id");
+			if (word_id == null) {
+				println "Warning: found <w> without id at line "+parser.getLocation().getLineNumber()+" in "+inputFile
+			} else {
+				writeOpenUnits()
+			}
+		}
+
+		super.processStartElement();
+	}
+
+	protected void writeOpenUnits() {
+		
+		def toWrite = open_id2Units[word_id]
+		
+		if (toWrite != null) {
+			for (Unite unite : toWrite) {
+				
+				for (int i = 0 ; i < writing_units.size() ; i++) {
+					Unite u = writing_units.get(i);
+					if (unite.getFin() > u.getFin()) {
+						// add unite to close_id2Units
+						String id = positions2id[u.getFin()]
+						close_id2Units[id] << unite // close the unite at the same moment
+					}
+				}
+				
+				writeUnit(unite);
+			}
+		}
+	}
+
+	protected void writeCloseUnits() {
+		if (word_id != null) {
+			def toClose = close_id2Units[word_id]
+			if (toClose != null) {
+				for (int i = 0 ; i < writing_units.size() ; i++) {
+					Unite u = writing_units.get(i);
+					if (toClose.contains(u)) {
+						writing_stacks.remove(i)
+						writing_units.remove(i)
+						writer.writeEndElement();
+						i--;
+					}
+				}
+			}
+		} else {
+			for (int i = 0 ; i < writing_stacks.size() ; i++) {
+				if (writing_stacks[i].equals(stack)) {
+					writing_stacks.remove(i)
+					writing_units.remove(i)
+					writer.writeEndElement();
+					i--
+				}
+			}
+		}
+	}
+
+	protected void writeUnit(Unite currentUnit) {
+
+		writing_units << currentUnit
+		writing_stacks << currentUnit
+		if (currentUnit.getDeb() > writing_start)
+
+		writer.writeStartElement(currentUnit.getProp("type"));
+		HashMap props = currentUnit.getProps();
+		for (String p : props.keySet()) {
+			if (p.equals("type")) continue; // ignore the type since written in tag name
+			writer.writeAttribute(p, ""+props.get(p));
+		}
+	}
+
+	@Override
+	protected void processEndElement() throws XMLStreamException {
+		
+//		println "writing_stacks=$writing_stacks"
+//		println "stack=$stack"
+		
+		if (writing_stacks.size() > 0 && writing_stacks[-1].equals(stack)) {
+			writeCloseUnits()
+		}
+
+		super.processEndElement();
+		
+		stack = stack.substring(0, stack.length() - localname.length() - 1);
+		
+		if ("w".equals(localname)) {
+			if (start && word_id != null) {
+				writeCloseUnits()
+			}
+			word_id = null;
+		}
+	}
+}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/URSUnits2CQPWordsMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/URSUnits2CQPWordsMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/URSUnits2CQPWordsMacro.groovy	(revision 3653)
@@ -0,0 +1,95 @@
+package org.txm.macro.urs.prototypes.cqp
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.annotation.urs.*
+import org.txm.importer.ValidateXml
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.elements.*
+
+// BEGINNING OF PARAMETERS
+
+// Open the parameters input dialog box
+//if (!ParametersDialog.open(this)) return;
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Selection must be a Corpus"
+	return
+}
+
+@Field @Option(name="unit_type", usage="Corpus name in uppercase", widget="String", required=true, def="Entity")
+		String unit_type
+
+@Field @Option(name="unit_properties", usage=" * or comma separated list of properties names", widget="String", required=true, def="Property")
+		String unit_properties
+		
+@Field @Option(name="unit_internal_properties", usage="Corpus name in uppercase", widget="Boolean", required=true, def="false")
+def unit_internal_properties
+
+@Field @Option(name="unit_word", usage="CQP word position to annotate", widget="StringArray", metaVar="START	END", required=true, def="START")
+		String unit_word
+
+if (!ParametersDialog.open(this)) return
+
+def corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus)
+
+def texts = corpus.getCorpusTextIdsList();
+def texts_startlimits = corpus.getTextStartLimits()
+def texts_endlimits = corpus.getTextEndLimits()
+
+for (int i = 0 ; i < texts.size() ; i++) {
+	
+	println "Processing annotations of "+texts[i]+"..."
+	
+	def text_id = texts[i]
+	def text_start = texts_startlimits[i]
+	def text_end = texts_endlimits[i]
+	
+	File xmltxmFile = new File(corpus.getProject().getProjectDirectory(), "txm/"+corpus.getID()+"/"+text_id+".xml")
+	File xmltxmFileCopy = new File(corpus.getProject().getProjectDirectory(), text_id+"_copy.xml")
+	
+	if (!xmltxmFile.exists()) {
+		println "Warning: no text file found: "+xmltxmFile
+		continue
+	}
+	
+	def corpus_units = []
+	ArrayList<Unite> all_units = analecCorpus.getUnites(unit_type)
+	corpus_units = all_units.findAll() {
+		text_start <= it.getDeb() && it.getFin() < text_end
+	}
+	
+	if (corpus_units.size() == 0) {
+		println " No '$unit_type' unit found."
+		continue;
+	}
+	
+	try {
+		println " Processing word Units ${text_id} and its '$unit_type' units ("+corpus_units.size()+")"
+		WordUnitsInserter inserter = new WordUnitsInserter(corpus, xmltxmFile, corpus_units, unit_properties, unit_word, unit_internal_properties);
+		if (inserter.process(xmltxmFileCopy) && ValidateXml.test(xmltxmFileCopy)) {
+			xmltxmFile.delete()
+			xmltxmFileCopy.renameTo(xmltxmFile)
+			
+			println "Done, "+corpus_units.size()+ " units written"
+			
+		} else {
+			println "Error while processing the XML-TXM $xmltxmFile file"
+			File error = new File(corpus.getProject().getProjectDirectory(), "error/"+xmltxmFile.getName())
+			error.getParentFile().mkdirs()
+			println "	moving created file to $error"
+			error.delete()
+			xmltxmFileCopy.renameTo(error)
+		}
+	} catch(Exception e) {
+		println "Error while processing milestones $xmltxmFile file: "+e
+		e.printStackTrace();
+		File error = new File(corpus.getProject().getProjectDirectory(), "error/"+xmltxmFile.getName())
+		error.getParentFile().mkdirs()
+		println "	moving created file to $error"
+		error.delete()
+		xmltxmFileCopy.renameTo(error)
+	}
+}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/AllMesuresMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/AllMesuresMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/AllMesuresMacro.groovy	(revision 3653)
@@ -0,0 +1,135 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.exploit
+
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.core.preferences.TBXPreferences
+import org.txm.core.preferences.TXMPreferences
+import org.txm.searchengine.cqp.corpus.*
+import org.apache.commons.lang.StringUtils;
+
+// BEGINNING OF PARAMETERS
+
+@Field @Option(name="csvFile",usage="", widget="FileSave", required=true, def="result.tsv")
+File csvFile
+
+@Field @Option(name="default_schema_ursql", usage="TYPE@PROP=REGEX", widget="String", required=true, def="CHAINE")
+String default_schema_ursql
+
+@Field @Option(name="default_minimum_schema_size", usage="", widget="Integer", required=true, def="3")
+int default_minimum_schema_size
+
+
+@Field @Option(name="schema_property_display_name",usage="", widget="String", required=false, def="REF")
+String schema_property_display_name
+
+@Field @Option(name="default_unit_ursql", usage="TYPE@PROP=REGEX", widget="String", required=false, def="MENTION")
+String default_unit_ursql
+
+@Field @Option(name="default_word_property", usage="", widget="String", required=false, def="word")
+String default_word_property
+@Field @Option(name="default_pos_property", usage="", widget="String", required=false, def="CATEGORIE")
+String default_pos_property
+
+if (!ParametersDialog.open(this)) return;
+// END OF PARAMETERS
+
+println "Corpora selections: "+corpusViewSelections
+
+table = [] // contains all table lines
+mesures = []
+
+for (def corpus : corpusViewSelections) { // for each corpus selected in the corpora view
+	if (!(corpus instanceof MainCorpus)) continue; // check if the corpus is a maincorpus
+	def line = [] ; table << line // create and add a new table line
+	line << corpus.getID() // add the corpus name in the first column
+	
+	println "*** Computing mesures for $corpus" // each macro return a "result" and a "data"
+
+	params = [
+		"unit_ursql":default_unit_ursql,
+	]
+	returnedValue = execMesure(UnitsReferentialDensityMacro, line, corpus, params)
+	line << returnedValue["result"]
+	
+	params = [
+		"schema_ursql":default_schema_ursql,
+		"minimum_schema_size":default_minimum_schema_size,
+		"unit_ursql":default_unit_ursql,
+	]
+	returnedValue = execMesure(SchemaLengthsMacro, line, corpus, params)
+	line << returnedValue["result"]
+	
+	params = [
+		"schema_ursql":default_schema_ursql,
+		"minimum_schema_size":default_minimum_schema_size,
+		"unit_ursql":default_unit_ursql,
+	]
+	returnedValue = execMesure(NumberOfSchemaMacro, line, corpus, params)
+	line << returnedValue["result"]
+	
+	params = [
+		"schema_ursql":default_schema_ursql,
+		"minimum_schema_size":default_minimum_schema_size,
+		"schema_property_display_name":schema_property_display_name,
+		"unit_ursql":default_unit_ursql+"@CATEGORIE=GN Défini|GN Démonstratif|Nom Propre",
+		"word_property":default_word_property,
+	]
+	returnedValue = execMesure(UnitsStabilityScoreMacro, line, corpus, params)
+	line << returnedValue["result"]
+	
+	params = [
+		"schema_ursql":default_schema_ursql,
+		"minimum_schema_size":default_minimum_schema_size,
+		"unit_ursql":default_unit_ursql,
+	]
+	returnedValue = execMesure(UnitsInterDistanceMacro, line, corpus, params)
+	line << returnedValue["result"]
+
+	params = [
+		"schema_ursql":default_schema_ursql,
+		"minimum_schema_size":default_minimum_schema_size,
+		"unit_ursql":default_unit_ursql,
+		"word_property":default_pos_property,
+	]
+	returnedValue = execMesure(NatureOfTheFirstUnitMacro, line, corpus, params)
+	line << returnedValue["data"]
+	
+	params = [
+		"schema_ursql":default_schema_ursql,
+		"minimum_schema_size":default_minimum_schema_size,
+		"schema_property_display_name":schema_property_display_name,
+		"unit_ursql":default_unit_ursql,
+		"word_property":default_pos_property,
+	]
+	returnedValue = execMesure(GrammaticalCategoryMacro, line, corpus, params)
+	line << returnedValue["data"]
+}
+
+// WRITE RESULTS IN THE TSV FILE
+def separator = TBXPreferences.getInstance().getString(TBXPreferences.EXPORT_COL_SEPARATOR)
+csvFile.withWriter("UTF-8") { writer ->
+	writer.println "\t"+mesures.join("\t")
+	table.each { line -> writer.println line.join("\t")	}
+}
+
+println "Done. Results are saved in ${csvFile.getAbsolutePath()} file."
+
+// UTILITY FUNCTIONS
+def execMesure(def mesure, def line, def corpus, def params) {
+	def m = mesure.getSimpleName().substring(0, mesure.getSimpleName().indexOf("Macro"))
+	mesures << m
+	println "***** ${mesures.size()}- $m with parameters: $params"
+	def r = gse.run(mesure, ["args":params, "corpusViewSelection":corpus, "monitor":monitor])
+	if (r == null) throw new Exception("Null result");
+	return r;
+}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/NatureOfTheFirstUnitMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/NatureOfTheFirstUnitMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/NatureOfTheFirstUnitMacro.groovy	(revision 3653)
@@ -0,0 +1,105 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.exploit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.*
+import org.txm.macro.urs.AnalecUtils
+import visuAnalec.elements.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.apache.commons.lang.StringUtils;
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=REGEX", widget="String", required=true, def="CHAINE")
+String schema_ursql
+
+@Field @Option(name="minimum_schema_size", usage="minimal schema size", widget="Integer", required=true, def="3")
+int minimum_schema_size
+
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=REGEX", widget="String", required=false, def="MENTION")
+String unit_ursql
+
+@Field @Option(name="word_property", usage="", widget="String", required=false, def="CATEGORIE")
+String word_property
+
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+debug
+
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+
+CQPCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus)
+
+if (!AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)) {
+	println "** The $schema_ursql schema URSQL cannot be computed in the corpus."
+	return;
+}
+
+if (!AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, unit_ursql)) {
+	println "** $unit_ursql unit URSQL cannot be computed in the corpus."
+	return;
+}
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+def prop = corpus.getProperty(word_property)
+
+def schemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, 999999);
+def freqs = [:]
+
+def distances = 0;
+def nDistances = 0
+for (def schema : schemas) {
+	
+	def allUnites = schema.getUnitesSousjacentesNonTriees()
+	
+	def units = AnalecUtils.filterElements(debug, allUnites, unit_ursql)
+	
+	int nUnites = units.size();
+	
+	if (units.size() == 0) continue;
+	
+	def unit = units[0]
+	
+	String forme =  null;
+	if (prop == null) { // word_property is the analec unit property to use
+		forme = unit.getProp(word_property)
+	} else {
+		int[] pos = null;
+		if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+		else pos = unit.getDeb()..unit.getFin()
+			
+		forme = StringUtils.join(CQI.cpos2Str(prop.getQualifiedName(), pos), " ") // ids is enough
+	}
+	
+	if (!freqs.containsKey(forme)) freqs[forme] = 0;
+	
+	freqs[forme] = freqs[forme] + 1;
+}
+
+println "Index des natures de premier maillon :"
+int max = 0;
+def result = "";
+for (def forme : freqs.keySet().sort() {it -> -freqs[it]}) {
+	println "$forme\t"+freqs[forme]
+	if (max < freqs[forme]) {
+		max = freqs[forme]
+		result = "$forme: "+freqs[forme]
+	}
+}
+
+["result": result, "data": freqs]
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/NumberOfSchemaMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/NumberOfSchemaMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/NumberOfSchemaMacro.groovy	(revision 3653)
@@ -0,0 +1,50 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.exploit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import visuAnalec.elements.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.macro.urs.AnalecUtils
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=REGEX", widget="String", required=true, def="CHAINE")
+String schema_ursql
+
+@Field @Option(name="minimum_schema_size", usage="minimal schema size", widget="Integer", required=true, def="3")
+int minimum_schema_size
+
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+debug
+
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+
+CQPCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus)
+
+// check Schema parameters
+if (!AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)) {
+	println "** The $schema_ursql schema URSQL cannot be computed in the corpus."
+	return;
+}
+
+def schemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, 999999);
+
+int nSchemas = schemas.size();
+
+println "Nombre de chaînes de référence d'un texte : $nSchemas"
+
+["result":nSchemas, "data":schemas]
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/GrammaticalCategoryMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/GrammaticalCategoryMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/GrammaticalCategoryMacro.groovy	(revision 3653)
@@ -0,0 +1,126 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.exploit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.*
+import org.txm.macro.urs.AnalecUtils
+import visuAnalec.elements.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import org.apache.commons.lang.StringUtils;
+
+// BEGINNING OF PARAMETERS
+
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=true, def="CHAINE")
+String schema_ursql
+
+@Field @Option(name="minimum_schema_size", usage="minimal schema size", widget="Integer", required=true, def="3")
+int minimum_schema_size
+
+@Field @Option(name="schema_display_property_name",usage="", widget="String", required=false, def="REF")
+String schema_display_property_name
+
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+String unit_ursql
+
+@Field @Option(name="property", usage="", widget="String", required=false, def="CATEGORIE")
+String property
+
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+debug
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+// END OF PARAMETERS
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus)
+
+if (!AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)) {
+	println "** The $schema_ursql schema URSQL cannot be computed in the corpus."
+	return;
+}
+
+if (!AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, unit_ursql)) {
+	println "** $unit_ursql unit URSQL cannot be computed in the corpus."
+	return;
+}
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+def prop = corpus.getProperty(property)
+if (prop == null) {
+	analecCorpus.getStructure()
+}
+def schemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, 999999);
+def allFreqs = [:]
+def n = 0
+for (def schema : schemas) {
+	n++
+	
+	def freqs = [:]
+		
+	def allUnites = schema.getUnitesSousjacentesNonTriees()
+
+	def units = AnalecUtils.filterElements(debug, allUnites, unit_ursql)
+	
+	for (def unit : units) { // no need to sort units
+
+		String forme =  null;
+		if (prop == null) { // property is the analec unit property to use
+			forme = unit.getProp(property)
+		} else {
+			int[] pos = null;
+			if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+			else pos = unit.getDeb()..unit.getFin()
+				
+			forme = StringUtils.join(CQI.cpos2Str(prop.getQualifiedName(), pos), " ") // ids is enough
+		}
+		
+		if (!freqs.containsKey(forme)) freqs[forme] = 0;
+		freqs[forme] = freqs[forme] + 1;
+		
+		if (!allFreqs.containsKey(forme)) allFreqs[forme] = 0;
+		allFreqs[forme] = allFreqs[forme] + 1;
+	}
+	
+	if (schema_display_property_name != null) {
+		println "Index des natures de $unit_ursql de '"+schema.getProp(schema_display_property_name)+"' : "
+	} else {
+		println "Index des natures de $schema_ursql - $n : "
+	}
+	
+	int max = 0;
+	def result = "";
+	for (def forme : freqs.sort() { a, b -> -a.value <=> -b.value ?: a.key <=> b.key }) {
+		println forme.key+"\t"+forme.value
+	}
+}
+
+int max = 0;
+def result = "";
+
+println "Index des natures de $schema_ursql : "
+for (def forme : allFreqs.sort() { a, b -> -a.value <=> -b.value ?: a.key <=> b.key }) {
+	println forme.key+"\t"+forme.value
+	if (max < forme.value) {
+		max = forme.value
+		result = "$forme: "+forme.value
+	}
+}
+
+return ["result":result, "data":allFreqs]
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/check/CheckDuplicatesInSchemasMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/check/CheckDuplicatesInSchemasMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/check/CheckDuplicatesInSchemasMacro.groovy	(revision 3653)
@@ -0,0 +1,110 @@
+package org.txm.macro.urs.check
+
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+
+import groovy.transform.Field
+
+import org.jfree.chart.JFreeChart
+import org.kohsuke.args4j.*
+import org.txm.Toolbox
+import org.txm.annotation.urs.*
+import org.txm.macro.urs.AnalecUtils
+import org.txm.rcp.Application
+import org.txm.rcp.IImageKeys
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+
+import visuAnalec.elements.*
+
+def scriptName = this.class.getSimpleName()
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "** $scriptName please select a Corpus to run the macro"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=true, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="schema_property_display", usage="PROP", widget="String", required=true, def="REF")
+		String schema_property_display
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+if (!ParametersDialog.open(this)) return
+	if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+def corpus = corpusViewSelection
+
+def word = corpus.getWordProperty()
+def analecCorpus = URSCorpora.getCorpus(corpus)
+
+
+
+def errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)
+if (errors.size() > 0) {
+	println "** The $schema_ursql schema URSQL cannot be computed in the corpus with types: $errors."
+	return;
+}
+
+if (schema_property_display.length() > 0) {
+	errors = AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, AnalecUtils.getFilterParameters(schema_ursql)[0], schema_property_display).size()
+	if (errors > 0) {
+		println "Error: some Schema types don't contain the $schema_property_display property: $errors"
+		return
+	}
+}
+
+def allUnits = [:]
+
+def allSchemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus , schema_ursql, -1, Integer.MAX_VALUE, false)
+
+if (allSchemas.size() == 0) {
+	println "No schema match for '$schema_ursql' selection. Aborting"
+	return
+}
+
+allUnits = AnalecUtils.groupAllUnitesInElements(debug, allSchemas)
+
+if (allUnits.size() == 0) {
+	println "No unit selection. Aborting"
+	return
+}
+
+if (debug) println "allUnits=${allUnits.size()}"
+
+def duplicates = [:]
+for (Schema schema : allSchemas) {
+	def units = allUnits[schema];
+	for (def unit : units) {
+		if (!duplicates.containsKey(unit)) duplicates[unit] = []
+		duplicates[unit] << schema
+	}
+}
+
+def units = []
+units.addAll(duplicates.keySet()) // remove non duplicates from hash
+for (def unit : units) {
+	if (duplicates[unit].size() < 2) duplicates.remove(unit)
+}
+
+if (duplicates.size() > 0) {
+	println "${duplicates.size()} duplicates found"
+	for (def unit : duplicates.keySet()) {
+		println AnalecUtils.toString(CQI, word, unit)+" in: "
+		for (Schema schema : duplicates[unit]) {
+			println " '"+schema.getProp(schema_property_display)+"'\t"+schema.getProps()
+		}
+	}
+} else {
+	println "No duplicates found in $schema_ursql schema units"
+}
+
+return duplicates
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/check/CheckAnnotationStructureValuesMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/check/CheckAnnotationStructureValuesMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/check/CheckAnnotationStructureValuesMacro.groovy	(revision 3653)
@@ -0,0 +1,69 @@
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.check
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.elements.*
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+@Field @Option(name="unit_type",usage="", widget="String", required=false, def="MENTION")
+String unit_type
+
+@Field @Option(name="unit_property", usage="", widget="String", required=false, def="REF")
+String unit_property
+
+@Field @Option(name="pruneUnusedValues", usage="", widget="Boolean", required=false, def="false")
+boolean pruneUnusedValues
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return;
+
+// END OF PARAMETERS
+
+def corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus);
+def structure = analecCorpus.getStructure()
+
+def unit_types = structure.getTypes(Unite.class);
+if (!unit_types.contains(unit_type)) {
+	println "Missing unit type: $unit_type"
+	return
+}
+
+def props = analecCorpus.getStructure().getUniteProperties(unit_type);
+if (!props.contains(unit_property)) {
+	println "No properties '$unit_property' in '$unit_type' unit."
+	return
+}
+
+def prop  = unit_property
+	
+def tmpvalues = new HashSet()
+tmpvalues.addAll(structure.getValeursProp(Unite.class, unit_type, prop));
+println "Values stored in the structure: $tmpvalues"
+	
+def used_values = new HashSet();
+def unites = analecCorpus.getUnites(unit_type);
+for (Unite unite : unites) {
+	used_values.add(unite.getProp(prop))
+}
+	
+tmpvalues.removeAll(used_values);
+if (tmpvalues.size() > 0) {
+	println "The following values ("+tmpvalues.size()+") are not used: "+tmpvalues.join(", ")
+	if (pruneUnusedValues) {
+		println "Pruning the values..."
+		for (String val : tmpvalues) {
+			structure.supprimerVal(Unite.class, unit_type, unit_property, val);
+		}
+	} 
+} else {
+	println "All the values are used."
+}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Si2SingletonMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Si2SingletonMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Si2SingletonMacro.groovy	(revision 3653)
@@ -0,0 +1,85 @@
+// @author Bruno Oberlé
+// v1.0.0 20170711
+
+// Cette macro individualise tous les noms de référents "SI" en leur attribuant un numéro unique (SI_1, SI_2, etc.).
+
+package org.txm.macro.urs.democrat
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="ref_property_name", usage="", widget="String", required=true, def="REF")
+def ref_property_name
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+CQI = CQPSearchEngine.getCqiClient()
+word = corpus.getWordProperty()
+analecCorpus = URSCorpora.getCorpus(corpus)
+vue = URSCorpora.getVue(corpus)
+structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+
+if (!structure.getUniteProperties(unit_type).contains(ref_property_name)) {
+	println "Error: corpus structure does not contains property name=$unit_type"
+	return
+} 
+
+def nModified = 0
+def nIgnored = 0
+
+def units = analecCorpus.getUnites(unit_type)
+//units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+
+def refSet = new HashSet()
+for (Unite unit : units) { // process all units
+	def prop = unit.getProp(ref_property_name)
+	refSet.add(prop)
+}
+
+def counter = 1
+for (Unite unit : units) { // process all units
+	
+	def prop = unit.getProp(ref_property_name)
+	if (prop && prop == "SI") {
+		def name = "SI_" + counter
+		while (refSet.contains(name)) {
+			counter++
+			name = "SI_" + counter
+		}
+		counter++
+		//println "old prop"+ prop
+		unit.getProps().put(ref_property_name, name)
+		//println "new prop"+ name
+		nModified++
+	} else {
+		nIgnored++
+	}
+}
+
+println "Result:"
+println "- $nModified units of type $unit_type have been modified."
+println "- $nIgnored units of type $unit_type have not been modified.\n"
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/AjoutDefinitudeMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/AjoutDefinitudeMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/AjoutDefinitudeMacro.groovy	(revision 3653)
@@ -0,0 +1,117 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.democrat
+
+import org.apache.commons.lang.StringUtils;
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.Toolbox;
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.AbstractCqiClient;
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+import visuAnalec.Message.StructureEvent;
+import visuAnalec.Message.TypeModifStructure;
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.Unite;
+import visuAnalec.vue.Vue
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type",usage="", widget="String", required=true, def="MENTION")
+String unit_type
+@Field @Option(name="reset",usage="", widget="Boolean", required=true, def="false")
+boolean reset
+
+if (!ParametersDialog.open(this)) return;
+
+def corpus = corpusViewSelection
+AbstractCqiClient CQI = CQPSearchEngine.getCqiClient();
+def word = corpus.getWordProperty()
+def analecCorpus = URSCorpora.getCorpus(corpus);
+Structure structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+def props = structure.getUniteProperties(unit_type)
+
+String DEFINITUDE = "DEFINITUDE"
+if (!props.contains(DEFINITUDE)) { // update the structure if needed
+	analecCorpus.ajouterProp(Unite.class, unit_type, DEFINITUDE);
+	analecCorpus.ajouterVal(Unite.class, unit_type, DEFINITUDE, "DEFINI");
+	analecCorpus.ajouterVal(Unite.class, unit_type, DEFINITUDE, "INDEFINI");
+	analecCorpus.ajouterVal(Unite.class, unit_type, DEFINITUDE, "DEMONSTRATIF");
+	analecCorpus.ajouterVal(Unite.class, unit_type, DEFINITUDE, "AMBIGU");
+	analecCorpus.ajouterVal(Unite.class, unit_type, DEFINITUDE, "NONE");
+}
+Vue vue = URSCorpora.getVue(corpus)
+if (!vue.getTypesAVoir(Unite.class).contains(unit_type)) {
+	vue.ajouterType(Unite.class, unit_type)
+}
+if (!vue.getNomsChamps(Unite.class, unit_type).contains(DEFINITUDE)) {
+	vue.ajouterProp(Unite.class, unit_type, DEFINITUDE)
+}
+
+int nIgnored = 0 // number of ignored units
+int nModified = 0 // number of modified units
+int nDefini = 0 // number of "DEFINI" units
+int nIndefini = 0 // number of "InDEFINI" units
+int nDemonstratif = 0 // number of "DEMONSTRATIF" units
+int nAmbigu = 0 // number of "AMBIGU" units
+int nNone = 0 // number of "NONE" units
+
+def units = analecCorpus.getUnites(unit_type)
+units = units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+for (Unite unit : units) { // process all units
+	
+	def prop = unit.getProp(DEFINITUDE);
+	
+	int[] pos = null
+	if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+	else pos = (unit.getDeb()..unit.getFin())
+	def form = StringUtils.join(CQI.cpos2Str(word.getQualifiedName(), pos), " ")
+	
+	if (reset || prop == null || prop.length() == 0 || prop.equals("NONE")) {
+		// petits ajouts à faire ? : |(ses\s.+)|(Ses\s.+)|(son\s.+)|(Son\s.+)|(sa\s.+)|(Sa\s.+)|(leurs?\s.+)|(Leurs?\s.+)|(tous\s.+)|(Tous\s.+)|(toutes\s.+)|(Toutes\s.+)
+		if (form =~ /^(le\s.+)|(Les\s.+)|(Le\s.+)|(la\s.+)|(La\s.+)|(l'.+)|(L'.+)|(les\s.+)|(au\s.+)|(Au\s.+)|(aux\s.+)|(Aux\s.+)|(du\s.+)|(Du\s.+)/) {
+			unit.getProps().put(DEFINITUDE, "DEFINI")
+			nDefini++
+		} else if (form =~ /^(un\s.+)|(une\s.+)|(Un\s.+)|(Une\s.+)|(Chaque\s.+)|(chaque\s.+)|(Certains\s.+)|(Certaines\s.+)|(certains\s.+)|(certaines\s.+)|(aucun\s.+)|(aucune\s.+)|(Aucun\s.+)|(Aucunes\s.+)|(Autre\s.+)|(Autre\s.+)|(autres\s.+)|(autre\s.+)|(quelque\s.+)|(quelques\s.+)|(Quelque\s.+)|(Quelques\s.+)/) {
+			unit.getProps().put(DEFINITUDE, "INDEFINI")
+			nIndefini++
+		} else if (form =~ /^(ce\s.+)|(cette\s.+)|(Cette\s.+)|(cet\s.+)|(ces\s.+)|(Ce\s.+)|(Cet\s.+)|(Ces\s.+)/) {
+			unit.getProps().put(DEFINITUDE, "DEMONSTRATIF")
+			nDemonstratif++
+		} else if (form =~ /^(des\s.+)|(de\s.+)|(Des\s.+)|(De\s.+)/) {
+			unit.getProps().put(DEFINITUDE, "AMBIGU")
+			nAmbigu++
+		} else {
+			unit.getProps().put(DEFINITUDE, "NONE")
+			nNone++;
+		}
+		nModified++
+		
+	} else {
+		// nothing to do
+		nIgnored++
+	}
+}
+
+println "nIgnored=$nIgnored"
+println "nModified=$nModified"
+println " nDefini=$nDefini"
+println " nIndefini=$nIndefini"
+println " nDemonstratif=$nDemonstratif"
+println " nAmbigu=$nAmbigu"
+println " nNone=$nNone"
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Frpos2CattexMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Frpos2CattexMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Frpos2CattexMacro.groovy	(revision 3653)
@@ -0,0 +1,275 @@
+// @author Matthieu Quignard
+// Date : 04 Mai 2017
+
+/*
+Définit la catégorie grammaticale des mentions d'après le champ `frpos'
+(tagset de TreeTagger). 
+
+La liste des catégories grammaticales est celle de CATTEX2009
+-- Groupes nominaux :
+	GN.NAM (noms propres) : Henri II
+	GN.DEF (définis) : Le roi, du roi
+	GN.IND (indéfinis) : Un roi
+	GN.POS (possessifs) : [Mon roi]
+	GN.DEM (demonstratif) : Ce roi
+	GN.NUM (numéraux) : Deux rois
+	GN.CHECK (GN indéterminés)
+-- Déterminants
+	DET.POS (possessifs) : [mon] roi
+-- Pronoms
+	PRO.PER (personnels) : je, moi, me, on, il, etc.
+	PRO.ADV (adverbiaux) : y, en
+	PRO.IND (indéfinis) : tout, tous, certains, plusieurs, etc.
+	PRO.DEM (demonstratifs) : ceci, cela, ce, ça...
+	PRO.POS (possessifs) : le mien, les nôtres...
+	PRO.NUM (cardinaux, ordinaux) : les deux...
+	PRO.REL (relatifs) : qui, que, quoi, duquel, etc.
+	PRO.INT (interrogatifs)
+	PRO.CHECK (pronoms indéterminés)
+-- Sujet Zéro : verbes conjugués, éventuellement pronominal
+
+-- ERREUR : erreur (a priori) de mention
+
+	
+*/
+
+package org.txm.macro.urs.democrat
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+// Propriété donnant le lemme
+def lemmaProperty = "frlemma"
+
+/*
+   TODO : TreeTagger fait un mauvais étiquetage des premiers mots de la phrase.
+   La majuscule lui fait croire qu'il s'agit d'un nom propre.
+   Vérifier que ce mot n'est pas en fait un pronom en testant sa présence dans une des listes de formes particulières 
+*/
+
+
+/**
+  * Liste de formes utile à la catégorisation des mentions
+  * TreeTagger n'est pas forcément très performant sur des états plus anciens de la langue
+***/  
+
+formesArticlesDéfinis = ["le", "la", "les", "l'", "au", "aux", "du", "des"]
+formesArticlesIndéfinis = ["un", "une", "des"]
+formesDéterminantsPossessifs = ["ma", "ta", "sa", "mon", "ton", "son", "mes", "tes", "ses", "notre", "votre", "leur", "nos", "vos", "leurs"]
+formesAdjectifsDémonstratifs = ["ce", "cet", "cette", "ces"]
+
+formesPronomsPersonnels = ["je", "tu", "il", "elle", "on", "nous", "vous", "ils", "elles", "moi", "toi", "eux", "me", "te", "se", "lui", "leur"]
+formesPronomsAdverbiaux = ["en", "y"]
+formesPronomsPossessifs = ["mien", "mienne", "miens", "miennes", "tien", "tienne", "tiens", "tiennes", "sien", "sienne", "siens", "siennes", "nôtre", "nôtres", "vôtre", "vôtres", "leur", "leurs"]
+formesPronomsDémonstratifs = ["ce", "c'", "celui", "celle", "ceux", "celles", "ci", "ça", "ceci", "cela", "tel", "telle", "tels", "telles"]
+
+toutesLesFormes = []
+toutesLesFormes += formesArticlesDéfinis
+toutesLesFormes += formesArticlesIndéfinis
+toutesLesFormes += formesDéterminantsPossessifs
+toutesLesFormes += formesAdjectifsDémonstratifs
+toutesLesFormes += formesPronomsPersonnels
+toutesLesFormes += formesPronomsAdverbiaux
+toutesLesFormes += formesPronomsPossessifs
+toutesLesFormes += formesPronomsDémonstratifs
+
+/** Fin de la déclaration des formes **/
+
+
+
+def testRules(def positions, def Mention) {
+	def catégorie = null
+    def forme = CQI.cpos2Str(word.getQualifiedName(), positions)[0].toLowerCase()
+    
+	if (Mention.length == 1) {    
+	    
+		     if (Mention.first() == "NAM"    ) catégorie = "GN.NAM"
+		else if (Mention.first() == "DET:POS") catégorie = "DET.POS"
+		else if (Mention.first() == "PRO:PER") {
+			if (formesPronomsAdverbiaux.contains(forme)) catégorie = "PRO.ADV"
+			else catégorie = "PRO.PER"
+		}
+		else if (Mention.first() == "PRO:DEM") catégorie = "PRO.DEM"
+		else if (Mention.first() == "PRO:IND") catégorie = "PRO.IND"
+		else if (Mention.first() == "PRO:REL") catégorie = "PRO.REL"
+		else if (Mention.first().contains("VER:")) catégorie = "SUJ.ZERO"
+		else if (Mention.first() == "PRO") catégorie = "PRO.INT"
+		
+		// GN indéfinis sans articles
+		else if (Mention.first() == "NOM") catégorie = "GN.IND"
+		else if (Mention.first() == "ADJ") catégorie = "GN.IND"
+		
+		// gestion des erreurs de TreeTagger
+		else if (Mention.first() == "KON") catégorie = "PRO.REL" // Le 'que' dans une mention simple est un relatif
+		else if (Mention.first() == "DET:ART") catégorie = "PRO.PER" // le, les
+		else if (forme == "en") catégorie = "PRO.ADV"
+		
+		else if (Mention.first() == "ADV") catégorie = "ERREUR"  // un adverbe seul n'est jamais référentiel
+		else if (Mention.first() == "PRE") catégorie = "ERREUR"  // une preposition seule n'est jamais référentielle
+		else if (Mention.first() == "ADJ") catégorie = "ERREUR"  // un adjectif seul n'est jamais référentiel
+		else if (Mention.first() == "INT") catégorie = "ERREUR"  // une interjection seule n'est jamais référentielle
+		
+		else catégorie = "PRO.CHECK"		
+	} 
+	
+	else if (Mention.length == 2) {
+		     if (Mention.contains("NAM")) catégorie = "GN.NAM"
+		else if (Mention[1] == "PRO:POS") catégorie = "PRO.POS"  // "les miens"
+		else if (Mention[1] == "NUM"    ) catégorie = "PRO.NUM"  // "les deux"
+		else if (Mention[1] == "PRO:DEM") catégorie = "PRO.DEM"  // "Tout cela"
+		else if (Mention[0] == "PRO:IND") catégorie = "GN.IND"   // "Quelques trucs"
+		else if (Mention.contains("PRO:REL")) catégorie = "PRO.REL"
+		else if ((Mention[0].contains("DET")) && (Mention[1] == "PROind")) catégorie = "PRO.IND" // des autres
+		else if (Mention[1].contains("VER:")) catégorie = "SUJ.ZERO"
+		else if (!Mention.contains("NOM") && !Mention.contains("ADJ")) {
+			if (Mention[0] == "PRO:DEM") catégorie = "PRO.DEM"
+			else catégorie = "PRO.CHECK"
+		}
+		else catégorie = "GN.CHECK"            
+	} 
+	
+	if ( (catégorie == null) || (catégorie == "GN.CHECK") ) {
+		// on est dans les GN
+		     if (Mention[0] == "DET:POS" ) catégorie = "GN.POS"
+		else if (Mention[0] == "NUM"     ) catégorie = "GN.NUM"
+		else if (Mention[0] == "PRO:DEM" ) catégorie = "GN.DEM"
+		else if (Mention[0] == "PRP:det" ) catégorie = "GN.DEF"
+		else if (formesArticlesIndéfinis.contains(forme) || (forme == "une")) catégorie = "GN.IND" 
+		else if (formesArticlesDéfinis.contains(forme))   catégorie = "GN.DEF"
+		else if (Mention[0] == "PRO:IND" ) catégorie = "GN.IND"
+		else if (Mention[0] == "PRP" ) catégorie = "GN.IND"
+		else if (Mention[0] == "ADJ" ) catégorie = "GN.IND"
+		else if (Mention[0] == "NOM" ) catégorie = "GN.IND"		
+		else if (Mention.contains("NAM")) catégorie = "GN.NAM"
+		else catégorie = "TEST"
+	}
+		
+	return catégorie
+}
+
+//
+// FIN DE LA DÉFINITION DES RÈGLES
+//
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="pos_property_name", usage="", widget="String", required=true, def="pos")
+def pos_property_name
+@Field @Option(name="reset", usage="", widget="Boolean", required=true, def="true")
+def reset
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+CQI = CQPSearchEngine.getCqiClient()
+word = corpus.getWordProperty()
+posProperty = corpus.getProperty(pos_property_name)
+if (posProperty == null) {
+	println "Error: CQP corpus does not contains the word property with name=$pos_property_name"
+	return
+}
+analecCorpus = URSCorpora.getCorpus(corpus)
+vue = URSCorpora.getVue(corpus)
+structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+
+CATEGORIE = "CATEGORIE"
+// Si la structure d'annotation ne contient pas CATEGORIE, on la crée avec ses valeurs
+if (!structure.getUniteProperties(unit_type).contains(CATEGORIE)) { 
+
+// FIXME: dans le script original (see also
+// http://forge.cbp.ens-lyon.fr/redmine/issues/2065), on utilise
+// analecCorpus.ajouterProp/Val, mais cela ne marche pas dans ma version de
+// TXM-Analec --> je retourne donc à structure.ajouterProp/Val
+
+// la propriété
+	structure.ajouterProp(Unite.class, unit_type, CATEGORIE)
+// les valeurs
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN.NAM")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN.DEF")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN.IND")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN.POS")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN.DEM")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN.NUM")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN.CHECK")
+	
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "DET.POS")
+	
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.PER")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.ADV")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.IND")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.DEM")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.POS")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.NUM")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.INT")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.REL")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.CHECK")
+	
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "SUJ.ZERO")
+	
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "ERREUR")
+}
+
+if (!vue.getTypesAVoir(Unite.class).contains(unit_type)) {
+	vue.ajouterType(Unite.class, unit_type)
+}
+if (!vue.getNomsChamps(Unite.class, unit_type).contains(CATEGORIE)) {
+	vue.ajouterProp(Unite.class, unit_type, CATEGORIE)
+}
+
+def nModified = 0
+def nIgnored = 0
+
+errors = new HashMap()
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+for (Unite unit : units) { // process all units
+	
+	def prop = unit.getProp(CATEGORIE)
+	if (!reset && prop != null && prop.length() > 0) continue // l'unité a déjà une CATEGORIE
+	
+	int[] positions = null
+	if (unit.getDeb() == unit.getFin()) positions = [unit.getDeb()]
+	else positions = (unit.getDeb()..unit.getFin())
+	
+	def Mention = CQI.cpos2Str(posProperty.getQualifiedName(), positions)
+	def cat = testRules(positions, Mention)
+
+	if (cat != null) {
+		// following line in the original script but doesn't work for me:
+      // vue.setValeurChamp(unit, CATEGORIE, cat)
+      unit.getProps().put(CATEGORIE, cat)
+		nModified++
+	} else {
+		nIgnored++
+	}
+}
+
+println "Result:"
+println "- $nModified units of type $unit_type have been modified."
+println "- $nIgnored units of type $unit_type have not been modified.\n"
+
+if (errors.size() > 0) {
+	println "Some rules should be added to this macro to process the following remaining 'FROPOS / words' values:"
+	errors.keySet().each { println "fropos="+it+"\twords="+errors[it].join(" | ") }
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/SubCorpusMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/SubCorpusMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/SubCorpusMacro.groovy	(revision 3653)
@@ -0,0 +1,74 @@
+package org.txm.macro.urs.democrat;
+
+	// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+	// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+	// @author mdecorde
+	// @author sheiden
+	
+	
+	import org.kohsuke.args4j.*
+	import groovy.transform.Field
+	import org.txm.rcpapplication.swt.widget.parameters.*
+	import org.txm.searchengine.cqp.*
+	import org.txm.searchengine.cqp.corpus.*
+	import org.txm.searchengine.cqp.corpus.query.*
+	import org.txm.*
+	import org.txm.rcpapplication.views.*
+	
+	// BEGINNING OF PARAMETERS
+	
+	// Declare each parameter here
+	// (available widget types: Query, File, Folder, String, Text, Boolean, Integer, Float and Date)
+	
+	@Field @Option(name="name", usage="name of the subcorpus result", widget="String", required=true, def="subcorpus1")
+	def name
+	
+	@Field @Option(name="query", usage="query to build subcorpus", widget="String", required=true, def="n:[] :: n = 0 expand to 10")
+	def query
+	/*
+	
+	n:[] [] [] [] [] [] [] [] [] [] :: n = 0
+	n:[] :: n = 0 expand to 10
+	
+	*/
+	
+	// Open the parameters input dialog box
+	if (!ParametersDialog.open(this)) return false
+	
+	def CQI = CQPSearchEngine.getCqiClient()
+	
+	def scriptName = this.class.getSimpleName()
+	
+	def utils = new org.txm.macro.urs.exploit.CQPUtils()
+	
+	def corpora = utils.getCorpora(this)
+	
+	if ((corpora == null) || corpora.size() == 0) {
+		println "** $scriptName: please select a corpus in the Corpus view or provide a corpus name. Aborting."
+		return false
+	}
+	
+	/*
+	CorpusManager.getCorpusManager().getCorpora().each {
+		if (it.getSubcorpusByName(name)) {
+			println "** Subcorpus: sub-corpus name already used. Please use another sub-corpus name. Aborting."
+			return false
+		}
+		// it.getSubcorpora().each { sub -> println it.getName()+" subcorpora: "+sub.getName() }
+	}
+	*/
+	
+	String resultCqpId = CqpObject.subcorpusNamePrefix + CQPCorpus.getNextSubcorpusCounter()
+	String queryString = "$resultCqpId=$query;"
+	
+	CQI.query(queryString)
+	
+	def subcorpus = corpora[0].createSubcorpus(new CQLQuery("$query;"), name)
+	
+	if (binding.variables["monitor"]) {
+		utils.refreshCorpusViewExpand(monitor, subcorpus.getParent())
+	}
+	
+	return true
+
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/PROPERanaphoriquesMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/PROPERanaphoriquesMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/PROPERanaphoriquesMacro.groovy	(revision 3653)
@@ -0,0 +1,121 @@
+package org.txm.macro.urs.democrat
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+/*
+   Distingue les Pronoms Personnels Anaphoriques (PRO.PERA) des Pronoms Personnels Déictiques (PRO.PERD)
+   PRO.PERD = frlemma(je|me|moi|tu|te|toi|nous|vous)
+   On rajoute aussi quelques graphies anciennes que TreeTagger ne connaît pas forcément.
+   Inutile de différencier minuscules et majuscules. Le test gère cela très bien.
+   Auteur : Matthieu Quignard (ICAR)
+   Date : 19/12/2017
+ */
+
+listeLemmesDeictiques = ["je", "me", "moi", "tu", "te", "toi", "nous", "vous"]
+listeFormesDeictiques = ["moy", "toy"]
+
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="pos_property_name", usage="", widget="String", required=true, def="frlemma")
+def pos_property_name
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+CQI = CQPSearchEngine.getCqiClient()
+word = corpus.getWordProperty()
+posProperty = corpus.getProperty(pos_property_name)
+if (posProperty == null) {
+	println "Error: CQP corpus does not contains the word property with name=$pos_property_name"
+	return
+}
+analecCorpus = URSCorpora.getCorpus(corpus)
+vue = URSCorpora.getVue(corpus)
+structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+
+CATEGORIE = "CATEGORIE"
+structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.PERA")
+structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.PERD")
+
+if (!vue.getTypesAVoir(Unite.class).contains(unit_type)) {
+	vue.ajouterType(Unite.class, unit_type)
+}
+if (!vue.getNomsChamps(Unite.class, unit_type).contains(CATEGORIE)) {
+	vue.ajouterProp(Unite.class, unit_type, CATEGORIE)
+}
+
+def nModified = 0
+def nIgnored = 0
+def nProPerA = 0
+def nProPerD = 0
+
+errors = new HashMap()
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+
+for (Unite unit : units) { // process all units
+	def prop = unit.getProp(CATEGORIE)
+	
+	if ( (prop == null) || (!prop.contains("PRO.PER")) ) {
+		// On ne s'intéresse qu'aux pronoms personnels (PRO.PER)
+		// Les autres sont ignorés
+		nIgnored++
+	} else {
+		// Pour les mentions de type "PRO.PER", on cherche le premier mot
+		int[] positions = null
+		if (unit.getDeb() == unit.getFin()) positions = [unit.getDeb()]
+		else positions = (unit.getDeb()..unit.getFin())
+	
+		// On récupère le lemme du premier mot
+		def tags = CQI.cpos2Str(posProperty.getQualifiedName(), positions)
+		def firstTag = tags[0];
+		
+		// On récupère la forme du premier mot en minuscule
+		def forme = CQI.cpos2Str(word.getQualifiedName(), positions)[0].toLowerCase()
+		
+		if (listeLemmesDeictiques.contains(firstTag)) {
+			// Si le lemme est dans la liste de déictiques, on recatégorise en PRO.PERD
+			vue.setValeurChamp(unit, CATEGORIE, "PRO.PERD")
+			nProPerD++
+		} else if (listeFormesDeictiques.contains(forme)) {
+			// Si la forme du premier mot dans la liste des formes des déictiques, on recatégorise en PRO.PERD
+			vue.setValeurChamp(unit, CATEGORIE, "PRO.PERD")
+			nProPerD++
+		} else {
+			// Sinon on recatégorise en PRO.PERA
+			vue.setValeurChamp(unit, CATEGORIE, "PRO.PERA")
+			nProPerA++
+		}
+		nModified++
+	}
+}
+
+println "Result:"
+println "- $nModified units of type $unit_type have been modified."
+println "- $nIgnored units of type $unit_type have not been modified.\n"
+
+println "- $nProPerA mentions de ProPer anaphoriques."
+println "- $nProPerD mentions de ProPer déictiques."
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Verification.txt
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Verification.txt	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Verification.txt	(revision 3653)
@@ -0,0 +1,26 @@
+Macro Verification
+auteur : matthieu quignard
+
+Se lance après l'annotation des mentions en référence et en catégories.
+On a besoin de catégories pour repérer les erreurs de type 1, 3, 4 et 7.
+
+Vérifie les erreurs les plus fréquentes :
+1. Repère les mentions sans catégorie : CHECK > CAT
+2. Repère les mentions sans référent : CHECK > REF
+3. Supprime les ponctuations en début et en fin de mention : CHECK > BORNES
+4. Supprime les prépositions autres que 'de' en début de mention : CHECK > BORNES
+5. Supprime automatiquement toutes les mentions vides = sans aucun mot = de longueur 0
+6. Détecter les mentions qui ont exactement les mêmes bornes  : CHECK > DOUBLON
+7 (option). Détecter les pronoms hors mention : CHECK > NEW
+
+Nécessite de renseigner : 
+- le nom des unités à vérifier (MENTION)
+- le nom de la propriété catégorie à vérifier (CATEGORIE)
+- le nom de la propriété référent à vérifier (REF)
+- le nom du champ qui porte l'étiquette morphosyntaxique (type, pos, frpos, fropos...)
+
+Cocher "checkPronouns" si on veut rajouter les éventuels pronoms oubliés (= hors mention).
+
+Le script ajoute une propriété CHECK en cas d'erreur.
+Cette propriété qui indique quel type d'erreur a été rencontré. 
+NB : il peut y avoir plusieurs erreurs pour une même mention.

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Verification.txt
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Metadata2TEIHeader.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Metadata2TEIHeader.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Metadata2TEIHeader.groovy	(revision 3653)
@@ -0,0 +1,264 @@
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.democrat
+
+import java.nio.charset.Charset
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import net.sf.saxon.functions.IndexOf
+
+import org.txm.importer.StaxIdentityParser
+import org.txm.objects.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.utils.CsvReader
+import org.txm.utils.io.IOUtils
+import org.txm.scripts.importer.XPathResult
+import javax.xml.xpath.XPathConstants
+
+class Metadata2TEIHeader {
+	
+	int debug = 0;
+	public Metadata2TEIHeader(int debug) {
+		this.debug = debug
+	}
+	//@Field @Option(name="teiHeaderTemplateFile", usage="the default teiHeader of texts", widget="FileOpen", required=true, def="teiHeaderTemplateFile.xml")
+	//def teiHeaderTemplateFile
+	//
+	//@Field @Option(name="xpathFile", usage="properties file to redirect metadata column to the teiHeader locations", widget="FileOpen", required=true, def="xpathFile.properties")
+	//def xpathFile
+	//
+	//@Field @Option(name="metadataFile", usage="the TSV file containing the metadata values per text", widget="FileOpen", required=true, def="metadataFile.tsv")
+	//def metadataFile
+	//
+	//@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+	//debug
+	//
+	//if (!ParametersDialog.open(this)) return;
+	//if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+	//
+	//def xpathProperties = new Properties()
+	//xpathProperties.load(IOUtils.getReader(xpathFile))
+	//println xpathProperties
+	//
+	//def csvReader = new CsvReader(metadataFile.getAbsolutePath(), "\t".charAt(0), Charset.forName("UTF-8"))
+	//println csvReader
+	//
+	//csvReader.readHeaders();
+	//def header = csvReader.getHeaders()
+	//if (!header.contains("id")) {
+	//	println "** 'id' column not found in $metadataFile header=$header"
+	//	return;
+	//}
+	//if (!header.contains("corpus_id")) {
+	//	println "** 'corpus_id' column not found in $metadataFile header=$header"
+	//	return;
+	//}
+	//
+	//def corpora = [:]
+	//for (Project project : Workspace.getInstance().getProjects()) {
+	//	for (MainCorpus corpus : project.getChildren(MainCorpus.class)) {
+	//		corpora[corpus.getID()] = corpus;
+	//	}
+	//}
+	//
+	//while (csvReader.readRecord())	{
+	//	String text_id = csvReader.get("id")
+	//	if (text_id == null || text_id.length() == 0) {
+	//		//println "** @id not found for record="+csvReader.getRawRecord()
+	//		continue;
+	//	}
+	//
+	//	String corpus_id = csvReader.get("corpus_id")
+	//	if (corpus_id == null || corpus_id.length() == 0) {
+	//		println "** @corpus_id not found for record="+csvReader.getRawRecord()
+	//		continue;
+	//	}
+	//
+	//	MainCorpus corpus = corpora[corpus_id]
+	//	if (corpus == null) {
+	//		println "** no corpus found for ID=$corpus_id"
+	//		continue;
+	//	}
+	//	def project = corpus.getProject()
+	//
+	//	def txmDir = new File(project.getProjectDirectory(), "txm/"+corpus.getID())
+	//
+	//	if (!txmDir.exists()) {
+	//		println "** the selected corpus has no XML-TXM files. Aborting."
+	//	}
+	//
+	//
+	//	File txmFile = new File(txmDir, text_id+".xml")
+	//	if (txmFile.exists()) {
+	//
+	//		def data = [:]
+	//
+	//		for (def h : header) data[h] = csvReader.get(h)
+	//
+	//		String xmlteiHeaderContent = getCustomizedTEiHeader(teiHeaderTemplateFile, data, xpathProperties);
+	//		if (xmlteiHeaderContent != null && xmlteiHeaderContent.length() > 0) {
+	//			injecting(txmFile, xmlteiHeaderContent)
+	//		} else {
+	//			println "** Text header not updated: $txmFile"
+	//		}
+	//	} else {
+	//		println "** Text not found: $txmFile"
+	//	}
+	//}
+
+	def getCustomizedTEiHeader(File teiHeaderTemplateFile, def data, Properties xpathProperties) {
+		XPathResult xpathProcessor = new XPathResult(teiHeaderTemplateFile);
+		for (String info : data.keySet()) {
+			String xpath = xpathProperties[info];
+			String value = data[info]
+			if (xpath == null) {
+				continue; // not a data to inject
+			}
+			if (debug > 1) println "   injecting '$info'='$value' in '$xpath'"
+
+			def expr = xpathProcessor.xpath.compile(xpath);
+			def first = expr.evaluate(xpathProcessor.doc.getDocumentElement(), XPathConstants.NODE);
+			if (first != null) {
+				switch (first.getNodeType()) {
+					case 1: // element
+						if (debug > 1) println "   patching: $info with "+value
+						def newChild = xpathProcessor.doc.createElement(first.getTagName())
+						newChild.appendChild(xpathProcessor.doc.createTextNode(value))
+						
+						def attributes = first.getAttributes();
+						for (int i = 0 ; i < attributes.getLength() ; i++) { // copy attributes
+							def attr = attributes.item(i)
+							newChild.setAttribute(attr.getNodeName(), attr.getNodeValue())
+						}
+						
+						first.getParentNode().replaceChild(newChild, first)
+						break;
+					case 2: // attribute
+						if (debug > 1) println "   patching attribute: $info with "+value
+						first.setNodeValue(value)
+						break;
+					case 3: // text
+						if (debug > 1) println "   patching text: $info with "+value
+						first.setNodeValue(value)
+						break;
+					default:
+						break
+				}
+			} else {
+				//try finding parent and add a new node
+				String attribute_xpath = null;
+				if (xpath.lastIndexOf("/@") > 0) {
+					attribute_xpath = xpath.substring(xpath.lastIndexOf("/@")+2)
+					xpath = xpath.substring(0, xpath.lastIndexOf("/@"))
+				}
+				String parent_xpath = xpath.substring(0, xpath.lastIndexOf("/"))
+				String element_xpath = xpath.substring(xpath.lastIndexOf("/")+1)
+				def parent_expr = xpathProcessor.xpath.compile(parent_xpath);
+				def parent = parent_expr.evaluate(xpathProcessor.doc.getDocumentElement(), XPathConstants.NODE);
+				if (parent != null) {
+					String namespace = element_xpath.substring(element_xpath.indexOf(":"))
+					String nodename = element_xpath.substring(element_xpath.indexOf(":")+1)
+					def attributes = [:]
+					if (nodename.contains("[")) {
+						
+						String attributesString = nodename.substring(nodename.indexOf("[")+1, nodename.length()-1)
+						for (String attributeString : attributesString.split(",")) {
+							def split = attributeString.split("=")
+							attributes[split[0].substring(1)] = split[1].substring(1, split[1].length()-1) // remove @ and remove ""
+						}
+						nodename = nodename.substring(0, nodename.indexOf("["))
+					}
+					def newChild = xpathProcessor.doc.createElement(nodename)
+					for (String attributeName : attributes.keySet()) {
+						newChild.setAttribute(attributeName, attributes[attributeName])
+					}
+					
+					if (attribute_xpath != null) {
+						newChild.setAttribute(attribute_xpath, value)
+					} else {
+						newChild.appendChild(xpathProcessor.doc.createTextNode(value))
+					}
+					
+					if (debug > 1) println "  creating node $parent_xpath / $nodename[$attributes] : $attribute_xpath = $value"
+					parent.appendChild(newChild)
+				} else {
+					println " ** info=$info not found or created for "+xpathProperties[info]
+				}
+			}
+		}
+
+		//	return xpathProcessor.doc.getElementsByTagName("teiHeader").item(0).getNodeValue();
+		//println "DOC="+xpathProcessor.doc.getDocumentElement().getElementsByTagName("teiHeader").item(0).toString()
+		String content = ""+xpathProcessor.doc.getDocumentElement().getElementsByTagName("teiHeader").item(0)
+		content = content.substring('<?xml version="1.0" encoding="UTF-8"?>'.length())
+	}
+
+	/**
+	 * Replace the teiHeader 
+	 * @param txmFile
+	 * @param data
+	 * @param paths
+	 * @param xmlteiHeaderContent
+	 * @return
+	 */
+	def replaceHeader(File txmFile, String xmlteiHeaderContent) {
+		println " editing: $txmFile..."
+		StaxIdentityParser sparser = new StaxIdentityParser(txmFile) {
+					boolean start = false;
+					public void processStartElement() {
+
+						if (localname == "teiHeader") {
+							start = true;
+							if (debug > 2) println "   replacing teiHeader"
+							if (debug > 3) println "       with $xmlteiHeaderContent"
+							output.write(xmlteiHeaderContent.getBytes(Charset.forName("UTF-8")));  // REPLACE CONTENT !
+						}
+						if (!start) {
+							super.processStartElement();
+						}
+					}
+
+					public void processEndElement() {
+						if (!start) {
+							super.processEndElement();
+						}
+						if (localname == "teiHeader") {
+							start = false;
+							if (debug > 2) println "   replace done"
+						}
+					}
+
+					public void processCharacters() {
+						if (!start) {
+							super.processCharacters();
+						}
+					}
+
+					public void processComment() {
+						if (!start) {
+							super.processComment();
+						}
+					}
+				}
+
+		File outfile = new File("tmp_"+txmFile.getName())
+		if (sparser.process(outfile)) { // replace inputFile
+				txmFile.delete()
+				if (outfile.renameTo(txmFile)) {
+					println " -> SUCCESS see $txmFile"
+					return true
+				} else {
+					println " -> FAIL could not rename $outfile $txmFile"
+					println "    $outfile exists ? "+outfile.exists()
+					println "    $txmFile exists ? "+txmFile.exists()
+					println " -> see result in $outfile"
+				}
+
+		} else {
+			println " -> FAIL see $outfile"
+		}
+
+		return false;
+	}
+}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/ComputeDemocratMeasureMetadata.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/ComputeDemocratMeasureMetadata.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/ComputeDemocratMeasureMetadata.groovy	(revision 3653)
@@ -0,0 +1,52 @@
+package org.txm.macro.urs.democrat
+
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.txm.searchengine.cqp.corpus.MainCorpus
+import org.txm.searchengine.cqp.corpus.StructuralUnit
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+import visuAnalec.donnees.Corpus
+import org.txm.annotation.urs.URSCorpora
+import org.txm.properties.core.functions.*
+
+class ComputeDemocratMeasureMetadata {
+	
+	def ignored = ["txmcorpus", "text", "body"]
+	
+	def getStats(MainCorpus corpus, def xpathProperties) {
+		def data = [:]
+		
+		data["number of words"] = corpus.query(new CQLQuery("[]"), "TMP", false).getNMatch();
+		
+		Corpus analecCorpus = URSCorpora.getCorpus(corpus);
+		def chaines = analecCorpus.getSchemas("CHAINE");
+		def refchaines = [];
+		for (def chaine : chaines) {
+			if (chaine.getUnitesSousjacentes().length >= 3) {
+				refchaines << chaine
+			}
+		}
+		data["number of coreference chains"] = chaines.size()
+		data["number of referring chains"] = refchaines.size()
+		data["number of referring expressions"] = analecCorpus.getUnites("MENTION").size()
+		
+		// add default xpaths for measures
+		for (String s : ["number of words", "number of coreference chains", "number of referring chains", "number of referring expressions"]) {
+			if (!xpathProperties.containsKey(s)) {
+				xpathProperties.put(s,"/tei:TEI/tei:teiHeader/tei:fileDesc/tei:extent/tei:measure[@unit=\"$s\"]/@quantity")
+			}
+		}
+		
+		// add structure measures
+		for (StructuralUnit su : corpus.getStructuralUnits()) {
+			if (!ignored.contains(su.getName())) {
+				String s = "structure "+su.getName()
+				data[s] = corpus.query(new CQLQuery("<"+su.getName()+">[]"), "TMP", false).getNMatch();
+				if (!xpathProperties.containsKey(s)) {
+					xpathProperties.put(s,"/tei:TEI/tei:teiHeader/tei:fileDesc/tei:extent/tei:measure[@unit=\"$s\"]/@quantity")
+				}
+			}
+		}
+		
+		return data
+	}
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Frpos2CategorieMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Frpos2CategorieMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Frpos2CategorieMacro.groovy	(revision 3653)
@@ -0,0 +1,258 @@
+// @author Bruno Oberlé (2017-04-01 21:50)
+
+/*
+Définit la catégorie grammaticale du maillon d'après le champ `frpos'
+(tagset de TreeTagger).  Le script est adapté de
+http://svn.code.sf.net/p/txm/code/trunk/plugins/Analec/AnalecRCP/src/org/txm/macro/analec/Fropos2CategorieMacro.groovy.
+
+Voici la liste des catégories grammaticales retenues (manuel d'annotation de
+Democrat):
+- GN: Groupe Nominal (le petit chat, le chat, le même, ce chat etc.)
+- POSS: Possessif (mon, ton son, ma, ta, sa, mes, tes, ses, notre, votre,
+  leur, nos, vos, leurs)
+- PR: Pronom (moi, toi, lui, elle, nous, vous, eux, elles, le tien, le mien,
+  moi-même etc.)
+- PR_CL_O: Pronom Clitique Objet (me, te, le, la, les, lui, leur, y, en)
+- PR_CL_R: Pronom Clitique Réfléchi
+- PR_CL_S: Pronom Clitique Sujet (je, tu, il, elle, on, nous, vous, ils,
+  elles)
+- PR_REL: Pronom Relatif (qui, que, quoi, dont, où, lequel, quiconque etc.)
+- PR_WH: Pronom Interrogatif (qui, que, quoi, lequel etc.)
+
+Le script ne peut pas désambiguïser les pronoms clitiques de même forme
+(`nous' est-il un sujet, un objet ou un réfléchi?).  Dans ce cas, le script
+opte pour le sujet (ou pour l'objet si l'ambiguïté n'est que entre objet et
+réfléchi).
+
+Quand il n'y a aucune information disponible (erreurs de l'étiqueteur), la
+valeur est UNDEFINED.
+
+L'algorithme est décrit ici:
+https://groupes.renater.fr/wiki/democrat/prive/txm_annotation_exploitation
+
+*/
+
+package org.txm.macro.urs.democrat
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+def testClitic(def position, def frpos) {
+
+   // je me sers de la forme, parce qu'il est difficile de savoir quel est le
+   // lemme de "elle" ("il"?), de "te" ("tu"?) ou encore de "leur"
+   def form = CQI.cpos2Str(word.getQualifiedName(), position)[0].toLowerCase()
+   if (     form == "je" || form == "j'"
+         || form == "tu" || form == "t'"
+         || form == "il"
+         || form == "elle"
+         || form == "on"
+         || form == "vous"
+         || form == "nous"
+         || form == "ils"
+         || form == "elles" ) {
+      return "PR_CL_S"
+   } else if (form == "me" || form == "m'"
+           || form == "te"
+           || form == "le" || form == "l'"
+           || form == "la"
+           || form == "lui"
+           || form == "leur"
+           || form == "les" ) {
+      return "PR_CL_O"
+   } else if (form == "se" || form == "s'") {
+      return "PR_CL_R"
+   }
+   return null
+
+}
+
+def testPhrase(def positions, def Mention) {
+
+   // on doit regarder ce qui apparaît en premier:
+   // - ce peut être un nom, comme dans `le petit chat que j'ai adopté'
+   // - ce peut être un pronom relatif, comme dans `(le livre) dans lequel
+   // j'ai lu cette histoire...'
+   // NOTE: dans Democrat, on n'annote pas, bizarrement, la relative dans le
+   // maillon, donc, dans un GN on n'a jamais de relatif inclus.  On aura donc
+   // toujours `[le petit chat] [que] [j']ai adopté'.  Mais tout le monde
+   // n'annote pas de la sorte...
+   for (def i=0; i<Mention.length; i++) {
+         def mention = Mention[i]
+         //def form = CQI.cpos2Str(word.getQualifiedName(), positions[i])[0]
+         if (mention == "NOM" || mention == "NAM") {
+            return "GN"
+         } else if (mention == "PRO:REL") {
+            return "PR_REL"
+         }
+    }
+
+    return null
+
+}
+
+def testWhPronoun(position, mention) {
+   def form = CQI.cpos2Str(word.getQualifiedName(), position)[0]
+   if (mention == "PRO" && (form == "qui" || form == "que" || form == "lequel")) {
+      return "PR_WH"
+   }
+   return null
+
+}
+
+def testRules(def positions, def Mention) {
+	def catégorie = null
+
+   // a possessive (mon, ma...)
+   if (Mention.length == 1 && Mention.contains("DET:POS"))
+      catégorie = "POSS"
+
+   // a clitic (subject: je, tu...; object: me, te; reflexive: se)
+   if (!catégorie && Mention.length == 1 && Mention.contains("PRO:PER"))
+      catégorie = testClitic(positions[0], Mention[0])
+
+   // an interrogative pronoun
+   if (!catégorie && Mention.length == 1)
+      catégorie = testWhPronoun(positions[0], Mention[0])
+
+   // a noun phrase or a relative pronoun
+   if (!catégorie)
+      catégorie = testPhrase(positions, Mention)
+
+   // some other kind of pronouns
+   if (!catégorie
+         && (   Mention.contains("PRO")
+             || Mention.contains("PRO:POSS")
+             || Mention.contains("PRO:IND")
+             || Mention.contains("PRO:DEM")
+             || Mention.contains("PRO:PER") )
+         && !Mention.contains("NOM")
+         && !Mention.contains("NAM") )
+      catégorie = "PRO"
+
+// Fin des règles, aucune n'a matchée. On stocke le pattern  qu'on affichera à la fin.
+   if (!catégorie) {
+      catégorie = "UNDEFINED" // clear the field
+		def forms = CQI.cpos2Str(word.getQualifiedName(), positions)
+		if (!errors.containsKey(Mention)) errors[Mention] = new HashSet()
+		errors[Mention] << forms
+	}
+	
+	return catégorie
+}
+
+//
+// FIN DE LA DÉFINITION DES RÈGLES
+//
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="pos_property_name", usage="", widget="String", required=true, def="pos")
+def pos_property_name
+@Field @Option(name="reset", usage="", widget="Boolean", required=true, def="true")
+def reset
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+CQI = CQPSearchEngine.getCqiClient()
+word = corpus.getWordProperty()
+posProperty = corpus.getProperty(pos_property_name)
+if (posProperty == null) {
+	println "Error: CQP corpus does not contains the word property with name=$pos_property_name"
+	return
+}
+analecCorpus = URSCorpora.getCorpus(corpus)
+vue = URSCorpora.getVue(corpus)
+structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+
+CATEGORIE = "CATEGORIE"
+// Si la structure d'annotation ne contient pas CATEGORIE, on la crée avec ses valeurs
+if (!structure.getUniteProperties(unit_type).contains(CATEGORIE)) { 
+
+// FIXME: dans le script original (see also
+// http://forge.cbp.ens-lyon.fr/redmine/issues/2065), on utilise
+// analecCorpus.ajouterProp/Val, mais cela ne marche pas dans ma version de
+// TXM-Analec --> je retourne donc à structure.ajouterProp/Val
+
+// la propriété
+	structure.ajouterProp(Unite.class, unit_type, CATEGORIE)
+// les valeurs
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "POSS")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PR_CL_O")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PR_CL_S")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PR_CL_R")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PR_REL")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PR_WH")
+//...
+}
+
+if (!vue.getTypesAVoir(Unite.class).contains(unit_type)) {
+	vue.ajouterType(Unite.class, unit_type)
+}
+if (!vue.getNomsChamps(Unite.class, unit_type).contains(CATEGORIE)) {
+	vue.ajouterProp(Unite.class, unit_type, CATEGORIE)
+}
+
+def nModified = 0
+def nIgnored = 0
+
+errors = new HashMap()
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+for (Unite unit : units) { // process all units
+	
+	def prop = unit.getProp(CATEGORIE)
+	if (!reset && prop != null && prop.length() > 0) continue // l'unité a déjà une CATEGORIE
+	
+	int[] positions = null
+	if (unit.getDeb() == unit.getFin()) positions = [unit.getDeb()]
+	else positions = (unit.getDeb()..unit.getFin())
+	
+	def Mention = CQI.cpos2Str(posProperty.getQualifiedName(), positions)
+	def cat = testRules(positions, Mention)
+
+	if (cat != null) {
+		// following line in the original script but doesn't work for me:
+      // vue.setValeurChamp(unit, CATEGORIE, cat)
+      unit.getProps().put(CATEGORIE, cat)
+		nModified++
+	} else {
+		nIgnored++
+	}
+}
+
+println "Result:"
+println "- $nModified units of type $unit_type have been modified."
+println "- $nIgnored units of type $unit_type have not been modified.\n"
+
+if (errors.size() > 0) {
+	println "Some rules should be added to this macro to process the following remaining 'FROPOS / words' values:"
+	errors.keySet().each { println "fropos="+it+"\twords="+errors[it].join(" | ") }
+}
+
+// udpate the view (also see also
+// http://forge.cbp.ens-lyon.fr/redmine/issues/2065)
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/CreationChainesMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/CreationChainesMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/CreationChainesMacro.groovy	(revision 3653)
@@ -0,0 +1,140 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.democrat
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.Schema
+import visuAnalec.elements.Unite;
+import visuAnalec.vue.Vue
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type",usage="", widget="String", required=true, def="MENTION")
+String unit_type
+@Field @Option(name="ref_property",usage="", widget="String", required=true, def="REF")
+String ref_property
+if (!ParametersDialog.open(this)) return;
+
+int nCreated = 0 // count the number of created CHAINE
+int nUpdated = 0 // count the number of updated CHAINE
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus); 
+Structure structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+if (!structure.getSchemas().contains("CHAINE")) { // update the structure if needed
+	println "Creating the 'CHAINE' schema in the structure"
+	analecCorpus.ajouterType(Schema.class, "CHAINE")
+	analecCorpus.ajouterProp(Schema.class, "CHAINE", "REF")
+	analecCorpus.ajouterProp(Schema.class, "CHAINE", "GENRE")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "GENRE", "INDETERMINABLE")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "GENRE", "FEMININ")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "GENRE", "MASCULIN")
+	analecCorpus.ajouterProp(Schema.class, "CHAINE", "NOMBRE")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "NOMBRE", "GROUPE_FLOU")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "NOMBRE", "GROUPE_STRICT")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "NOMBRE", "SINGULIER")
+	analecCorpus.ajouterProp(Schema.class, "CHAINE", "NB MAILLONS")
+	analecCorpus.ajouterProp(Schema.class, "CHAINE", "TYPE REFERENT")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "TYPE REFERENT", "UNKNOWN")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "TYPE REFERENT", "CONCRET_OBJECT")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "TYPE REFERENT", "ABSTRACT_OBJECT")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "TYPE REFERENT", "TIME")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "TYPE REFERENT", "PRODUCT")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "TYPE REFERENT", "AMOUNT")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "TYPE REFERENT", "EVENT")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "TYPE REFERENT", "GPE")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "TYPE REFERENT", "ORG")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "TYPE REFERENT", "PERSON")
+	analecCorpus.ajouterVal(Schema.class, "CHAINE", "TYPE REFERENT", "LIEU")
+}
+
+Vue vue = URSCorpora.getVue(corpus)
+if (!vue.getTypesAVoir(Schema.class).contains("CHAINE")) {
+	vue.ajouterType(Schema.class, "CHAINE")
+}
+if (!vue.getNomsChamps(Schema.class, "CHAINE").contains("REF")) {
+	vue.ajouterProp(Schema.class, "CHAINE", "REF")
+}
+if (!vue.getNomsChamps(Schema.class, "CHAINE").contains("GENRE")) {
+	vue.ajouterProp(Schema.class, "CHAINE", "GENRE")
+}
+if (!vue.getNomsChamps(Schema.class, "CHAINE").contains("NOMBRE")) {
+	vue.ajouterProp(Schema.class, "CHAINE", "NOMBRE")
+}
+if (!vue.getNomsChamps(Schema.class, "CHAINE").contains("NB MAILLONS")) {
+	vue.ajouterProp(Schema.class, "CHAINE", "NB MAILLONS")
+}
+if (!vue.getNomsChamps(Schema.class, "CHAINE").contains("TYPE")) {
+	vue.ajouterProp(Schema.class, "CHAINE", "TYPE")
+}
+
+def props = structure.getUniteProperties(unit_type)
+if (!props.contains(ref_property)) { // check the unit_type units have the REF property
+	println "Error: $unit_type units have no proprerty named '$ref_property'"
+	return
+}
+
+// parse the units to build CHAINES
+def chaines = [:]
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+for (Unite unit : units) {
+	def ref = unit.getProp(ref_property)
+	if (!chaines.containsKey(ref)) {
+		chaines[ref] = []
+	}
+	chaines[ref] << unit
+}
+
+// update the already existing CHAINES schemas
+for (Schema schema : analecCorpus.getSchemas("CHAINE")) {
+	String ref = schema.getProp(ref_property)
+	if (chaines.containsKey(ref)) { // the CHAINE exists 
+		// maj des unités de la chaine existante
+		int size_before = schema.getContenu().size()
+		for (def unit : chaines[ref]) schema.ajouter(unit) // insert the new units in the hashset
+		
+		// Update the CHAINE size
+		schema.props.put("NB MAILLONS", Integer.toString(schema.contenu.size())) 
+		
+		// remove the inserted CHAINE from 'chaines'
+		chaines.remove(ref)
+		if (size_before < schema.getContenu().size()) // if the size changed, then the CHAIEN have been updated
+			nUpdated++
+	}
+}
+
+// create the remaining CHAINES schemas
+for (def ref : chaines.keySet()) { // process the remaining CHAINE of 'chaines'
+	nCreated++;
+	Schema schema = new Schema()
+	schema.type = "CHAINE"
+	schema.props.put("REF", ref) 
+	schema.props.put("GENRE", "") // set default values
+	schema.props.put("NOMBRE", "") // set default values
+	schema.props.put("NB MAILLONS", Integer.toString(chaines[ref].size())) 
+	schema.props.put("TYPE REFERENT", "") // set default values
+	
+	for (def unit : chaines[ref]) schema.ajouter(unit) // insert the new units in the hashset
+	
+	analecCorpus.addSchemaLu(schema)  // add the new schema
+}
+
+if (nUpdated > 0 || nCreated > 0) corpus.setIsModified(true);
+println "nUpdated=$nUpdated"
+println "nCreated=$nCreated"
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/TrimPropertyValuesMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/TrimPropertyValuesMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/TrimPropertyValuesMacro.groovy	(revision 3653)
@@ -0,0 +1,95 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.democrat
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.macro.urs.AnalecUtils
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.donnees.Corpus
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.*
+import visuAnalec.vue.Vue
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return;
+}
+
+@Field @Option(name="element", usage="Unite|Relation|Schema", widget="StringArray", metaVar="Unite	Relation	Schema", required=true, def="Unite")
+		String element
+@Field @Option(name="ursql", usage="select the elements with a URSQL", widget="String", required=true, def="")
+		String ursql
+	
+@Field @Option(name="replaceValues", usage="do replace the property values", widget="Boolean", required=true, def="false")
+		def replaceValues
+@Field @Option(name="trimProperties", usage="remove heading and trailing blanks", widget="Boolean", required=true, def="true")
+		def trimProperties
+@Field @Option(name="fixSpaces", usage="replace several blanks with one blank", widget="Boolean", required=true, def="true")
+		def fixSpaces
+		@Field @Option(name="fixNewLines", usage="replace", widget="Boolean", required=true, def="true")
+		def fixNewLines
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+if (!ParametersDialog.open(this)) return
+
+	if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+int nCreated = 0 // count the number of created CHAINE
+int nUpdated = 0 // count the number of updated CHAINE
+
+CQPCorpus corpus = corpusViewSelection
+Corpus analecCorpus = URSCorpora.getCorpus(corpus);
+
+Class clazz = Unite.class;
+def elements = null
+if ("Schema".equals(element)) {
+	clazz = Schema.class;
+	elements = analecCorpus.getTousSchemas()
+} else if ("Relation".equals(element)){
+	clazz = Relation.class;
+	elements = analecCorpus.getToutesRelations()
+} else if ("Unite".equals(element)){
+	clazz = Unite.class;
+	elements = analecCorpus.getToutesUnites()
+}
+
+elements = AnalecUtils.filterElements(debug, elements, ursql)
+
+println "Fixing ${elements.size()} $ursql $element"
+int nUpdate = 0;
+// update the already existing CHAINES schemas
+
+	for (def e : elements) {
+		def props = e.getProps()
+		if (debug > 2) println "		e=$props"
+		for (def k : props.keySet()) {
+			String p = props[k]
+			
+			if (trimProperties) {
+				p = p.trim()
+			}
+			if (fixNewLines) {
+				p = p.replaceAll("\n", "")
+			}
+			if (fixSpaces) {
+				p = p.replaceAll("[ ]++", " ")
+			}
+			
+			if (p != props[k]) {
+				nUpdate++
+			}
+			if (replaceValues) {
+				props[k] = p
+				if (debug > 3) println "			props[$k]=${props[k]} -> $p"
+			} else if (p != props[k]) {
+				println "			props[$k]=${props[k]} -> $p"
+			}
+		}
+	}
+
+println "Done: $nUpdate update(s)"
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/BuildDemocratCorpusVersion1Macro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/BuildDemocratCorpusVersion1Macro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/BuildDemocratCorpusVersion1Macro.groovy	(revision 3653)
@@ -0,0 +1,195 @@
+package org.txm.macro.urs.democrat
+
+import java.io.File
+import java.nio.charset.Charset
+
+import org.eclipse.core.runtime.IProgressMonitor
+import org.kohsuke.args4j.*
+import groovy.io.FileType
+import groovy.transform.Field
+import visuAnalec.donnees.Corpus
+import visuAnalec.vue.Vue
+
+import org.txm.annotation.urs.URSCorpora
+import org.txm.importer.StaxIdentityParser
+import org.txm.objects.*
+import org.txm.rcp.commands.workspace.LoadBinaryCorpus
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.rcp.utils.JobHandler
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.utils.CsvReader
+import org.txm.utils.io.IOUtils
+import org.txm.scripts.importer.XPathResult
+import javax.xml.xpath.XPathConstants
+import org.txm.annotation.urs.commands.*
+
+@Field @Option(name="inputDirectory", usage="Directory with .txm files, metadata.xslx, metadata.properties...", widget="Folder", required=true, def="input directory path")
+def inputDirectory
+
+@Field @Option(name="outputDirectory", usage="the default teiHeader of texts", widget="Folder", required=true, def="output directory path")
+def outputDirectory
+
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+debug
+
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+def teiHeaderTemplateFile = new File(inputDirectory, "teiHeader.xml")
+def xpathFile = new File(inputDirectory, "metadata.properties")
+def metadataFile = new File(inputDirectory, "metadata.tsv")
+
+if (!inputDirectory.exists()) {
+	println "no inputDirectory found: $inputDirectory"
+	return false;
+}
+
+outputDirectory.mkdirs()
+if (!outputDirectory.exists()) {
+	println "outputDirectory not created: $outputDirectory"
+	return false;
+}
+
+if (!teiHeaderTemplateFile.exists()) {
+	println "no teiHeader template found: $teiHeaderTemplateFile"
+	return false;
+}
+
+if (!xpathFile.exists()) {
+	println "no xpath properties found: $xpathFile"
+	return false;
+}
+
+if (!metadataFile.exists()) {
+	println "no metadata TSV found: $metadataFile"
+	return false;
+}
+
+def xpathProperties = new Properties()
+xpathProperties.load(IOUtils.getReader(xpathFile))
+
+println "xpath properties: "+xpathProperties.keySet()
+
+def csvReader = new CsvReader(metadataFile.getAbsolutePath(), "\t".charAt(0), Charset.forName("UTF-8"))
+
+csvReader.readHeaders();
+def header = csvReader.getHeaders()
+if (!header.contains("text_id")) {
+	println "** 'id' column not found in $metadataFile header=$header" 
+	return;
+}
+if (!header.contains("corpus_id")) {
+	println "** 'corpus_id' column not found in $metadataFile header=$header"
+	return;
+}
+
+if (!header.contains("txm_file")) {
+	println "** 'txm_file' column not found in $metadataFile header=$header"
+	return;
+}
+
+def corpora = [:]
+for (Project project : Workspace.getInstance().getProjects()) {
+	for (MainCorpus corpus : project.getChildren(MainCorpus.class)) {
+		corpora[corpus.getID()] = corpus;
+	}
+}
+
+while (csvReader.readRecord())	{
+	String text_id = csvReader.get("text_id")
+	if (text_id == null || text_id.length() == 0) {
+		println "** @text_id not found for record="+csvReader.getRawRecord()
+		continue;
+	}
+	println "text: "+text_id
+	
+	String corpus_id = csvReader.get("corpus_id")
+	if (corpus_id == null || corpus_id.length() == 0) {
+		println " ** @corpus_id <- @text_id="+text_id.toUpperCase()
+		corpus_id = text_id.toUpperCase();
+	}
+	
+	String txm_file = csvReader.get("txm_file")
+	if (txm_file == null || txm_file.length() == 0) {
+		println " ** @txm_file <- @corpus_id=${corpus_id}.txm"
+		txm_file = corpus_id.toUpperCase()+".txm";
+	}
+	
+	MainCorpus corpus = corpora[corpus_id]
+	Project project = null
+	boolean loaded = false
+	if (corpus == null) {
+		File binCorpusFile = new File(inputDirectory, txm_file)
+		if (!binCorpusFile.exists()) {
+			println " ** no corpus binary file found for ID='$corpus_id' : $binCorpusFile"
+			continue;
+		}
+		println " loading corpus from ${binCorpusFile}..."
+		JobHandler job = LoadBinaryCorpus.loadBinaryCorpusArchive(binCorpusFile)
+		job.join();
+		project = job.getResultObject();
+		corpus = project.getCorpusBuild(corpus_id);
+		if (corpus == null) {
+			println " ** no corpus for ID='$corpus_id' found in the binary corpus."
+			continue
+		}
+		corpora[corpus.getID()] = corpus;
+		loaded = true
+	} else {
+		println " using loaded corpus ${corpus}..."
+		project = corpus.getProject()
+	}
+	
+	def txmDir = new File(project.getProjectDirectory(), "txm/"+corpus.getID())
+	
+	if (!txmDir.exists()) {
+		println " ** the selected corpus has no XML-TXM files. Aborting."
+		continue;
+	}
+	
+	File txmFile = new File(txmDir, text_id+".xml")
+	if (!txmFile.exists()) { //
+		def list = []
+		txmDir.eachFileRecurse (FileType.FILES) { file ->
+			list << file
+		}
+		txmFile = list[0]
+	}
+	if (!txmFile.exists()) {
+		println " ** the selected corpus has no XML-TXM file: $txmFile"
+		continue;
+	}
+	
+	
+	println " compute measures..."
+	def data = new ComputeDemocratMeasureMetadata().getStats(corpus, xpathProperties)
+	
+	Metadata2TEIHeader mthm = new Metadata2TEIHeader(debug);
+	for (def h : header) data[h] = csvReader.get(h)
+	
+	println " creating teiHeader..."
+	String xmlteiHeaderContent = mthm.getCustomizedTEiHeader(teiHeaderTemplateFile, data, xpathProperties);
+	if (xmlteiHeaderContent != null && xmlteiHeaderContent.length() > 0) {
+		println " replacing teiHeader... "
+		mthm.replaceHeader(txmFile, xmlteiHeaderContent)
+	} else {
+		println " ** Text header not updated: $txmFile"
+	}
+		
+	println " URS Export..."
+	Corpus analecCorpus = URSCorpora.getCorpus(corpus);
+	Vue vue = URSCorpora.getVue(corpus);
+	if (!ExportTEICorpus.export(true, outputDirectory, false, null, corpus, analecCorpus, vue)) {
+		println " FAIL TO EXPORT CORPUS $corpus"
+	}
+	
+	println " exporting the corpus to '.txm' file..."
+	corpus.export(new File(outputDirectory, corpus.getID()+".txm"), null)
+	
+	if (loaded) {
+		println " removing loaded corpus..."
+		corpus.delete();
+	}
+	
+	println " done."
+}
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/SUJ-PARTINFMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/SUJ-PARTINFMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/SUJ-PARTINFMacro.groovy	(revision 3653)
@@ -0,0 +1,110 @@
+package org.txm.macro.urs.democrat
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.analec.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+/*
+   Retouche les sujets zéros pour les recatégoriser au besoin
+   en SUJ.PARTINF lorsque le verbe est au participe ou à 
+   l'infinitif
+   Auteur : Matthieu QUIGNARD
+   Date : 05 Février 2019
+ */
+
+def listePartInf = ["VER:pper", "VER:ppre", "VER:infi", "VERppe", "VERppa", "VERinf"]
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="property_name", usage="", widget="String", required=true, def="CATEGORIE")
+def property_name
+@Field @Option(name="suj_zero_cat", usage="", widget="String", required=true, def="SUJ.ZERO")
+def suj_zero_cat
+@Field @Option(name="pos_property_name", usage="", widget="String", required=true, def="frpos")
+def pos_property_name
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+CQI = CQPSearchEngine.getCqiClient()
+word = corpus.getWordProperty()
+posProperty = corpus.getProperty(pos_property_name)
+if (posProperty == null) {
+	println "Error: CQP corpus does not contains the word property with name=$pos_property_name"
+	return
+}
+analecCorpus = URSCorpora.getCorpus(corpus)
+vue = URSCorpora.getVue(corpus)
+structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Erreur : le corpus ne contient d'unité de type $unit_type"
+	println "Script terminé"
+	return
+}
+
+if (!structure.getUniteProperties(unit_type).contains(property_name)) { 
+	println "Erreur : les unités $unit_type n'ont pas de propriété $property_name"
+	println "Script terminé"
+	return
+}
+
+if (!vue.getTypesAVoir(Unite.class).contains(unit_type)) {
+	vue.ajouterType(Unite.class, unit_type)
+}
+if (!vue.getNomsChamps(Unite.class, unit_type).contains(property_name)) {
+	vue.ajouterProp(Unite.class, unit_type, property_name)
+}
+
+def nModified = 0
+def nIgnored = 0
+
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+
+for (Unite unit : units) { // process all units
+	def prop = unit.getProp(property_name)
+	
+	if (prop != suj_zero_cat) {
+		// On ne s'intéresse qu'aux SUJ.ZERO
+		// Les autres sont ignorés
+		nIgnored++
+	} else {
+		// Pour les mentions de type "GN.IND", on cherche le premier mot
+		int[] positions = null
+		if (unit.getDeb() == unit.getFin()) positions = [unit.getDeb()]
+		else positions = (unit.getDeb()..unit.getFin())
+	
+		// On récupère le POS du premier mot
+		def tags = CQI.cpos2Str(posProperty.getQualifiedName(), positions)
+		def firstTag = tags[0];
+			
+		if ( listePartInf.contains(firstTag) ) {
+			vue.setValeurChamp(unit, property_name, "SUJ.PARTINF")
+			nModified++
+		} else {
+			// Sinon on laisse tel quel
+			nIgnored++
+		}
+	}
+}
+
+println "Result:"
+println "- $nModified units of type $unit_type have been modified."
+println "- $nIgnored units of type $unit_type have not been modified.\n"
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/AccessibiliteMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/AccessibiliteMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/AccessibiliteMacro.groovy	(revision 3653)
@@ -0,0 +1,116 @@
+package org.txm.macro.urs.democrat
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+/*
+   Calcule l'accessibilité (faible ou forte) d'une mention à partir de sa CATEGORIE
+   La macro fonctionne à partir de 2 listes de catégories : accessibilité forte, accessibilité nulle.
+   L'accessibilité faible sera le cas par défaut.
+   
+   La macro crée une nouvelle propriété pour les MENTION : ACCESSIBILITE
+   Les valeurs autorisées sont : "Faible", "Forte" et "N/A"
+   Voir si la dénomination de cette dernière valeur convient.
+    
+   Auteur : Matthieu Quignard
+   Date : 19/12/2017
+ */
+
+def listeAccessibiliteForte=["PRO.PERA", "PRO.REL", "SUJ.ZERO", "DET.POS"]
+def listeAccessibiliteNulle=[]
+
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Corpora selection is not a Corpus: "+corpusViewSelection
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="", widget="String", required=true, def="MENTION")
+def unit_type
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+CQI = CQPSearchEngine.getCqiClient()
+
+analecCorpus = URSCorpora.getCorpus(corpus)
+vue = URSCorpora.getVue(corpus)
+structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+
+ACCESSIBILITE = "ACCESSIBILITE"
+// Si la structure d'annotation ne contient pas ACCESSIBILITE, on la crée avec ses valeurs
+if (!structure.getUniteProperties(unit_type).contains(ACCESSIBILITE)) {
+	// la propriété
+	analecCorpus.ajouterProp(Unite.class, unit_type, ACCESSIBILITE)
+	// les valeurs
+
+	structure.ajouterVal(Unite.class, unit_type, ACCESSIBILITE, "Faible")
+	structure.ajouterVal(Unite.class, unit_type, ACCESSIBILITE, "Forte")
+	structure.ajouterVal(Unite.class, unit_type, ACCESSIBILITE, "N/A")
+}
+if (!vue.getTypesAVoir(Unite.class).contains(unit_type)) {
+	vue.ajouterType(Unite.class, unit_type)
+}
+if (!vue.getNomsChamps(Unite.class, unit_type).contains(ACCESSIBILITE)) {
+	vue.ajouterProp(Unite.class, unit_type, ACCESSIBILITE)
+}
+
+def nModified = 0
+def nIgnored = 0
+def nNulle = 0
+def nForte = 0
+def nFaible = 0
+
+errors = new HashMap()
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+for (Unite unit : units) { // process all units
+
+	def prop = unit.getProp("CATEGORIE")
+	
+	if (prop== null) {
+		// On ignore les cas où la catégorie n'est pas renseignée.
+		nIgnored++
+	} else {
+		nModified++
+		if (listeAccessibiliteNulle.contains(prop)) {
+			// Cas d'accessibilité nulle
+			vue.setValeurChamp(unit, ACCESSIBILITE, "N/A")
+			nNulle++
+		} else if (listeAccessibiliteForte.contains(prop)) {
+			// Cas d'accessibilité forte
+			vue.setValeurChamp(unit, ACCESSIBILITE, "Forte")	
+			nForte++
+		} else {
+			// Sinon, on est dans le cas d'accessibilité faible
+			vue.setValeurChamp(unit, ACCESSIBILITE, "Faible")	
+			nFaible++
+		}
+	}
+	
+}
+
+println "Result:"
+println "- $nModified mentions ont été modifiées."
+println "- $nIgnored mentions ont été ignorées (leur catégorie est vide).\n"
+
+println "- $nForte mentions d'accessibilité forte."
+println "- $nFaible mentions d'accessibilité faible."
+println "- $nNulle mentions de type 'N/A' (déictiques).\n"
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Fropos2CattexMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Fropos2CattexMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Fropos2CattexMacro.groovy	(revision 3653)
@@ -0,0 +1,259 @@
+package org.txm.macro.urs.democrat
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+/*
+Définit la catégorie grammaticale des mentions d'après le champ `frpos'
+(tagset de TreeTagger). 
+
+La liste des catégories grammaticales est celle de CATTEX2009
+-- Groupes nominaux :
+	GN.NAM (noms propres) : Henri II
+	GN.DEF (définis) : Le roi, du roi
+	GN.IND (indéfinis) : Un roi
+	GN.POS (possessifs) : [Mon roi]
+	GN.DEM (demonstratif) : Ce roi
+	GN.NUM (numéraux) : Deux rois
+	GN.CHECK (GN indéterminés)
+-- Déterminants
+	DET.POS (possessifs) : [mon] roi
+-- Pronoms
+	PRO.PER (personnels) : je, moi, me, on, il, etc.
+	PRO.ADV (adverbiaux) : y, en
+	PRO.IND (indéfinis) : tout, tous, certains, plusieurs, etc.
+	PRO.DEM (demonstratifs) : ceci, cela, ce, ça...
+	PRO.POS (possessifs) : le mien, les nôtres...
+	PRO.NUM (cardinaux, ordinaux) : les deux...
+	PRO.REL (relatifs) : qui, que, quoi, duquel, etc.
+	PRO.INT (interrogatifs)
+	PRO.CHECK (pronoms indéterminés)
+-- SUJ.ZERO (Sujet Zéro) : verbes conjugués, éventuellement pronominal
+
+-- ERREUR : erreur (a priori) de mention
+-- ADJpos : adjectif possessif à fusionner ou pas avec DETpos
+	
+*/
+
+
+
+def testRules(def positions, def Mention) {
+	def catégorie = null
+	
+	// la forme du premier mot de la mention s'appelle 'forme'
+	def forme = CQI.cpos2Str(word.getQualifiedName(), positions)[0].toLowerCase()
+    
+    
+	if (Mention.length == 1) {    
+	    
+		     if (Mention.first() == "NOMpro"    ) catégorie = "GN.NAM"
+		else if (Mention.first() == "DETpos") catégorie = "DET.POS"
+		else if (Mention.first() == "ADJpos") catégorie = "ADJ.POS"
+		else if (Mention.first() == "PROdem") catégorie = "PRO.DEM"
+		else if (Mention.first() == "PROind") catégorie = "PRO.IND"
+		else if (Mention.first() == "PROcar") catégorie = "PRO.NUM"
+		else if (Mention.first() == "PROord") catégorie = "PRO.NUM" // fusionné avec Cardinaux
+		else if (Mention.first() == "PROpos") catégorie = "PRO.POS"
+		else if (Mention.first() == "PROper") catégorie = "PRO.PER" 
+		else if (Mention.first() == "PROimp") catégorie = "PRO.PER" // fusionné avec Pronoms Personnels
+		else if (Mention.first() == "PROint") catégorie = "PRO.INT"
+		else if (Mention.first() == "PROadv") catégorie = "PRO.ADV"
+		else if (Mention.first() == "PROrel") catégorie = "PRO.REL"
+		
+		else if (Mention.first().contains("VER")) catégorie = "SUJ.ZERO"
+		
+		else if (Mention.first() == "NOMcom") catégorie = "GN.CHECK"
+		
+		// Pronoms "contractés"
+		else if (Mention.first() == "PROper.PROper") catégorie = "PRO.PER"  // double pronom personnel : ex 'jel' pour 'je le'
+		else if (Mention.first() == "ADVgen.PROper") catégorie = "PRO.PER"  // adverbe + pronom personnel : ex 'sil' pour 'si le'
+		else if (Mention.first() == "ADVneg.PROper") catégorie = "PRO.PER"  // adverbe + pronom personnel : ex 'nel' pour 'ne le'
+		
+		// Erreurs de mention
+		else if (Mention.first() == "ADVgen") catégorie = "ERREUR"  // un adverbe seul n'est jamais référentiel
+		else if (Mention.first() == "ADVneg") catégorie = "ERREUR"  // un adverbe seul n'est jamais référentiel
+		else if (Mention.first() == "PRE") catégorie = "ERREUR"  // une preposition seule n'est jamais référentielle
+		else if (Mention.first() == "ADJqua") catégorie = "ERREUR"  // un adjectif seul n'est jamais référentiel
+		else if (Mention.first() == "ADJind") catégorie = "ERREUR"  // un adjectif seul n'est jamais référentiel
+		else if (Mention.first() == "INJ") catégorie = "ERREUR"  // une interjection seule n'est jamais référentielle
+		
+		else catégorie = "PRO.CHECK"	
+
+	} else if (Mention.length == 2) {
+		if ( (Mention[0] == "NOMpro") || (Mention[1] == "NOMpro") ) catégorie = "GN.NAM"
+		else if (Mention[1] == "PROrel") catégorie = "PRO.REL"  // "ce que" prioritaire sur "celui là"
+		else if (Mention[1] == "PROpos") catégorie = "PRO.POS"  // "les miens"
+		else if (Mention[1].contains("car")) catégorie = "PRO.NUM"  // "les deux"
+		else if (Mention[1] == "PROdem") catégorie = "PRO.DEM"  // "Tout cela"
+		
+		else if (Mention[0].contains("DET") && Mention[1].contains("PROind")) catégorie = "PRO.IND" // "les autres"
+		
+		else if (Mention[0].contains("VER") && Mention[1].contains("VER")) catégorie = "SUJ.ZERO" // verbe temps composé
+		
+		else if (!Mention[0].contains("NOM") && !Mention[0].contains("ADJ") && !Mention[1].contains("NOM") && !Mention[1].contains("ADJ")) {
+			if (Mention[0] == "PROdem") catégorie = "PRO.DEM"
+			else if (Mention[1] == "VERinf") catégorie = "GN.CHECK" // Verbe substantivé
+			else if (Mention[1] == "VERppa") catégorie = "GN.CHECK" // Verbe substantivé
+			else if ( Mention[0].contains("PRE") && (Mention[1] == "PROper")) catégorie = "GN.CHECK" // Complément de nom
+			else catégorie = "PRO.CHECK"
+		}
+		else catégorie = "GN.CHECK"           
+	} 
+	
+	if ( (catégorie == null) || (catégorie == "GN.CHECK") ) {
+		// on est dans les GN
+		
+		if (Mention[0] == "DETcar"     ) catégorie = "GN.NUM"
+		else if (Mention[0] == "DETord"     ) catégorie = "GN.NUM"
+
+		else if (Mention.contains("NOMpro")) catégorie = "GN.NAM"
+				
+		else if (Mention[0] == "DETpos" ) catégorie = "GN.POS"
+				
+		else if (Mention[0] == "PROdem" ) catégorie = "GN.DEM"
+		else if (Mention[0] == "DETdem" ) catégorie = "GN.DEM"
+		
+		else if (Mention[0] == "PRE.DETdef" ) catégorie = "GN.DEF"
+		else if (Mention[0] == "DETdef")   catégorie = "GN.DEF"
+		
+		else if (Mention[0] == "DETndf") catégorie = "GN.IND" 
+		else if (Mention[0] == "DETind") catégorie = "GN.IND" 
+		
+		else if (Mention[0] == "PROind" ) catégorie = "GN.IND"
+		else if (Mention[0].contains("PRP")) catégorie = "GN.IND"
+		else if (Mention[0].contains("ADJ")) catégorie = "GN.IND"
+		else if (Mention[0].contains("NOM")) catégorie = "GN.IND"
+		
+		
+		
+		else catégorie = "GN.CHECK"
+	}
+
+
+	
+	return catégorie
+}
+
+//
+// FIN DE LA DÉFINITION DES RÈGLES
+//
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="pos_property_name", usage="", widget="String", required=true, def="pos")
+def pos_property_name
+@Field @Option(name="reset", usage="", widget="Boolean", required=true, def="true")
+def reset
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+CQI = CQPSearchEngine.getCqiClient()
+word = corpus.getWordProperty()
+posProperty = corpus.getProperty(pos_property_name)
+if (posProperty == null) {
+	println "Error: CQP corpus does not contains the word property with name=$pos_property_name"
+	return
+}
+analecCorpus = URSCorpora.getCorpus(corpus)
+vue = URSCorpora.getVue(corpus)
+structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+
+CATEGORIE = "CATEGORIE"
+// Si la structure d'annotation ne contient pas CATEGORIE, on la crée avec ses valeurs
+if (!structure.getUniteProperties(unit_type).contains(CATEGORIE)) { 
+// la propriété
+	analecCorpus.ajouterProp(Unite.class, unit_type, CATEGORIE)
+// les valeurs
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN.NAM")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN.DEF")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN.IND")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN.POS")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN.DEM")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN.NUM")
+	
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN.CHECK")
+	
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "DET.POS")
+	
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.PER")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.ADV")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.IND")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.DEM")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.POS")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.NUM")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.INT")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.REL")
+	
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO.CHECK")
+	
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "SUJ.ZERO")
+	
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "ERREUR")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "ADJ.POS")
+	
+//...
+}
+
+if (!vue.getTypesAVoir(Unite.class).contains(unit_type)) {
+	vue.ajouterType(Unite.class, unit_type)
+}
+if (!vue.getNomsChamps(Unite.class, unit_type).contains(CATEGORIE)) {
+	vue.ajouterProp(Unite.class, unit_type, CATEGORIE)
+}
+
+def nModified = 0
+def nIgnored = 0
+
+errors = new HashMap()
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+for (Unite unit : units) { // process all units
+	
+	def prop = unit.getProp(CATEGORIE)
+	if (!reset && prop != null && prop.length() > 0) continue // l'unité a déjà une CATEGORIE
+	
+	int[] positions = null
+	if (unit.getDeb() == unit.getFin()) positions = [unit.getDeb()]
+	else positions = (unit.getDeb()..unit.getFin())
+	
+	def Mention = CQI.cpos2Str(posProperty.getQualifiedName(), positions)
+	def cat = testRules(positions, Mention)
+	
+	if (cat != null) {
+		vue.setValeurChamp(unit, CATEGORIE, cat)
+		nModified++
+	} else {
+		nIgnored++
+	}
+}
+
+println "Result:"
+println "- $nModified units of type $unit_type have been modified."
+println "- $nIgnored units of type $unit_type have not been modified.\n"
+
+if (errors.size() > 0) {
+	println "Some rules should be added to this macro to process the following remaining 'FROPOS / words' values:"
+	errors.keySet().each { println "fropos="+it+"\twords="+errors[it].join(" | ") }
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/VerificationsMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/VerificationsMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/VerificationsMacro.groovy	(revision 3653)
@@ -0,0 +1,259 @@
+// Auteur Matthieu Quignard, Alexey Lavrentev
+// Date : 14 janvier 2019
+
+/**********
+Vérifications automatiques :
+1. Repère les mentions sans catégorie : CHECK > CAT
+2. Repère les mentions sans référent : CHECK > REF
+3. Supprime les ponctuations en début et en fin de mention : CHECK > BORNES
+4. Supprime les prépositions autres que 'de' en début de mention : CHECK > BORNES
+5. Supprime automatiquement toutes les mentions vides = sans aucun mot = de longueur 0
+6. Détecter les mentions qui ont exactement les mêmes bornes  : CHECK > DOUBLON
+7 (option). Détecter les pronoms hors mention : CHECK > NEW
+***********/
+
+package org.txm.macro.urs.democrat
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.urs.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+// TODO : ajouter les étiquettes équivalentes issues du tagset TreeTagger
+// Ponctuations et Prépositions
+def interditsAuDebut = ["PONfbl", "PONfrt", "PONpxx", "PRE"]
+// Ponctuations
+def interditsALaFin = ["PONfbl", "PONfrt", "PONpxx"]
+// Pronoms en tous genres
+def listePronoms = ["PROadv", "PROcar", "PROdem", "PROimp", "PROind", "PROint", "PROper", "PROpos", "PROrel"]
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="Unité", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="pos_property_name", usage="Etiquette de morphosyntaxe", widget="String", required=true, def="frpos")
+def pos_property_name
+@Field @Option(name="cat_name", usage="Propriété CATEGORIE", widget="String", required=true, def="CATEGORIE")
+def cat_name
+@Field @Option(name="ref_name", usage="Propriété REF", widget="String", required=true, def="REF")
+def ref_name
+@Field @Option(name="checkPronouns", usage="Vérifier les pronoms oubliés", widget="Boolean", required=true, def="true")
+def checkPronouns
+
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+CQI = CQPSearchEngine.getCqiClient()
+word = corpus.getWordProperty()
+posProperty = corpus.getProperty(pos_property_name)
+if (posProperty == null) {
+	println "Error: CQP corpus does not contains the word property with name=$pos_property_name"
+	return
+}
+
+analecCorpus = URSCorpora.getCorpus(corpus)
+vue = URSCorpora.getVue(corpus)
+structure = analecCorpus.getStructure()
+
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+
+if (!structure.getUniteProperties(unit_type).contains(cat_name)) { 
+	println "Erreur : les unités $unit_type n'ont pas de propriété $cat_name"
+	return
+}
+
+if (!structure.getUniteProperties(unit_type).contains(ref_name)) { 
+	println "Erreur : les unités $unit_type n'ont pas de propriété $ref_name"
+	return
+}
+
+println "Détection des pronoms oubliés : $checkPronouns"
+
+// Reinitialiser la propriété CHECK
+if (!structure.getUniteProperties(unit_type).contains("CHECK")) {
+	analecCorpus.ajouterProp(Unite.class, unit_type, "CHECK")
+} else {
+	println "Nettoyage des anciennes annotations CHECK"
+  	def tmpvalues = new HashSet()
+	tmpvalues.addAll(structure.getValeursProp(Unite.class, unit_type, "CHECK"));
+	for (String val : tmpvalues) {
+		structure.supprimerVal(Unite.class, unit_type, "CHECK", val);
+		//println "suppression de l'étiquette $val"
+	}
+}
+
+structure.ajouterVal(Unite.class, unit_type, "CHECK", "DONE")
+
+	
+
+def nModified = 0
+def nIgnored = 0
+def nDeleted = 0
+def nAdded = 0
+
+def garbageBin = []
+
+def nToks = corpus.getSize()
+def tokenIndex = new int[nToks]
+
+def i = 0
+for (i=0 ; i< nToks ; i++) tokenIndex[i] = 1
+
+errors = new HashMap()
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+
+// pour les doublons
+def lastUnit = null
+
+for (Unite unit : units) { // process all units
+	def erreur = ""
+	
+	// 1. Catégories vides
+	def cat = unit.getProp( cat_name );
+	if (cat == "") erreur += "CAT "
+	
+	// 2. Référents vides (plus grave) ; pas besoin de catégories
+	def ref = unit.getProp( ref_name );
+	if (ref == "") erreur += "REF "
+	
+	// 3. Suppression des erreurs initiales ; besoin de catégories
+	int[] positions = null
+	if (unit.getDeb() == unit.getFin()) positions = [unit.getDeb()]
+	else positions = (unit.getDeb()..unit.getFin())
+	def Mention = CQI.cpos2Str(posProperty.getQualifiedName(), positions)
+	
+	def isOK = false
+	while (isOK == false) {
+	   if (interditsAuDebut.contains(Mention[0])) {
+	      if (positions.size() == 1) {
+	         erreur += "SUPPR"
+	         isOK = true
+	      } else {
+	         def debut = unit.getDeb()
+	         unit.setDeb(  debut + 1 )
+	         
+	         if (unit.getDeb() == unit.getFin()) positions = [unit.getDeb()]
+			 else positions = (unit.getDeb()..unit.getFin())
+			 Mention = CQI.cpos2Str(posProperty.getQualifiedName(), positions)
+			 if (!erreur.contains("BORNESG")) erreur += "BORNESG "
+	      }
+	   } else { 
+	      isOK = true
+	   } 
+	}
+	
+	
+	// 4. Suppression des erreurs de borne de fin ; besoin de catégories
+	if (unit.getDeb() == unit.getFin()) positions = [unit.getDeb()]
+	else positions = (unit.getDeb()..unit.getFin())
+	Mention = CQI.cpos2Str(posProperty.getQualifiedName(), positions)
+	
+	isOK = false
+	while ((isOK == false) && (erreur != "remove")) {
+		def n = Mention.size()
+		if (interditsALaFin.contains(Mention[ n-1 ])) {
+			if (positions.size() == 1) {
+	         if (!erreur.contains("SUPPR")) erreur += "SUPPR"
+	         isOK = true
+	      } else {
+	         def fin = unit.getFin()
+	         unit.setFin(  fin - 1 )
+	         
+	         if (unit.getDeb() == unit.getFin()) positions = [unit.getDeb()]
+			 else positions = (unit.getDeb()..unit.getFin())
+			 Mention = CQI.cpos2Str(posProperty.getQualifiedName(), positions)
+			 if (!erreur.contains("BORNESD")) erreur += "BORNESD "
+	      }
+		} else isOK = true
+	}
+	
+	// 5. Suppression des unités problématiques (bornes incohérentes ou mot vide) ; pas besoin de catégories
+	def forme = CQI.cpos2Str(word.getQualifiedName(), positions)[0].trim().toLowerCase()
+	
+	if (erreur == "remove") {}
+	else if (unit.getFin() < unit.getDeb()) {
+	   println "ERREUR GRAVE : segmentation incohérente"
+	   erreur = "remove"
+	} else if ( forme.length() == 0 ) {
+	   println "ERREUR GRAVE : unité sans mot"
+	   erreur = "remove"
+	}
+	
+	// 6. Détection des doublons ; pas besoin de catégories
+	if (lastUnit != null) {
+	   if ((unit.getDeb() == lastUnit.getDeb()) && (unit.getFin() == lastUnit.getFin()) ) {
+	   		erreur += " DOUBLON "
+	   }
+	}
+	lastUnit = unit
+	
+	
+	erreur = erreur.trim()
+	if (erreur == "remove") {
+	    garbageBin.add( unit )
+		nDeleted++
+	} else if (erreur != "") {
+		vue.setValeurChamp(unit, "CHECK", erreur)
+		nModified++
+	} else {
+		nIgnored++
+	}
+	
+	// mise à jour des tokens couverts
+	for (int p=unit.getDeb() ; p <= unit.getFin() ; p++) {
+	   tokenIndex[p] = 0
+	}
+}
+
+// Suppression effective des unités incohérentes
+garbageBin.each {
+   analecCorpus.supUnite( it )
+}
+
+// 7. Ajouter les pronoms non couverts par une annotation ; besoin de catégories
+// Parcourir les tokens non couverts ; obtenir leur POS et créer une unité si c'est un pronom
+
+if (checkPronouns) {
+	println "Détection des pronoms oubliés"
+	for (i=0 ; i < nToks ; i++) {
+    	if (tokenIndex[i] > 0) {
+			Mention = CQI.cpos2Str(posProperty.getQualifiedName(), i)
+			if (listePronoms.contains(Mention[0])) {
+	    		def props = [:]
+        		props["CHECK"] = "NEW"
+        		Unite u = analecCorpus.addUniteSaisie(unit_type, i, i, props)
+        		vue.setValeurChamp(u, "CHECK", "NEW")
+	    		nAdded++
+	    	}
+		}
+	}
+}
+
+if (nAdded + nModified + nDeleted > 0) corpus.setIsModified(true);
+
+println "Result:"
+println "- $nModified units of type $unit_type have been modified."
+println "- $nDeleted units of type $unit_type have been deleted."
+println "- $nIgnored units of type $unit_type have not been modified."
+println "- $nAdded forgotten pronominal units of type $unit_type have been added.\n"
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/RetoucheComplementDuNomMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/RetoucheComplementDuNomMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/RetoucheComplementDuNomMacro.groovy	(revision 3653)
@@ -0,0 +1,130 @@
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.democrat
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.analec.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+
+/*  MACRO pour corriger une erreur d'annotation
+    Retirer le "de" ou le "d'" (forme élidée) du complément du nom
+
+   Algo : 
+   POUR CHAQUE MENTION dont le premier mot est "de" (en minuscules)
+   SI     il existe une autre MENTION dans laquelle celle-ci est totalement incluse
+   ALORS  incrémenter d'un mot la frontière gauche de la mention
+   Ajouter la categorie CDN.CHECK pour qu'on puisse verifier facilement le job.
+   
+   Cette macro ne s'appuie pas sur des catégories morphosyntaxiques. 
+   On peut donc la faire tourner avant les frpos2cattex ou fropos2cattex
+   
+   Auteur : Matthieu QUIGNARD
+   Date : 18 janvier 2019
+*/
+
+// BEGINNING OF PARAMETERS
+
+// Declare each parameter here
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="category_name", usage="", widget="String", required=true, def="CATEGORIE")
+def category_name
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+CQI = CQPSearchEngine.getCqiClient()
+word = corpus.getWordProperty()
+
+analecCorpus = URSCorpora.getCorpus(corpus)
+vue = URSCorpora.getVue(corpus)
+structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+
+
+// Si la structure d'annotation ne contient pas CATEGORIE, on la crée avec ses valeurs
+if (!structure.getUniteProperties(unit_type).contains(category_name)) { 
+   structure.ajouterProp(Unite.class, unit_type, category_name)
+}
+
+def check_cat = "CDN.CHECK"
+structure.ajouterVal(Unite.class, unit_type, category_name, check_cat)
+
+if (!vue.getTypesAVoir(Unite.class).contains(unit_type)) {
+	vue.ajouterType(Unite.class, unit_type)
+}
+if (!vue.getNomsChamps(Unite.class, unit_type).contains(category_name)) {
+	vue.ajouterProp(Unite.class, unit_type, category_name)
+}
+
+def nModified = 0
+def nIgnored1 = 0
+def nIgnored2 = 0
+def compteur = 0
+
+errors = new HashMap()
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+
+/* Test sur la premiere mention :
+def debut1 = units[1].getDeb()
+def fin1 = units[1].getFin()
+println "$debut1 - $fin1"
+units[1].setDeb( debut1 + 1)
+units[1].setFin( fin1 + 1)
+def debut2 = units[1].getDeb()
+def fin2 = units[1].getFin()
+println "$debut2 - $fin2"
+*/
+
+for (Unite unit : units) { // process all units
+	
+	def debut = unit.getDeb()
+	def fin = unit.getFin()
+	def premierMot = CQI.cpos2Str(word.getQualifiedName(), debut)[0]
+		
+	if ((premierMot != "de") && (premierMot !="d'")) {
+		nIgnored1++
+		compteur++
+		continue
+	} else {
+		for (i = compteur-1; i>=0 ; i--) {
+			def u = units[i]
+			def udeb = u.getDeb()
+			def ufin = u.getFin()
+			if (ufin >= fin) {
+			   println "\nAVANT => Unit $compteur : $debut - $fin"
+			   if (fin > debut) unit.setDeb( ++debut ) 
+			   else println "not resizing"
+			   def debut2 = unit.getDeb()
+			   def fin2 = unit.getFin()
+			   println "APRES => Unit $compteur : $debut2 - $fin2"
+			   unit.getProps().put(category_name, check_cat)
+			   break
+			}
+		}
+		if (i <0) nIgnored2++
+		else nModified++
+		compteur++
+	} 
+}
+
+println "\nResult:"
+println "- $nModified units have been modified."
+println "- $nIgnored1 units have been ignored because not concerned"
+println "- $nIgnored2 units have been ignored because no overlap.\n"
+println "Total ($compteur)."
+
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/CreationAnaphoresMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/CreationAnaphoresMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/CreationAnaphoresMacro.groovy	(revision 3653)
@@ -0,0 +1,81 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.democrat
+
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.Relation;
+import visuAnalec.elements.Schema
+import visuAnalec.elements.Unite;
+import visuAnalec.vue.Vue
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type",usage="", widget="String", required=true, def="MENTION")
+		String unit_type
+@Field @Option(name="schema_type",usage="", widget="String", required=true, def="CHAINE")
+		String schema_type
+if (!ParametersDialog.open(this)) return;
+
+int nCreated = 0 // count the number of created RELATION
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus);
+Structure structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+if (!structure.getSchemas().contains(schema_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains schema with name=$schema_type"
+	return
+}
+if (!structure.getRelations().contains("ANAPHORE")) { // update the structure if needed
+	println "Creating the 'ANAPHORE' relation in the structure"
+	structure.ajouterType(Relation.class, "ANAPHORE")
+	analecCorpus.ajouterProp(Relation.class, "ANAPHORE", "TYPE")
+	analecCorpus.ajouterVal(Relation.class, "ANAPHORE", "TYPE", "COREFERENTE")
+	analecCorpus.ajouterVal(Relation.class, "ANAPHORE", "TYPE", "ASSOCIATIVE")
+}
+if (analecCorpus.getRelations("ANAPHORE").size() > 0) {
+	println "Error: This macro can't update existing Relations"
+	return
+}
+Vue vue = URSCorpora.getVue(corpus)
+if (!vue.getTypesAVoir(Relation.class).contains("ANAPHORE")) {
+	vue.ajouterType(Relation.class, "ANAPHORE")
+}
+if (!vue.getNomsChamps(Relation.class, "ANAPHORE").contains("TYPE")) {
+	vue.ajouterProp(Relation.class, "ANAPHORE", "TYPE")
+}
+
+for (Schema schema : analecCorpus.getSchemas(schema_type)) { // parse all CHAINE
+	def units = []
+	for (Unite unit : schema.getUnitesSousjacentes()) { // keep only the 'unit_type' units
+		if (unit.type.equals(unit_type)) units << unit
+	}
+	units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() } // sort them
+	
+	for (int i = 0 ; i < units.size() - 1 ; i++) { // build RELATIONS and don't process the last unit
+		println "creating relation with "+units[i+1].getProps()+", "+units[i].getProps()
+		Relation relation = new Relation("ANAPHORE", units[i+1], units[i])
+		relation.getProps().put("TYPE", "COREFERENTE")
+		analecCorpus.addRelationLue(relation)  // add the new relation
+		nCreated++;
+	}
+}
+
+println "nCreated=$nCreated"
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/BuildSectionsMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/BuildSectionsMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/BuildSectionsMacro.groovy	(revision 3653)
@@ -0,0 +1,67 @@
+package org.txm.macro.urs.democrat
+
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.rcpapplication.views.*
+import org.txm.searchengine.cqp.corpus.query.*
+import org.txm.Toolbox
+
+def scriptName = this.class.getSimpleName()
+def utils = new org.txm.macro.urs.exploit.CQPUtils()
+
+// Création des 4 sous-corpus de chapitres
+
+[1, 2, 3, 4].each { chapitre ->
+	res = gse.run(SubCorpusMacro, ["args":["name":"Chapitre "+chapitre, "query":"[_.div_n1=\""+chapitre+"\"] expand to div1" ],
+                                "selection":selection,
+                                "selections":selections,
+                                "corpusViewSelection":corpusViewSelection,
+                                "corpusViewSelections":corpusViewSelections,
+                                "monitor":monitor])
+	if (!res) println "** problem calling SubCorpusMacro."
+}
+
+
+// Définition des paragraphes dans les 4 chapitres
+
+def para = [
+[1, 14, 17, 22],
+[2, 29, 44, 46],
+[3, 53, 63, 66],
+[4, 74, 75, 79]
+]
+
+// get the CQP corpus
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Corpus view selection is no a corpus: $corpusViewSelection"
+	return false;
+}
+def corpus = corpusViewSelection
+if (corpus.getName() != "DIDEROTESSAIS") {
+	println "Warning: this macro was made to work for the DIDEROTESSAIS corpus"
+}
+	
+para.each { chapitre ->
+
+	println chapitre
+
+	def subcorpus = corpus.getSubcorpusByName("Chapitre "+chapitre[0])
+
+	println "chap = "+subcorpus
+
+	[1, 2, 3].each { num ->
+
+		def p = chapitre[num]
+
+		println "p = "+p
+
+		name = "p "+p
+		query = '[_.p_n=\"'+p+'\"] expand to p'
+
+		res = gse.run(SubCorpusMacro, ["args":[ "name":name, "query":query ],
+                                "corpusViewSelections":[subcorpus],
+								"corpusViewSelection":subcorpus,
+                                "monitor":monitor])
+
+	} // [1, 2, 3].each
+
+} // para.each
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/LongueurDesMentionsMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/LongueurDesMentionsMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/LongueurDesMentionsMacro.groovy	(revision 3653)
@@ -0,0 +1,136 @@
+package org.txm.macro.urs.democrat
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+/*
+ Calcule la longueur des mentions et attribue une valeur (1, 2, 3 ou plus) dans la propriété "LONGUEUR"
+ */
+
+nLongueur1 = 0
+nLongueur2 = 0
+nLongueur3 = 0
+
+def testRules(def positions, def Mention) {
+
+	if (Mention.length == 1) {
+		catégorie = "1"
+		nLongueur1++
+	}
+	else if (Mention.length == 2) {
+		catégorie = "2"
+		nLongueur2++
+	}
+	else {
+		catégorie = "3 ou plus"
+		nLongueur3++
+	}
+
+	return catégorie
+}
+
+//
+// FIN DE LA DÉFINITION DES RÈGLES
+//
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="pos_property_name", usage="", widget="String", required=true, def="pos")
+def pos_property_name
+@Field @Option(name="reset", usage="", widget="Boolean", required=true, def="true")
+def reset
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+CQI = CQPSearchEngine.getCqiClient()
+word = corpus.getWordProperty()
+posProperty = corpus.getProperty(pos_property_name)
+if (posProperty == null) {
+	println "Error: CQP corpus does not contains the word property with name=$pos_property_name"
+	return
+}
+analecCorpus = URSCorpora.getCorpus(corpus)
+vue = URSCorpora.getVue(corpus)
+structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+
+LONGUEUR = "LONGUEUR"
+// Si la structure d'annotation ne contient pas LONGUEUR, on la crée avec ses valeurs
+if (!structure.getUniteProperties(unit_type).contains(LONGUEUR)) {
+	// la propriété
+	analecCorpus.ajouterProp(Unite.class, unit_type, LONGUEUR)
+	// les valeurs
+
+	structure.ajouterVal(Unite.class, unit_type, LONGUEUR, "1")
+	structure.ajouterVal(Unite.class, unit_type, LONGUEUR, "2")
+	structure.ajouterVal(Unite.class, unit_type, LONGUEUR, "3 ou plus")
+
+	//...
+}
+
+if (!vue.getTypesAVoir(Unite.class).contains(unit_type)) {
+	vue.ajouterType(Unite.class, unit_type)
+}
+if (!vue.getNomsChamps(Unite.class, unit_type).contains(LONGUEUR)) {
+	vue.ajouterProp(Unite.class, unit_type, LONGUEUR)
+}
+
+def nModified = 0
+def nIgnored = 0
+
+errors = new HashMap()
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+for (Unite unit : units) { // process all units
+
+	def prop = unit.getProp(LONGUEUR)
+	if (!reset && prop != null && prop.length() > 0) continue // l'unité a déjà une LONGUEUR
+
+	int[] positions = null
+	if (unit.getDeb() == unit.getFin()) positions = [unit.getDeb()]
+	else positions = (unit.getDeb()..unit.getFin())
+
+	//def Mention = CQI.cpos2Str(posProperty.getQualifiedName(), positions)
+	def cat = testRules(positions, positions)
+
+	if (cat != null) {
+		vue.setValeurChamp(unit, LONGUEUR, cat)
+		nModified++
+	} else {
+		nIgnored++
+	}
+}
+
+println "Result:"
+println "- $nModified units of type $unit_type have been modified."
+println "- $nIgnored units of type $unit_type have not been modified.\n"
+
+println "- $nLongueur1 mentions de longueur 1."
+println "- $nLongueur2 mentions de longueur 2."
+println "- $nLongueur3 mentions de longueur 3 ou plus.\n"
+
+if (errors.size() > 0) {
+	println "Some rules should be added to this macro to process the following remaining 'FROPOS / words' values:"
+	errors.keySet().each { println "fropos="+it+"\twords="+errors[it].join(" | ") }
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/SUJ-PARTINF.txt
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/SUJ-PARTINF.txt	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/SUJ-PARTINF.txt	(revision 3653)
@@ -0,0 +1,19 @@
+Macro  : SUJ-PARTINF
+Auteur : Matthieu QUIGNARD
+Date   : 05 Février 2019
+
+Recatégorise les mentions étiquetées en SUJ.ZERO pour distinguer les cas
+des verbes conjugués (qui restent en SUJ.ZERO) 
+des verbes à l'infinitif ou au participe passé/présent qui, eux, vont
+passer sous la catégorie SUJ.PARTINF
+
+Cette macro est réversible.
+Il suffit d'invoquer la macro ChercherRemplacer et substituer
+CATEGORIE=SUJ.PARTINF
+en 
+CATEGORIE=SUJ.ZERO
+
+NB : fonctionne avec le tagset fro (ancien français) et le tagset TreeTagger.
+Infinitif : VERinf  VER:infi
+Part.Pass : VERppa  VER:pper
+Part.Pres : VERppe   VER:ppre

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/SUJ-PARTINF.txt
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Frpos2CategorieDemocratMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Frpos2CategorieDemocratMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Frpos2CategorieDemocratMacro.groovy	(revision 3653)
@@ -0,0 +1,258 @@
+// @author Bruno Oberlé (2017-04-01 21:50)
+
+/*
+Définit la catégorie grammaticale du maillon d'après le champ `frpos'
+(tagset de TreeTagger).  Le script est adapté de
+http://svn.code.sf.net/p/txm/code/trunk/plugins/Analec/AnalecRCP/src/org/txm/macro/analec/Fropos2CategorieMacro.groovy.
+
+Voici la liste des catégories grammaticales retenues (manuel d'annotation de
+Democrat):
+- GN: Groupe Nominal (le petit chat, le chat, le même, ce chat etc.)
+- POSS: Possessif (mon, ton son, ma, ta, sa, mes, tes, ses, notre, votre,
+  leur, nos, vos, leurs)
+- PR: Pronom (moi, toi, lui, elle, nous, vous, eux, elles, le tien, le mien,
+  moi-même etc.)
+- PR_CL_O: Pronom Clitique Objet (me, te, le, la, les, lui, leur, y, en)
+- PR_CL_R: Pronom Clitique Réfléchi
+- PR_CL_S: Pronom Clitique Sujet (je, tu, il, elle, on, nous, vous, ils,
+  elles)
+- PR_REL: Pronom Relatif (qui, que, quoi, dont, où, lequel, quiconque etc.)
+- PR_WH: Pronom Interrogatif (qui, que, quoi, lequel etc.)
+
+Le script ne peut pas désambiguïser les pronoms clitiques de même forme
+(`nous' est-il un sujet, un objet ou un réfléchi?).  Dans ce cas, le script
+opte pour le sujet (ou pour l'objet si l'ambiguïté n'est que entre objet et
+réfléchi).
+
+Quand il n'y a aucune information disponible (erreurs de l'étiqueteur), la
+valeur est UNDEFINED.
+
+L'algorithme est décrit ici:
+https://groupes.renater.fr/wiki/democrat/prive/txm_annotation_exploitation
+
+*/
+
+package org.txm.macro.urs.democrat
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+def testClitic(def position, def frpos) {
+
+   // je me sers de la forme, parce qu'il est difficile de savoir quel est le
+   // lemme de "elle" ("il"?), de "te" ("tu"?) ou encore de "leur"
+   def form = CQI.cpos2Str(word.getQualifiedName(), position)[0].toLowerCase()
+   if (     form == "je" || form == "j'"
+         || form == "tu" || form == "t'"
+         || form == "il"
+         || form == "elle"
+         || form == "on"
+         || form == "vous"
+         || form == "nous"
+         || form == "ils"
+         || form == "elles" ) {
+      return "PR_CL_S"
+   } else if (form == "me" || form == "m'"
+           || form == "te"
+           || form == "le" || form == "l'"
+           || form == "la"
+           || form == "lui"
+           || form == "leur"
+           || form == "les" ) {
+      return "PR_CL_O"
+   } else if (form == "se" || form == "s'") {
+      return "PR_CL_R"
+   }
+   return null
+
+}
+
+def testPhrase(def positions, def Mention) {
+
+   // on doit regarder ce qui apparaît en premier:
+   // - ce peut être un nom, comme dans `le petit chat que j'ai adopté'
+   // - ce peut être un pronom relatif, comme dans `(le livre) dans lequel
+   // j'ai lu cette histoire...'
+   // NOTE: dans Democrat, on n'annote pas, bizarrement, la relative dans le
+   // maillon, donc, dans un GN on n'a jamais de relatif inclus.  On aura donc
+   // toujours `[le petit chat] [que] [j']ai adopté'.  Mais tout le monde
+   // n'annote pas de la sorte...
+   for (def i=0; i<Mention.length; i++) {
+         def mention = Mention[i]
+         //def form = CQI.cpos2Str(word.getQualifiedName(), positions[i])[0]
+         if (mention == "NOM" || mention == "NAM") {
+            return "GN"
+         } else if (mention == "PRO:REL") {
+            return "PR_REL"
+         }
+    }
+
+    return null
+
+}
+
+def testWhPronoun(position, mention) {
+   def form = CQI.cpos2Str(word.getQualifiedName(), position)[0]
+   if (mention == "PRO" && (form == "qui" || form == "que" || form == "lequel")) {
+      return "PR_WH"
+   }
+   return null
+
+}
+
+def testRules(def positions, def Mention) {
+	def catégorie = null
+
+   // a possessive (mon, ma...)
+   if (Mention.length == 1 && Mention.contains("DET:POS"))
+      catégorie = "POSS"
+
+   // a clitic (subject: je, tu...; object: me, te; reflexive: se)
+   if (!catégorie && Mention.length == 1 && Mention.contains("PRO:PER"))
+      catégorie = testClitic(positions[0], Mention[0])
+
+   // an interrogative pronoun
+   if (!catégorie && Mention.length == 1)
+      catégorie = testWhPronoun(positions[0], Mention[0])
+
+   // a noun phrase or a relative pronoun
+   if (!catégorie)
+      catégorie = testPhrase(positions, Mention)
+
+   // some other kind of pronouns
+   if (!catégorie
+         && (   Mention.contains("PRO")
+             || Mention.contains("PRO:POSS")
+             || Mention.contains("PRO:IND")
+             || Mention.contains("PRO:DEM")
+             || Mention.contains("PRO:PER") )
+         && !Mention.contains("NOM")
+         && !Mention.contains("NAM") )
+      catégorie = "PRO"
+
+// Fin des règles, aucune n'a matchée. On stocke le pattern  qu'on affichera à la fin.
+   if (!catégorie) {
+      catégorie = "UNDEFINED" // clear the field
+		def forms = CQI.cpos2Str(word.getQualifiedName(), positions)
+		if (!errors.containsKey(Mention)) errors[Mention] = new HashSet()
+		errors[Mention] << forms
+	}
+	
+	return catégorie
+}
+
+//
+// FIN DE LA DÉFINITION DES RÈGLES
+//
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="pos_property_name", usage="", widget="String", required=true, def="pos")
+def pos_property_name
+@Field @Option(name="reset", usage="", widget="Boolean", required=true, def="true")
+def reset
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+CQI = CQPSearchEngine.getCqiClient()
+word = corpus.getWordProperty()
+posProperty = corpus.getProperty(pos_property_name)
+if (posProperty == null) {
+	println "Error: CQP corpus does not contains the word property with name=$pos_property_name"
+	return
+}
+analecCorpus = URSCorpora.getCorpus(corpus)
+vue = URSCorpora.getVue(corpus)
+structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+
+CATEGORIE = "CATEGORIE"
+// Si la structure d'annotation ne contient pas CATEGORIE, on la crée avec ses valeurs
+if (!structure.getUniteProperties(unit_type).contains(CATEGORIE)) { 
+
+// FIXME: dans le script original (see also
+// http://forge.cbp.ens-lyon.fr/redmine/issues/2065), on utilise
+// analecCorpus.ajouterProp/Val, mais cela ne marche pas dans ma version de
+// TXM-Analec --> je retourne donc à structure.ajouterProp/Val
+
+// la propriété
+	structure.ajouterProp(Unite.class, unit_type, CATEGORIE)
+// les valeurs
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "GN")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "POSS")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PRO")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PR_CL_O")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PR_CL_S")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PR_CL_R")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PR_REL")
+	structure.ajouterVal(Unite.class, unit_type, CATEGORIE, "PR_WH")
+//...
+}
+
+if (!vue.getTypesAVoir(Unite.class).contains(unit_type)) {
+	vue.ajouterType(Unite.class, unit_type)
+}
+if (!vue.getNomsChamps(Unite.class, unit_type).contains(CATEGORIE)) {
+	vue.ajouterProp(Unite.class, unit_type, CATEGORIE)
+}
+
+def nModified = 0
+def nIgnored = 0
+
+errors = new HashMap()
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+for (Unite unit : units) { // process all units
+	
+	def prop = unit.getProp(CATEGORIE)
+	if (!reset && prop != null && prop.length() > 0) continue // l'unité a déjà une CATEGORIE
+	
+	int[] positions = null
+	if (unit.getDeb() == unit.getFin()) positions = [unit.getDeb()]
+	else positions = (unit.getDeb()..unit.getFin())
+	
+	def Mention = CQI.cpos2Str(posProperty.getQualifiedName(), positions)
+	def cat = testRules(positions, Mention)
+
+	if (cat != null) {
+		// following line in the original script but doesn't work for me:
+      // vue.setValeurChamp(unit, CATEGORIE, cat)
+      unit.getProps().put(CATEGORIE, cat)
+		nModified++
+	} else {
+		nIgnored++
+	}
+}
+
+println "Result:"
+println "- $nModified units of type $unit_type have been modified."
+println "- $nIgnored units of type $unit_type have not been modified.\n"
+
+if (errors.size() > 0) {
+	println "Some rules should be added to this macro to process the following remaining 'FROPOS / words' values:"
+	errors.keySet().each { println "fropos="+it+"\twords="+errors[it].join(" | ") }
+}
+
+// udpate the view (also see also
+// http://forge.cbp.ens-lyon.fr/redmine/issues/2065)
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Fropos2CategorieMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Fropos2CategorieMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/Fropos2CategorieMacro.groovy	(revision 3653)
@@ -0,0 +1,152 @@
+package org.txm.macro.urs.democrat
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+def testRules(def positions, def Mention) {
+	def catégorie = null
+
+// DÉFINITION DES RÈGLES
+// elles sont testées les unes après les autres. 
+// Dès qu'une règle est appliquée les suivantes sont ignorées.
+
+// Règles de type CONTIENT
+
+	     if (Mention.contains("NOMpro")) catégorie = "Nom Propre"
+	else if (Mention.contains("DETpos")) catégorie = "Dét Possessif"
+//  ...
+
+// Règles de type COMMENCE ET NE CONTIENT PAS	
+
+	else if (Mention.first() == "DETpos" && !Mention.contains("NOMpro")) catégorie = "GN Possessif"
+	else if (Mention.first() == "DETdem" && !Mention.contains("NOMpro")) catégorie = "GN Démonstratif"
+//  ...
+
+// Règles de type CONTIENT PLUSIEURS	
+
+	else if (Mention.contains("PROadv") || Mention.contains("ADVgen.PROadv")) catégorie = "Pronom Adverbial"
+//  ...
+
+// Règles de type CONTIENT ET NE CONTIENT PAS
+
+	else if (
+			 ( Mention.contains("DETdef") || Mention.contains("PRE.DETdef") )
+			  &&
+			  !Mention.contains("PROpos") && !Mention.contains("NOMpro") && !Mention.contains("PROcar")
+			) catégorie = "GN Défini"
+//  ...	
+
+// Fin des règles, aucune n'a matchée. On stocke le pattern  qu'on affichera à la fin.
+	else {
+		def forms = CQI.cpos2Str(word.getQualifiedName(), positions)
+		if (!errors.containsKey(Mention)) errors[Mention] = new HashSet()
+		errors[Mention] << forms
+	}
+	
+	return catégorie
+}
+
+//
+// FIN DE LA DÉFINITION DES RÈGLES
+//
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="pos_property_name", usage="", widget="String", required=true, def="pos")
+def pos_property_name
+@Field @Option(name="reset", usage="", widget="Boolean", required=true, def="true")
+def reset
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+CQI = CQPSearchEngine.getCqiClient()
+word = corpus.getWordProperty()
+posProperty = corpus.getProperty(pos_property_name)
+if (posProperty == null) {
+	println "Error: CQP corpus does not contains the word property with name=$pos_property_name"
+	return
+}
+analecCorpus = URSCorpora.getCorpus(corpus)
+vue = URSCorpora.getVue(corpus)
+structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+
+CATEGORIE = "CATEGORIE"
+// Si la structure d'annotation ne contient pas CATEGORIE, on la crée avec ses valeurs
+if (!structure.getUniteProperties(unit_type).contains(CATEGORIE)) { 
+// la propriété
+	analecCorpus.ajouterProp(Unite.class, unit_type, CATEGORIE)
+// les valeurs
+	analecCorpus.ajouterVal(Unite.class, unit_type, CATEGORIE, "Nom Propre")
+	analecCorpus.ajouterVal(Unite.class, unit_type, CATEGORIE, "Pronom Impersonnel")
+	analecCorpus.ajouterVal(Unite.class, unit_type, CATEGORIE, "Pronom Interrogatif")
+	analecCorpus.ajouterVal(Unite.class, unit_type, CATEGORIE, "Pronom Pronom cardinal")
+	analecCorpus.ajouterVal(Unite.class, unit_type, CATEGORIE, "Pronom Démonstratif")
+	analecCorpus.ajouterVal(Unite.class, unit_type, CATEGORIE, "Pronom Indéfini")
+	analecCorpus.ajouterVal(Unite.class, unit_type, CATEGORIE, "Pronom ordinal")
+	analecCorpus.ajouterVal(Unite.class, unit_type, CATEGORIE, "Pronom Relatif")
+//...
+}
+
+if (!vue.getTypesAVoir(Unite.class).contains(unit_type)) {
+	vue.ajouterType(Unite.class, unit_type)
+}
+if (!vue.getNomsChamps(Unite.class, unit_type).contains(CATEGORIE)) {
+	vue.ajouterProp(Unite.class, unit_type, CATEGORIE)
+}
+
+def nModified = 0
+def nIgnored = 0
+
+errors = new HashMap()
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+for (Unite unit : units) { // process all units
+	
+	def prop = unit.getProp(CATEGORIE)
+	if (!reset && prop != null && prop.length() > 0) continue // l'unité a déjà une CATEGORIE
+	
+	int[] positions = null
+	if (unit.getDeb() == unit.getFin()) positions = [unit.getDeb()]
+	else positions = (unit.getDeb()..unit.getFin())
+	
+	def Mention = CQI.cpos2Str(posProperty.getQualifiedName(), positions)
+	def cat = testRules(positions, Mention)
+	
+	if (cat != null) {
+		vue.setValeurChamp(unit, CATEGORIE, cat)
+		nModified++
+	} else {
+		nIgnored++
+	}
+}
+
+println "Result:"
+println "- $nModified units of type $unit_type have been modified."
+println "- $nIgnored units of type $unit_type have not been modified.\n"
+
+if (errors.size() > 0) {
+	println "Some rules should be added to this macro to process the following remaining 'FROPOS / words' values:"
+	errors.keySet().each { println "fropos="+it+"\twords="+errors[it].join(" | ") }
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/PremierMaillonMacro.groovy
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/PremierMaillonMacro.groovy	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/org/txm/macro/urs/democrat/PremierMaillonMacro.groovy	(revision 3653)
@@ -0,0 +1,92 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.democrat
+
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.Unite;
+import visuAnalec.vue.Vue
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a MainCorpus: "+corpusViewSelection
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type",usage="", widget="String", required=true, def="MENTION")
+String unit_type
+@Field @Option(name="reset",usage="", widget="Boolean", required=true, def="true")
+boolean reset
+
+if (!ParametersDialog.open(this)) return;
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus);
+Structure structure = analecCorpus.getStructure()
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Error: corpus structure does not contains unit with name=$unit_type"
+	return
+}
+def props = structure.getUniteProperties(unit_type)
+
+String NEW = "NEW"
+String REF = "REF"
+String YES = "YES"
+String NO = "NO"
+if (!props.contains(NEW)) { // update the structure if needed
+	analecCorpus.ajouterProp(Unite.class, unit_type, NEW);
+	analecCorpus.ajouterVal(Unite.class, unit_type, NEW, "YES");
+	analecCorpus.ajouterVal(Unite.class, unit_type, NEW, "NO");
+}
+
+if (!props.contains(REF)) { // check the unit_type units have the REF property
+	println "Error: $unit_type units have no proprerty named 'REF'"
+	return
+}
+
+Vue vue = URSCorpora.getVue(corpus)
+if (!vue.getTypesAVoir(Unite.class).contains(unit_type)) {
+	vue.ajouterType(Unite.class, unit_type)
+}
+if (!vue.getNomsChamps(Unite.class, unit_type).contains(NEW)) {
+	vue.ajouterProp(Unite.class, unit_type, NEW)
+}
+
+int nIgnored = 0; // number of units ignored
+int nYes = 0 // number of "YES" unit set
+int nNo = 0 // number of "NO" unit set
+
+def allRefs = new HashSet<String>() // store the references already seen, allow to set the 'NEW' property to 'YES' or 'NO'
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+for (Unite unit : units) {
+	def prop = unit.getProp(NEW);
+	def ref = unit.getProp(REF);
+	if (reset || prop == null || prop.length() == 0) {
+		if (allRefs.contains(ref)) {
+			unit.getProps().put(NEW, NO)
+			nNo++
+		} else { // this is the first MENTION of the CHAINE
+			allRefs << ref
+			unit.getProps().put(NEW, YES)
+			nYes++
+		}
+	} else {
+		// nothing to do "NEW" already exists
+		nIgnored++
+	}
+}
+
+println "nIgnored=$nIgnored"
+println "nYes=$nYes"
+println "nNo=$nNo"
\ No newline at end of file
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/analecrcp/Activator.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/analecrcp/Activator.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/analecrcp/Activator.java	(revision 3653)
@@ -0,0 +1,50 @@
+package analecrcp;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+	// The plug-in ID
+	public static final String PLUGIN_ID = "AnalecRCP"; //$NON-NLS-1$
+
+	// The shared instance
+	private static Activator plugin;
+	
+	/**
+	 * The constructor
+	 */
+	public Activator() {
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+	 */
+	public void start(BundleContext context) throws Exception {
+		super.start(context);
+		plugin = this;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+	 */
+	public void stop(BundleContext context) throws Exception {
+		plugin = null;
+		super.stop(context);
+	}
+
+	/**
+	 * Returns the shared instance
+	 *
+	 * @return the shared instance
+	 */
+	public static Activator getDefault() {
+		return plugin;
+	}
+
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/analecrcp/Activator.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauEditeur.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauEditeur.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauEditeur.java	(revision 3653)
@@ -0,0 +1,355 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec;
+
+import java.awt.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.text.Document;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.StyleConstants;
+import visuAnalec.Message.*;
+import visuAnalec.elements.*;
+import visuAnalec.texte.*;
+import visuAnalec.texte.PanneauTexte.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.vue.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class PanneauEditeur extends JPanel implements VueListener {
+  private enum Commandes {
+    GESTION_UNITES,
+    GESTION_RELATIONS,
+    GESTION_SCHEMAS,
+    MODIF_TEXTE;
+    private static Commandes getCommande(Class<? extends Element> classe) {
+      if (classe==Unite.class) return GESTION_UNITES;
+      if (classe==Relation.class) return GESTION_RELATIONS;
+      if (classe==Schema.class) return GESTION_SCHEMAS;
+      throw new UnsupportedOperationException("sous-classe non traitée");
+    }
+  }
+  private Vue vue;
+  private PanneauAffTexte panneauTexte;
+  private JPanel panneauOccurrences;
+  private PanneauChamps panneauChamps;
+  private Commandes commandes = null;
+  private HashMap<Commandes, PanneauCommandes> panneauxCommandes =
+          new HashMap<Commandes, PanneauCommandes>();
+  private HashMap<Commandes, String> titresPanneauxCommandes =
+          new HashMap<Commandes, String>();
+  private JDialog fenetreModifTexte;
+  private PanneauModifTexte panneauModifTexte;
+  private PanneauCommandesModifTexte panneauCommandesModifTexte;
+  private String recherche = "";
+  private Element elementCourant;
+
+  public static class ElementMarque {
+    public Element elt;
+    public String id;
+    public TypeMarquage marque;
+    public ElementMarque(Element elt, TypeMarquage marque, String id) {
+      this.elt = elt;
+      this.id = id;
+      this.marque = marque;
+    }
+  }
+
+  public static abstract class PanneauCommandes extends Box {
+    protected Vue vue;
+    protected PanneauAffTexte panneauTexte;
+    PanneauCommandes(Vue vue, PanneauAffTexte panneauTexte) {
+      super(BoxLayout.Y_AXIS);
+      this.vue = vue;
+      this.panneauTexte = panneauTexte;
+    }
+    public Vue getVue() {
+      return vue;
+    }
+    abstract public void reafficher();        // quand la vue n'a pas changé
+    abstract public void reinitialiser();     // quand la vue a changé
+    abstract public void elementSuivant(int sens);
+    abstract public Element elementSelectionne();
+    abstract public void editerElement(Element elt);
+    abstract public void traiterElementEvent(ElementEvent evt);
+    abstract public void traiterSourisEvent(PanneauAffTexte.SourisEvent evt);   // appelée par le panneau AffTexte
+    abstract public ArrayList<ElementMarque> trouverElementsVises(Unite uniteVisee,
+            TypeMarquage marqueUniteVisee, boolean avecId);  // appelée par le panneau AffTexte
+  }
+  public PanneauEditeur(Vue vue) {
+    super(new BorderLayout());
+    this.vue = vue;
+    vue.addEventListener(this);
+    setBorder(new TitledBorder(""));
+    panneauOccurrences = new JPanel(new BorderLayout());
+    panneauTexte = new PanneauAffTexte(vue.getCorpus());
+    panneauOccurrences.add(new JScrollPane(panneauTexte), BorderLayout.CENTER);
+    panneauChamps = new PanneauChamps(this, vue);
+    add(new JSplitPane(JSplitPane.VERTICAL_SPLIT, panneauOccurrences, panneauChamps), BorderLayout.CENTER);
+    // Les différents panneaux de commandes 
+    panneauxCommandes.put(Commandes.GESTION_UNITES,
+            new PanneauCommandesUnites(vue, panneauTexte, panneauChamps));
+    titresPanneauxCommandes.put(Commandes.GESTION_UNITES, "Gestion des unités");
+    panneauxCommandes.put(Commandes.GESTION_RELATIONS,
+            new PanneauCommandesRelations(vue, panneauTexte, panneauChamps));
+    titresPanneauxCommandes.put(Commandes.GESTION_RELATIONS, "Gestion des relations");
+    panneauxCommandes.put(Commandes.GESTION_SCHEMAS,
+            new PanneauCommandesSchemas(vue, panneauTexte, panneauChamps));
+    titresPanneauxCommandes.put(Commandes.GESTION_SCHEMAS, "Gestion des schémas");
+    new GActionClavier(this, "suivant", "F1", "control DOWN") {
+      public void executer() {
+        elementSuivant(1);
+      }
+    };
+    new GActionClavier(this, "précédent", "F2", "control UP") {
+      public void executer() {
+        elementSuivant(-1);
+      }
+    };
+    new GActionClavier(this, "copier", "F3", "control M") {
+      public void executer() {
+        copierElement();
+      }
+    };
+    new GActionClavier(this, "coller", "F4", "control R") {
+      public void executer() {
+        collerElement();
+      }
+    };
+    // La fenêtre modale pour éditer le texte
+    fenetreModifTexte = new JDialog((VisuMain) getTopLevelAncestor(), true);
+    fenetreModifTexte.setUndecorated(true);
+    fenetreModifTexte.getContentPane().setLayout(new BorderLayout());
+    panneauModifTexte = new PanneauModifTexte(vue.getCorpus());
+    fenetreModifTexte.getContentPane().add(new JScrollPane(panneauModifTexte), BorderLayout.CENTER);
+    panneauCommandesModifTexte = new visuAnalec.texte.PanneauCommandesModifTexte(this, vue, panneauModifTexte);
+    panneauModifTexte.setCommandesModifTexte(panneauCommandesModifTexte);
+    fenetreModifTexte.getContentPane().add(panneauCommandesModifTexte, BorderLayout.SOUTH);
+    fenetreModifTexte.setVisible(false);
+    // Panneau initial : gestion des unités
+    changerPanneauCommandes(Commandes.GESTION_UNITES);
+    reinitCommandes();
+
+  }
+  void agencerPanneaux() {
+    JSplitPane split = (JSplitPane) panneauOccurrences.getParent();
+    split.setDividerLocation(2./3);
+    revalidate();
+    repaint();
+  }
+  private void changerPanneauCommandes(Commandes newCommandes) {
+    if (commandes!=null)
+      panneauOccurrences.remove(panneauxCommandes.get(commandes));
+    commandes = newCommandes;
+    panneauOccurrences.add(panneauxCommandes.get(commandes), BorderLayout.NORTH);
+    ((TitledBorder) getBorder()).setTitle(titresPanneauxCommandes.get(commandes));
+    panneauTexte.setCommandes(panneauxCommandes.get(commandes));
+    revalidate();
+    repaint();
+  }
+  private void reinitCommandes() {
+    panneauxCommandes.get(commandes).reinitialiser();
+  }
+  private void elementSuivant(int sens) {
+    panneauxCommandes.get(commandes).elementSuivant(sens);
+  }
+  private void copierElement() {
+    Element elt = panneauxCommandes.get(commandes).elementSelectionne();
+    if (elt!=null) elementCourant = elt;
+  }
+  private void collerElement() {
+    if (elementCourant==null) return;
+    Element elt = panneauxCommandes.get(commandes).elementSelectionne();
+    if (elt==null) return;
+    vue.copierValeurs(elementCourant, elt);
+  }
+  private void reinitCommandes(Element elt) {
+    panneauxCommandes.get(commandes).reinitialiser();
+    panneauxCommandes.get(commandes).editerElement(elt);
+  }
+  private void reaffCommandes() {
+    panneauxCommandes.get(commandes).reafficher();
+  }
+  private void initNewCorpus() {
+    panneauTexte.setTexteVisu();
+    panneauTexte.initAscenseur();
+    colorierTexte();
+    changerPanneauCommandes(Commandes.GESTION_UNITES);
+    reinitCommandes();
+  }
+  private void colorierTexte() {
+    panneauTexte.setAttributsStandard(vue.getStyleTexte());
+    panneauTexte.colorierUnites(vue.getUnitesAColorier());
+  }
+  void initRechercherTexte() {
+    recherche = (String) JOptionPane.showInputDialog(this, "Recherche dans le texte",
+            "Rechercher", JOptionPane.PLAIN_MESSAGE, null, null, recherche);
+    if (recherche==null) recherche = "";
+    if (recherche.isEmpty()) return;
+    panneauTexte.rechercherTexte(recherche);
+  }
+  void rechercherSuivantTexte() {
+    if (recherche.isEmpty()) return;
+    panneauTexte.rechercherTexte(recherche);
+
+  }
+  void initModifierTexte() {
+    ((TitledBorder) getBorder()).setTitle("Modification du texte");
+    repaint();
+    fenetreModifTexte.setSize(panneauOccurrences.getSize());
+    fenetreModifTexte.setLocationRelativeTo(panneauOccurrences);
+    panneauChamps.effacer();
+    panneauModifTexte.init();
+    fenetreModifTexte.setModal(false);
+    fenetreModifTexte.setVisible(true);
+    panneauModifTexte.ajusterAscenseur(panneauTexte);
+    fenetreModifTexte.setVisible(false);
+    fenetreModifTexte.setModal(true);
+    fenetreModifTexte.setVisible(true);
+  }
+  public void finModifTexte() {
+    fenetreModifTexte.setVisible(false);
+    panneauTexte.ajusterAscenseur(panneauModifTexte);
+    if (commandes==null) {
+      changerPanneauCommandes(Commandes.GESTION_UNITES);
+      reinitCommandes();
+    } else {
+      ((TitledBorder) getBorder()).setTitle(titresPanneauxCommandes.get(commandes));
+      reaffCommandes();
+    }
+    repaint();
+  }
+  public void saisirStyleTexte(Vue vue) {
+    VisuStyleTexte.newVisuStyleTexte(this, vue.getStyleTexte());
+  }
+  public void changerStyleTexte(SimpleAttributeSet att) {
+    vue.setStyleTexte(att);
+    panneauTexte.setAttributsStandard(att);
+    panneauModifTexte.setAttributsStandard(att);
+    reaffCommandes();
+  }
+  public Document getTexteFormate() {
+    return panneauTexte.getDocument();
+  }
+  public void editerElement(Element elt) {
+    // typiquement, appelée de l'extérieur par d'autres fenêtres
+    changerPanneauCommandes(Commandes.getCommande(elt.getClass()));
+    reinitCommandes(elt);
+    ((VisuMain) getTopLevelAncestor()).premierPlan();
+  }
+  public void editerUniteChaine(Unite unit, Schema chaine) {
+    // appelée de l'extérieur notamment par visuChaines)
+    changerPanneauCommandes(Commandes.GESTION_SCHEMAS);
+    reinitCommandes();
+    ((PanneauCommandesSchemas) panneauxCommandes.get(commandes)).editerSchemaElement(chaine, unit);
+    ((VisuMain) getTopLevelAncestor()).premierPlan();
+  }
+  public void editerUniteTypeChaine(Unite unit, String typechaine) {
+    // appelée de l'extérieur notamment par visuChaines)
+    changerPanneauCommandes(Commandes.GESTION_SCHEMAS);
+    reinitCommandes();
+    ((PanneauCommandesSchemas) panneauxCommandes.get(commandes)).editerElementTypeSchema(unit, typechaine);
+    ((VisuMain) getTopLevelAncestor()).premierPlan();
+  }
+  void initGestionUnites() {
+    if (vue.getTypesUnitesAVoir().length==0) {
+      JOptionPane.showMessageDialog(getTopLevelAncestor(), "Aucun type d'unités n'est défini dans la vue actuelle",
+              "Saisie d'unités impossible", JOptionPane.ERROR_MESSAGE);
+      return;
+    }
+    changerPanneauCommandes(Commandes.GESTION_UNITES);
+    reinitCommandes();
+  }
+  void initGestionRelations() {
+    if (vue.getTypesRelationsAVoir().length==0) {
+      JOptionPane.showMessageDialog(getTopLevelAncestor(), "Aucun type de relation n'est défini dans la vue actuelle",
+              "Saisie de relations impossible", JOptionPane.ERROR_MESSAGE);
+      return;
+    }
+    changerPanneauCommandes(Commandes.GESTION_RELATIONS);
+    reinitCommandes();
+  }
+  void initGestionSchemas() {
+    if (vue.getTypesSchemasAVoir().length==0) {
+      JOptionPane.showMessageDialog(getTopLevelAncestor(), "Aucun type de schéma n'est défini dans la vue actuelle",
+              "Saisie de schéma impossible", JOptionPane.ERROR_MESSAGE);
+      return;
+    }
+    changerPanneauCommandes(Commandes.GESTION_SCHEMAS);
+    reinitCommandes();
+  }
+  public void traiterVueEvent(VueEvent evt) {
+    switch (evt.getModif()) {
+      case EXTRACTION:
+      case NEW_VUE:
+      case VUE_DEFAUT:
+        colorierTexte();
+        reinitCommandes();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getModif()+" oublié dans un switch");
+    }
+  }
+  public void traiterStructureEvent(StructureEvent evt) {
+    switch (evt.getModif()) {
+      case SUPPR_TYPE:
+      case FUSION_TYPE:
+      case RENOM_TYPE:
+      case AJOUT_TYPE:
+      case AJOUT_TYPE_ET_ELEMENTS:
+        colorierTexte();
+        reinitCommandes();
+        return;
+      case VALEUR_PAR_DEFAUT:
+      case AJOUT_FORME_UNITE:
+      case FUSION_PROP:
+      case RENOM_PROP:
+      case SUPPR_PROP:
+      case AJOUT_PROP:
+      case FUSION_VALEUR:
+      case RENOM_VALEUR:
+      case SUPPR_VALEUR:
+      case AJOUT_VALEUR:
+        colorierTexte();
+        panneauChamps.reafficher();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getModif()+" oublié dans un switch");
+    }
+  }
+  public void traiterEvent(Message evt) {
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        initNewCorpus();
+        return;
+      case NEW_CORPUS:
+        initNewCorpus();
+        return;
+      case CORPUS_SAVED:
+          return;
+      case MODIF_TEXTE:
+        panneauTexte.setTexteVisu();
+        return;
+      case MODIF_VUE:
+        traiterVueEvent((VueEvent) evt);
+        return;
+      case MODIF_STRUCTURE:
+        traiterStructureEvent((StructureEvent) evt);
+        return;
+      case MODIF_ELEMENT:
+        colorierTexte();
+        panneauxCommandes.get(commandes).traiterElementEvent((ElementEvent) evt);
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauEditeur.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauModifTexte.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauModifTexte.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauModifTexte.java	(revision 3653)
@@ -0,0 +1,170 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.texte;
+
+import java.util.*;
+import javax.swing.event.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class PanneauModifTexte extends PanneauTexte implements DocumentListener {
+  protected static class BorneUnite implements Comparable {
+    public Unite unite;
+    public int pos;
+    public BorneUnite(Unite unite, int pos) {
+      this.unite = unite;
+      this.pos = pos;
+    }
+    public int compareTo(Object obj) {
+      if (obj.getClass() != BorneUnite.class) {
+        throw new ClassCastException("Comparaison impossible : " + obj.toString() +
+                " n'est pas une instance de BorneUnite");
+      }
+      int comp = Integer.signum(pos - (((BorneUnite) obj).pos));
+      if (comp == 0) {
+        comp = -Integer.signum(unite.getFin() - unite.getDeb() - ((BorneUnite) obj).unite.getFin() +
+                ((BorneUnite) obj).unite.getDeb());
+      }
+      return comp;
+    }
+  }
+  private PanneauCommandesModifTexte panneauCommandes;
+  private BorneUnite[] bornesGauches;
+  private BorneUnite[] bornesDroites;
+  public PanneauModifTexte(Corpus corpus) {
+    super(corpus);
+    setEditable(true);
+  }
+  public void setCommandesModifTexte(PanneauCommandesModifTexte panneauCommandes) {
+    this.panneauCommandes = panneauCommandes;
+  }
+  void setBornesModifTexte() {
+    ArrayList<Unite> units = corpus.getToutesUnites();
+    bornesGauches = new BorneUnite[units.size()];
+    bornesDroites = new BorneUnite[units.size()];
+    for (int i = 0; i < units.size(); i++) {
+      Unite unite = units.get(i);
+      bornesGauches[i] = new BorneUnite(unite, unite.getDeb());
+      bornesDroites[i] = new BorneUnite(unite, unite.getFin());
+    }
+    Arrays.sort(bornesGauches);
+    Arrays.sort(bornesDroites);
+
+  }
+  public void init() {
+    doc.removeDocumentListener(this);
+    setTexteVisu();
+    setEditable(true);
+    doc.setParagraphAttributes(0, getText().length(), AttributsStandard, true);
+    doc.setCharacterAttributes(0, getText().length(), AttributsStandard, true);
+    setBornesModifTexte();
+    doc.addDocumentListener(this);
+  }
+  public int preparerValiderModifTexte() {
+    Comparator<BorneUnite> comp = new Comparator<BorneUnite>() {
+      public int compare(BorneUnite b1, BorneUnite b2) {
+        return b1.unite.compareTo(b2.unite);
+      }
+    };
+    Arrays.sort(bornesGauches, comp);
+    Arrays.sort(bornesDroites, comp);
+    int nbSupprimes = 0;
+    for (int i = 0; i < bornesGauches.length; i++) {
+      if (bornesGauches[i].pos == bornesDroites[i].pos) {
+        nbSupprimes++;
+      }
+    }
+    return nbSupprimes;
+  }
+  public void validerModifTexte() {
+    for (int i = 0; i < bornesGauches.length; i++) {
+      Unite unite = bornesGauches[i].unite;
+      if (bornesGauches[i].pos == unite.getDeb() && bornesDroites[i].pos == unite.getFin()) {
+        continue;
+      }
+      if (bornesGauches[i].pos == bornesDroites[i].pos) {
+        corpus.supUnite(unite);
+      } else {
+        corpus.modifBornesUnite(unite, bornesGauches[i].pos, bornesDroites[i].pos);
+      }
+    }
+    setEditable(false);
+    setTexteCorpus();  // Corpus enverra l'événement MODIF_TEXTE à tous les panneaux occurrence
+  }
+  public void insertUpdate(DocumentEvent evt) {
+    try {
+      String texte = getText();
+      int debutInsertion = positionToIndex(evt.getOffset());
+      int lengthInsertion = evt.getLength();
+      int iIns = 0;
+      while (iIns < posNewLines.size() && posNewLines.get(iIns) < evt.getOffset()) {
+        iIns++;
+      }
+      for (int ind = iIns; ind < posNewLines.size(); ind++) {
+        posNewLines.set(ind, posNewLines.get(ind) + evt.getLength());
+      }
+      for (int pos = evt.getOffset(); pos < evt.getOffset() + evt.getLength(); pos++) {
+        if (texte.charAt(pos) == '\n') {
+          lengthInsertion--;
+          posNewLines.add(iIns++, pos);
+        }
+      }
+      shiftDroitBornes(bornesGauches, debutInsertion, lengthInsertion);
+      shiftDroitBornes(bornesDroites, debutInsertion, lengthInsertion);
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  public void removeUpdate(DocumentEvent evt) {
+    try {
+      int debutSuppression = positionToIndex(evt.getOffset());
+      int lengthSuppression = evt.getLength();
+      int iSup = 0;
+      while (iSup < posNewLines.size() && posNewLines.get(iSup) < evt.getOffset()) {
+        iSup++;
+      }
+      while (iSup < posNewLines.size() && posNewLines.get(iSup) < evt.getOffset() + evt.getLength()) {
+        posNewLines.remove(iSup);
+        lengthSuppression--;
+      }
+      for (int ind = iSup; ind < posNewLines.size(); ind++) {
+        posNewLines.set(ind, posNewLines.get(ind) - evt.getLength());
+      }
+      shiftGaucheBornes(bornesGauches, debutSuppression, lengthSuppression);
+      shiftGaucheBornes(bornesDroites, debutSuppression, lengthSuppression);
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  public void changedUpdate(DocumentEvent evt) {
+    // rien à faire
+  }
+  void shiftDroitBornes(BorneUnite[] bornes, int deb, int shift) {
+    for (int i = bornes.length - 1; i >= 0; i--) {
+      if (bornes[i].pos < deb) {
+        return;
+      }
+      bornes[i].pos += shift;
+    }
+  }
+  void shiftGaucheBornes(BorneUnite[] bornes, int deb, int shift) {
+    for (int i = bornes.length - 1; i >= 0; i--) {
+      if (bornes[i].pos <= deb) {
+        return;
+      }
+      if (bornes[i].pos < deb + shift) {
+        bornes[i].pos = deb;
+      } else {
+        bornes[i].pos -= shift;
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauModifTexte.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauTexte.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauTexte.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauTexte.java	(revision 3653)
@@ -0,0 +1,542 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.texte;
+
+import java.awt.*;
+import java.util.*;
+import java.util.ArrayList;
+import javax.swing.*;
+import javax.swing.text.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class PanneauTexte extends JTextPane {
+  final private static Color ROUGE = new Color(0x800000);
+  final private static Color BLEU = new Color(0x000080);
+  final private static Color JAUNE_CLAIR = new Color(0xffffb0);
+  final private static Color JAUNE_TRES_CLAIR = new Color(0xffffe0);
+  final private static Color JAUNE_FONCE = new Color(0xffff60);
+  final private static Color VERT_CLAIR = new Color(0xd8f0ff);
+  final private static Color VERT_FONCE = new Color(0xb0d0ff);
+  final private static Color VIOLET_CLAIR = new Color(0xffd8e0);
+  final private static Color VIOLET_FONCE = new Color(0xffb0c0);
+  final public static SimpleAttributeSet STANDARD_DEFAUT = creerStyleStandardDefaut();
+  final protected static AttributeSet COLORATION_1 = creerCouleurFond(JAUNE_CLAIR);
+  final protected static AttributeSet COLORATION_1_MULTI = creerCouleurFond(JAUNE_FONCE);
+  final protected static AttributeSet COLORATION_2 = creerCouleurFond(VERT_CLAIR);
+  final protected static AttributeSet COLORATION_2_MULTI = creerCouleurFond(VERT_FONCE);
+  final protected static AttributeSet COLORATION_3 = creerCouleurFond(VIOLET_CLAIR);
+  final protected static AttributeSet COLORATION_3_MULTI = creerCouleurFond(VIOLET_FONCE);
+  final protected static AttributeSet SELECTION_1_1 = ajouterCouleurCar(COLORATION_1, BLEU);
+  final protected static AttributeSet SELECTION_1_1_MULTI = ajouterCouleurCar(COLORATION_1_MULTI,
+          BLEU);
+  final protected static AttributeSet SELECTION_1_2 = ajouterCouleurCar(COLORATION_1, ROUGE);
+  final protected static AttributeSet SELECTION_1_2_MULTI = ajouterCouleurCar(COLORATION_1_MULTI,
+          ROUGE);
+  final protected static AttributeSet SELECTION_1 = ajouterCouleurCar(COLORATION_1, ROUGE);
+  final protected static AttributeSet SELECTION_1_MULTI = ajouterCouleurCar(COLORATION_1_MULTI,
+          ROUGE);
+  final protected static AttributeSet SELECTION_2 = ajouterCouleurCar(COLORATION_2, BLEU);
+  final protected static AttributeSet SELECTION_2_MULTI = ajouterCouleurCar(COLORATION_2_MULTI,
+          BLEU);
+  final protected static AttributeSet SELECTION_3 = ajouterCouleurCar(COLORATION_3, ROUGE);
+  final protected static AttributeSet SELECTION_3_MULTI = ajouterCouleurCar(COLORATION_3_MULTI,
+          ROUGE);
+  final protected static AttributeSet BORNAGE = ajouterCouleurCar(COLORATION_1, null);
+  final private static HashMap<Integer, String> NOM_ALIGNEMENT = creerTableauNomsAlignement();
+
+  private static SimpleAttributeSet creerStyleStandardDefaut() {
+    String police;
+    if (Arrays.binarySearch(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(),
+            "Times New Roman")>=0) police = "Times New Roman";
+    else police = "Serif";
+    SimpleAttributeSet att = new SimpleAttributeSet();
+    StyleConstants.setFontFamily(att, police);
+    StyleConstants.setForeground(att, Color.BLACK);
+    StyleConstants.setBackground(att, Color.WHITE);
+    StyleConstants.setFontSize(att, 14);
+    StyleConstants.setBold(att, false);
+    StyleConstants.setItalic(att, false);
+    StyleConstants.setUnderline(att, false);
+    StyleConstants.setAlignment(att, StyleConstants.ALIGN_JUSTIFIED);
+    StyleConstants.setFirstLineIndent(att, 20f);
+    StyleConstants.setSpaceAbove(att, 4f);
+    StyleConstants.setSpaceBelow(att, 0f);
+    StyleConstants.setLeftIndent(att, 10f);
+    StyleConstants.setRightIndent(att, 10f);
+    StyleConstants.setLineSpacing(att, 0.1f);
+    return att;
+  }
+
+  private static HashMap<Integer, String> creerTableauNomsAlignement() {
+    HashMap<Integer, String> tab = new HashMap<Integer, String>();
+    tab.put(StyleConstants.ALIGN_CENTER, "Centré");
+    tab.put(StyleConstants.ALIGN_JUSTIFIED, "Justifié");
+    tab.put(StyleConstants.ALIGN_LEFT, "Gauche");
+    tab.put(StyleConstants.ALIGN_RIGHT, "Droite");
+    return tab;
+  }
+
+  public static String nomAlignement(int code) {
+    return NOM_ALIGNEMENT.get(code);
+  }
+
+  public static String[] nomsAlignement() {
+    String[] noms = NOM_ALIGNEMENT.values().toArray(new String[0]);
+    Arrays.sort(noms);
+    return noms;
+  }
+
+  public static int codeAlignement(String nom) {
+    for (int code : NOM_ALIGNEMENT.keySet()) if (nomAlignement(code).equals(nom))
+        return code;
+    return StyleConstants.ALIGN_JUSTIFIED;
+  }
+
+  private static SimpleAttributeSet creerCouleurFond(Color c) {
+    SimpleAttributeSet att = new SimpleAttributeSet();
+    StyleConstants.setBackground(att, c);
+    return att;
+  }
+
+  private static SimpleAttributeSet ajouterCouleurCar(AttributeSet att0, Color c) {
+    SimpleAttributeSet att = new SimpleAttributeSet(att0);
+    StyleConstants.setBold(att, true);
+    if (c!=null) StyleConstants.setForeground(att, c);
+    return att;
+  }
+
+  public static Color getCouleurFond1() {
+    return StyleConstants.getBackground(COLORATION_1);
+  }
+
+  public static Color getCouleurFond2() {
+    return StyleConstants.getBackground(COLORATION_2);
+  }
+
+  public static Color getCouleurFond3() {
+    return StyleConstants.getBackground(COLORATION_3);
+  }
+
+  public enum TypeMarquage {
+    FOND1(5, COLORATION_1, COLORATION_1_MULTI),
+    FOND1_2(5, COLORATION_1, COLORATION_1_MULTI),
+    FOND2(6, COLORATION_2, COLORATION_2_MULTI),
+    FOND3(7, COLORATION_3, COLORATION_3_MULTI),
+    SELECT1(2, SELECTION_1, SELECTION_1_MULTI),
+    SELECT1_2(1, SELECTION_1_1, SELECTION_1_1_MULTI),
+    SELECT1_3(2, SELECTION_1_2, SELECTION_1_2_MULTI),
+    SELECT2(3, SELECTION_2, SELECTION_2_MULTI),
+    SELECT3(4, SELECTION_3, SELECTION_3_MULTI);
+    protected AttributeSet attribut;
+    protected AttributeSet attributMulti;
+    protected int niveau;
+
+    TypeMarquage(int niv, AttributeSet att, AttributeSet attMulti) {
+      attribut = att;
+      attributMulti = attMulti;
+      niveau = niv;
+    }
+  }
+
+  public static class UniteColoree {
+    public Unite unite;
+    public AttributeSet att;
+
+    public UniteColoree(Unite unite, AttributeSet att) {
+      this.att = att;
+      this.unite = unite;
+    }
+  }
+
+  protected static class Coloriage {
+    private int[][] intervalles;
+    private AttributeSet[] attributIntervalles;
+    private PanneauTexte panneauTexte;
+
+    protected Coloriage(PanneauTexte pTexte) {
+      panneauTexte = pTexte;
+      intervalles = new int[0][];
+      attributIntervalles = new AttributeSet[0];
+    }
+
+    private void creerColoriage(UniteColoree[] unitsCol) {
+      ArrayList<int[]> intervlles = new ArrayList<int[]>();
+      ArrayList<AttributeSet> attIntervalle = new ArrayList<AttributeSet>();
+      for (UniteColoree unitCol : unitsCol) {
+        int deb = panneauTexte.indexToPosition(unitCol.unite.getDeb());
+        int fin = panneauTexte.indexToPosition(unitCol.unite.getFin());
+        intervlles.add(new int[]{deb, fin-deb});
+        attIntervalle.add(unitCol.att);
+      }
+      intervalles = intervlles.toArray(new int[0][]);
+      attributIntervalles = attIntervalle.toArray(new AttributeSet[0]);
+    }
+  }
+
+  protected static class Marquage {
+    private int[][] intervalles;
+    private Unite[][] unitesIntervalles;
+    private AttributeSet[] attributIntervalles;
+    private HashMap<Unite, ArrayList<TypeMarquage>> typesMarquage =
+            new HashMap<Unite, ArrayList<TypeMarquage>>();
+    private PanneauTexte panneauTexte;
+
+    protected Marquage(PanneauTexte pTexte) {
+      panneauTexte = pTexte;
+    }
+    // Ordre de masquage décroissant : si une unité est présente dans plusieurs types de marquage, 
+    // seule sa première mention sera prise en compte (grâce au HashMap typesMarquage)
+
+    void creerMarquage(TypeMarquage[] typesMarq, EnumMap<TypeMarquage, Unite[]> unites) {
+      HashMap<Integer, HashSet<Unite>> debs = new HashMap<Integer, HashSet<Unite>>();
+      HashMap<Integer, HashSet<Unite>> fins = new HashMap<Integer, HashSet<Unite>>();
+      HashSet<Integer> bornes = new HashSet<Integer>();
+      HashMap<Unite, Boolean> multis = new HashMap<Unite, Boolean>();
+      typesMarquage.clear();
+      for (TypeMarquage typeM : typesMarq)
+        for (Unite unit : unites.get(typeM)) {
+          if (!typesMarquage.containsKey(unit)) {
+            typesMarquage.put(unit, new ArrayList<TypeMarquage>());
+            typesMarquage.get(unit).add(typeM);
+            multis.put(unit, false);
+          } else {
+            ArrayList<TypeMarquage> types = typesMarquage.get(unit);
+            if (!types.get(types.size()-1).equals(typeM)) types.add(typeM);
+            else if (types.size()==1) multis.put(unit, true);
+          }
+          int deb = panneauTexte.indexToPosition(unit.getDeb());
+          int fin = panneauTexte.indexToPosition(unit.getFin());
+          bornes.add(deb);
+          bornes.add(fin);
+          if (!debs.containsKey(deb)) debs.put(deb, new HashSet<Unite>());
+          debs.get(deb).add(unit);
+          if (!fins.containsKey(fin)) fins.put(fin, new HashSet<Unite>());
+          fins.get(fin).add(unit);
+        }
+      Integer[] brnes = bornes.toArray(new Integer[0]);
+      Arrays.sort(brnes);
+      ArrayList<Unite> units = new ArrayList<Unite>();
+      ArrayList<int[]> intervlles = new ArrayList<int[]>();
+      ArrayList<Unite[]> unitsIntervalle = new ArrayList<Unite[]>();
+      ArrayList<AttributeSet> attIntervalle = new ArrayList<AttributeSet>();
+      int deb = 0;  // début d'un intervalle
+      int lg = 0;   // longueur d'un intervalle
+      for (int borne : brnes) {
+        if (!units.isEmpty()) {
+          lg = borne-deb;
+          intervlles.add(new int[]{deb, lg});
+          unitsIntervalle.add(ordonnerUnites(units));
+          attIntervalle.add(choisirAttribut(units, multis));
+        }
+        if (debs.containsKey(borne)) for (Unite unit : debs.get(borne))
+            units.add(unit);
+        if (fins.containsKey(borne)) for (Unite unit : fins.get(borne))
+            units.remove(unit);
+        if (!units.isEmpty()) deb = borne;
+      }
+      intervalles = intervlles.toArray(new int[0][]);
+      unitesIntervalles = unitsIntervalle.toArray(new Unite[0][]);
+      attributIntervalles = attIntervalle.toArray(new AttributeSet[0]);
+    }
+
+    private Unite[] ordonnerUnites(ArrayList<Unite> units) {
+      Unite[] unites = new Unite[units.size()];
+      unites[0] = units.get(0);
+      for (int i = 1; i<unites.length; i++) {
+        if (units.get(i).getFin()-units.get(i).getDeb()>=unites[0].getFin()-unites[0].getDeb())
+          unites[i] = units.get(i);
+        else {
+          unites[i] = unites[0];
+          unites[0] = units.get(i);
+        }
+      }
+      return unites;
+    }
+
+    private AttributeSet choisirAttribut(ArrayList<Unite> units, HashMap<Unite, Boolean> multis) {
+      AttributeSet att;
+      if (units.size()==1) {
+        att = multis.get(units.get(0)) ? typesMarquage.get(units.get(0)).get(0).attributMulti : typesMarquage.get(units.get(0)).get(0).attribut;
+      } else {
+        att = typesMarquage.get(units.get(0)).get(0).attributMulti;
+        int niv = typesMarquage.get(units.get(0)).get(0).niveau;
+        for (int i = 1; i<units.size(); i++) {
+          if (typesMarquage.get(units.get(i)).get(0).niveau<niv) {
+            att = typesMarquage.get(units.get(i)).get(0).attributMulti;
+            niv = typesMarquage.get(units.get(i)).get(0).niveau;
+          }
+        }
+      }
+      return att;
+    }
+
+    public Unite[] getUnitesVisees(int pos) {   // peut être améliorée par une recherche dichotomique
+      for (int i = 0; i<intervalles.length; i++) {
+        int[] interv = intervalles[i];
+        if (pos<interv[0]) return new Unite[0];
+        if (pos<interv[0]+interv[1]) return unitesIntervalles[i];
+      }
+      return new Unite[0];
+    }
+
+    public Unite getUniteVisee(int pos) {   // peut être améliorée par une recherche dichotomique
+      Unite[] units = getUnitesVisees(pos);
+      if (units.length==0) return null;
+      return units[0];
+    }
+
+    public TypeMarquage getMarquage(Unite unit) {
+      return typesMarquage.get(unit).get(0);
+    }
+
+    public ArrayList<TypeMarquage> getMarquages(Unite unit) {
+      return typesMarquage.get(unit);
+    }
+  }
+  // Champs de la classe PanneauTexte
+  protected SimpleAttributeSet AttributsStandard;
+  final static String CAR_FIN_PARAGRAPHE = "[\u00b6] ";
+  protected Corpus corpus;
+  protected StyledDocument doc;
+  protected Coloriage coloriage = null;
+  protected ArrayList<Integer> posNewLines = new ArrayList<Integer>();
+
+  public PanneauTexte(Corpus corpus) {
+    super();
+    this.corpus = corpus;
+    AttributsStandard = new SimpleAttributeSet(STANDARD_DEFAUT);
+    doc = getStyledDocument();
+    setText("");
+    ToolTipManager.sharedInstance().registerComponent(this);
+  }
+
+  @Override
+  public JToolTip createToolTip() {
+    JToolTip jt = new JToolTip();
+    jt.setBackground(JAUNE_TRES_CLAIR);
+    return jt;
+  }
+
+  public SimpleAttributeSet getAttributsStandard() {
+    return AttributsStandard;
+  }
+
+  public void setAttributsStandard(SimpleAttributeSet att) {
+    AttributsStandard = att;
+  }
+
+//  private int debParag;
+//  public void setTexteVisu() {
+//    final String texte = corpus.getTexte();
+//    posNewLines.clear();
+//    debParag = 0;
+//    final Integer[] finPars = corpus.getFinParagraphes();
+//    final StringBuffer newTexte = new StringBuffer(texte.length()+finPars.length);
+//    final GMessages.GProgression progression =
+//            new GMessages.GProgression(finPars.length, "paragraphes");
+//    Thread traitement = new Thread() {
+//      @Override
+//      public void run() {
+//        for (int i = 0; i<finPars.length; i++) {
+//          //           if(progression.isCanceled()) break;
+//          newTexte.append(texte.substring(debParag, finPars[i])).append("\n");
+//          posNewLines.add(newTexte.length()-1);
+//          debParag = finPars[i];
+//         progression.setNbTraites(i+1);
+//         }
+//        setText(new String(newTexte));
+//        revalidate();
+//        repaint();
+//      }
+//    };
+//    traitement.start();
+//  }
+//
+  public void setTexteVisu() {
+    final String texte = corpus.getTexte();
+    posNewLines.clear();
+    int debParag = 0;
+    Integer[] finPars = corpus.getFinParagraphes();
+    StringBuffer newTexte = new StringBuffer(texte.length()+finPars.length);
+    for (int i = 0; i<finPars.length; i++) {
+      //           if(progression.isCanceled()) break;
+      newTexte.append(texte.substring(debParag, finPars[i])).append("\n");
+      posNewLines.add(newTexte.length()-1);
+      debParag = finPars[i];
+    }
+    setText(new String(newTexte));
+    revalidate();
+    repaint();
+  }
+
+  private int getYHautAff() {
+    return ((JViewport) getParent()).getViewPosition().y;
+  }
+
+  private void setYHautAff(int y) {
+    ((JViewport) getParent()).setViewPosition(new Point(0, y));
+  }
+
+  public void initAscenseur() {
+    setYHautAff(0);
+    setCaretPosition(0);
+  }
+
+  public void ajusterAscenseur(PanneauTexte panneau) {
+    setYHautAff(panneau.getYHautAff());
+    setCurseur(panneau.getCaretPosition());
+  }
+
+  public void setCurseur(int pos) {
+    int ymax = getYHautAff()+((JViewport) getParent()).getViewSize().height;
+    pos = Math.max(pos, viewToModel(new Point(0, getYHautAff())));
+    pos = Math.min(pos, viewToModel(new Point(0, ymax)));
+    setCaretPosition(pos);
+  }
+
+  protected void placerAscenseur(Unite unite) {
+    int posdeb = indexToPosition(unite.getDeb());
+    placerAscenseur(posdeb, indexToPosition(unite.getFin()));
+    setCaretPosition(posdeb);
+  }
+
+  protected void placerAscenseur(int posdeb, int posfin) {
+    try {
+      Rectangle rectdeb = modelToView(posdeb);
+      Rectangle rectfin = modelToView(posfin);
+      int hligne = rectdeb.height;
+      int yhaut = rectdeb.y;
+      int ybas = rectfin.y+hligne;
+      int y0 = getYHautAff();
+      int h = ((JViewport) getParent()).getExtentSize().height;
+      if (yhaut<y0||ybas>y0+h) {
+        setYHautAff(Math.max(0, modelToView(posdeb).y-h/3));
+      }
+    } catch (BadLocationException ex) {
+      System.out.println("Erreur dans placerAscenseur : "+ex.getLocalizedMessage());
+      System.exit(1);
+    }
+  }
+
+  public int[] getIndSelection() {
+    int deb = getSelectionStart();
+    int fin = getSelectionEnd();
+    if (deb==fin) return null;
+    return new int[]{positionToIndex(deb), positionToIndex(fin)};
+  }
+
+  protected int indexToPosition(int ind) {
+    int nbnl = 0;
+    for (int finParag : corpus.getFinParagraphes()) {
+      if (ind<finParag) {
+        break;
+      }
+      nbnl++;
+    }
+    return ind+nbnl;
+  }
+
+  protected int positionToIndex(int pos) {
+    int nbnl = 0;
+    for (int posnl : posNewLines) {
+      if (pos<=posnl) {
+        break;
+      }
+      nbnl++;
+    }
+    return pos-nbnl;
+  }
+
+  public void colorierUnites(UniteColoree[] unitsCol) {
+    coloriage.creerColoriage(unitsCol);
+  }
+  // Ordre de masquage décroissant : si une unité est présente dans plusieurs types de marquage, 
+  // seule sa première mention sera prise en compte 
+
+  protected void marquerUnites(Marquage marquage, TypeMarquage[] typesMarq, EnumMap<TypeMarquage, Unite[]> unites) {
+    doc.setCharacterAttributes(0, getText().length(), AttributsStandard, true);
+    doc.setParagraphAttributes(0, getText().length(), AttributsStandard, true);
+    if (coloriage!=null&&typesMarq.length==0)
+      for (int i = 0; i<coloriage.intervalles.length; i++)
+        doc.setCharacterAttributes(
+                coloriage.intervalles[i][0], coloriage.intervalles[i][1], coloriage.attributIntervalles[i], false);
+    marquage.creerMarquage(typesMarq, unites);
+    for (int i = 0; i<marquage.intervalles.length; i++)
+      doc.setCharacterAttributes(
+              marquage.intervalles[i][0], marquage.intervalles[i][1], marquage.attributIntervalles[i], false);
+  }
+
+  protected Unite getUniteVisee(Marquage marquage, Point pt) {
+    return marquage.getUniteVisee(viewToModel(pt));
+  }
+
+  protected Unite[] getUnitesVisees(Marquage marquage, Point pt) {
+    return marquage.getUnitesVisees(viewToModel(pt));
+  }
+
+//  public static int[] calculerNoParagraphe(Unite[] unites, Integer[] finPar) {
+//    // les unites sont triées
+//    // les numéros de paragraphe commencent à 1 
+//    int[] nosPar = new int[unites.length];
+//    int nopar = 0;
+//    for (int i = 0; i<unites.length; i++) {
+//      while (unites[i].getDeb()>finPar[nopar]) nopar++;
+//      nosPar[i] = nopar+1;
+//    }
+//    return nosPar;
+//  }
+//
+  public static String insereCarFinParagraphe(String texte, Integer[] finPar, int offset) {
+    for (int ind : finPar) {
+      ind -= offset;
+      if (ind<=0) continue;
+      if (ind>=texte.length()) break;
+      texte = texte.substring(0, ind)+PanneauTexte.CAR_FIN_PARAGRAPHE+texte.substring(ind);
+      offset -= CAR_FIN_PARAGRAPHE.length();
+    }
+    return texte;
+  }
+
+  public String getTexteUnite(Unite unit) {  // utilisé pour les tooltips et les popups : à revoir
+    int deb = unit.getDeb();
+    int fin = unit.getFin();
+    return insereCarFinParagraphe(corpus.getTexte().substring(deb, fin), corpus.getFinParagraphes(), deb);
+  }
+
+  protected void setTexteCorpus() {
+    String newTexte = "";
+    ArrayList<Integer> newFinParag = new ArrayList<Integer>();
+    String texte = getText();
+    if (posNewLines.isEmpty()||posNewLines.get(posNewLines.size()-1)!=texte.length()-1) {
+      posNewLines.add(texte.length());
+    }
+    int debParag = 0;
+    for (int posnl : posNewLines) {
+      newTexte += texte.substring(debParag, posnl);
+      newFinParag.add(newTexte.length());
+      debParag = posnl+1;
+    }
+    corpus.modifTexte(newTexte, newFinParag);
+  }
+
+  public void rechercherTexte(String chaine) {
+    getCaret().setSelectionVisible(true);
+    String texte = getText();
+    int pos = texte.indexOf(chaine, getCaretPosition());
+    if (pos<0) pos = texte.indexOf(chaine);
+    if (pos>=0) {
+      placerAscenseur(pos, pos+chaine.length());
+      setCaretPosition(pos);
+      moveCaretPosition(pos+chaine.length());
+    } else moveCaretPosition(getCaretPosition());
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauTexte.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/VisuStyleTexte.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/VisuStyleTexte.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/VisuStyleTexte.java	(revision 3653)
@@ -0,0 +1,213 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.texte;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.text.*;
+import visuAnalec.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu;
+import visuAnalec.util.GVisu.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class VisuStyleTexte extends JFrame {
+  private static VisuStyleTexte instance = null;
+  private PanneauEditeur pEditeur;
+  private SimpleAttributeSet att;
+  JComboBox saisieTaille;
+  JComboBox saisiePolice;
+  JCheckBox saisieGras;
+  JCheckBox saisieItalique;
+  JCheckBox saisieSouligne;
+  CouleurComboBox saisieCouleur;
+  CouleurComboBox saisieFond;
+  JComboBox saisieInterligne;
+  JComboBox saisieEspaceAvant;
+  JComboBox saisieEspaceApres;
+  JComboBox saisieAlignement;
+  JComboBox saisieIndentGauche;
+  JComboBox saisieIndentDroite;
+  JComboBox saisieIndentPrem;
+  public static void newVisuStyleTexte(PanneauEditeur pEditeur, SimpleAttributeSet att) {
+    if (instance != null) instance.dispose();
+    instance = new VisuStyleTexte(pEditeur, att);
+
+  }
+  private VisuStyleTexte(PanneauEditeur pEditeur, SimpleAttributeSet att) {
+    super("Gestion du style du texte");
+    Container fen = pEditeur.getTopLevelAncestor();
+    Point pos = new Point(fen.getX() + 200, fen.getY() + 50);
+    setLocation(pos);
+    this.pEditeur = pEditeur;
+    this.att = att;
+    JPanel pStyleCaracteres = new JPanel(new GridLayout(0, 2, 2, 4));
+    pStyleCaracteres.setBorder(new TitledBorder("Caractères"));
+    pStyleCaracteres.add(new JLabel("Police", JLabel.TRAILING));
+    String[] polices = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
+    saisiePolice = new JComboBox(polices);
+    saisiePolice.setPrototypeDisplayValue("Times New Roman");
+    saisiePolice.setEditable(false);
+    saisiePolice.setSelectedItem(StyleConstants.getFontFamily(att));
+    saisiePolice.setMaximumSize(new Dimension(40, 100));
+    pStyleCaracteres.add(saisiePolice);
+    pStyleCaracteres.add(new JLabel("Taille (pts)", JLabel.TRAILING));
+    saisieTaille = new JComboBox(new String[]{"4", "8", "10", "12", "14", "16", "20"});
+    saisieTaille.setEditable(true);
+    saisieTaille.setSelectedItem(Integer.toString(StyleConstants.getFontSize(att)));
+    pStyleCaracteres.add(saisieTaille);
+    pStyleCaracteres.add(new JLabel("Couleur", JLabel.TRAILING));
+    saisieCouleur = new CouleurComboBox(GVisu.getCouleursEtNoirEtBlanc());
+    saisieCouleur.setEditable(true);
+    saisieCouleur.setSelectedItem(StyleConstants.getForeground(att));
+    pStyleCaracteres.add(saisieCouleur);
+    pStyleCaracteres.add(new JLabel("Surbrillance", JLabel.TRAILING));
+    saisieFond = new CouleurComboBox(GVisu.getCouleursEtNoirEtBlanc());
+    saisieFond.setEditable(true);
+    saisieFond.setSelectedItem(StyleConstants.getBackground(att));
+    pStyleCaracteres.add(saisieFond);
+    pStyleCaracteres.add(new JLabel("Caractères gras", JLabel.TRAILING));
+    saisieGras = new JCheckBox("", StyleConstants.isBold(att));
+    pStyleCaracteres.add(saisieGras);
+    pStyleCaracteres.add(new JLabel("italiques", JLabel.TRAILING));
+    saisieItalique = new JCheckBox("", StyleConstants.isItalic(att));
+   pStyleCaracteres.add(saisieItalique);
+    pStyleCaracteres.add(new JLabel("soulignés", JLabel.TRAILING));
+    saisieSouligne = new JCheckBox("", StyleConstants.isUnderline(att));
+    saisieSouligne.setHorizontalTextPosition(SwingConstants.LEADING);
+    pStyleCaracteres.add(saisieSouligne);
+    JPanel pStyleParagraphes = new JPanel(new GridLayout(0,2,2,4));
+    pStyleParagraphes.setBorder(new TitledBorder("Paragraphes"));
+    pStyleParagraphes.add(new JLabel("Alignement", JLabel.TRAILING));
+    saisieAlignement = new JComboBox(PanneauTexte.nomsAlignement());
+    saisieAlignement.setEditable(false);
+    saisieAlignement.setSelectedItem(PanneauTexte.nomAlignement(StyleConstants.getAlignment(att)));
+    pStyleParagraphes.add(saisieAlignement);
+    pStyleParagraphes.add(new JLabel("Interligne (pts)", JLabel.TRAILING));
+    saisieInterligne = new JComboBox(new String[]{"-0.2", "0", "0.2", "0.5", "1.0", "1.5", "2"});
+    saisieInterligne.setEditable(true);
+    saisieInterligne.setSelectedItem(Float.toString(StyleConstants.getLineSpacing(att)));
+    pStyleParagraphes.add(saisieInterligne);
+    pStyleParagraphes.add(new JLabel("Espacement avant (pts)", JLabel.TRAILING));
+    saisieEspaceAvant = new JComboBox(new String[]{"0.0", "2.0", "5.0", "10.0", "15.0", "20.0"});
+    saisieEspaceAvant.setEditable(true);
+    saisieEspaceAvant.setSelectedItem(Float.toString(StyleConstants.getSpaceAbove(att)));
+    pStyleParagraphes.add(saisieEspaceAvant);
+    pStyleParagraphes.add(new JLabel("après (pts)", JLabel.TRAILING));
+    saisieEspaceApres = new JComboBox(new String[]{"0.0", "2.0", "5.0", "10.0", "15.0", "20.0"});
+    saisieEspaceApres.setEditable(true);
+    saisieEspaceApres.setSelectedItem(Float.toString(StyleConstants.getSpaceBelow(att)));
+    pStyleParagraphes.add(saisieEspaceApres);
+    pStyleParagraphes.add(new JLabel("Retrait gauche (pts)", JLabel.TRAILING));
+    saisieIndentGauche = new JComboBox(new String[]{"0.0", "2.0", "5.0", "10.0", "15.0", "20.0"});
+    saisieIndentGauche.setEditable(true);
+    saisieIndentGauche.setSelectedItem(Float.toString(StyleConstants.getLeftIndent(att)));
+    pStyleParagraphes.add(saisieIndentGauche);
+    pStyleParagraphes.add(new JLabel("droit (pts)", JLabel.TRAILING));
+    saisieIndentDroite = new JComboBox(new String[]{"0.0", "2.0", "5.0", "10.0", "15.0", "20.0"});
+    saisieIndentDroite.setEditable(true);
+    saisieIndentDroite.setSelectedItem(Float.toString(StyleConstants.getRightIndent(att)));
+    pStyleParagraphes.add(saisieIndentDroite);
+    pStyleParagraphes.add(new JLabel("1ère ligne (pts)", JLabel.TRAILING));
+    saisieIndentPrem = new JComboBox(new String[]{"0.0", "2.0", "5.0", "10.0", "15.0", "20.0"});
+    saisieIndentPrem.setEditable(true);
+    saisieIndentPrem.setSelectedItem(Float.toString(StyleConstants.getFirstLineIndent(att)));
+    pStyleParagraphes.add(saisieIndentPrem);
+   Box pSaisieItems = Box.createHorizontalBox();
+   pSaisieItems.add(pStyleCaracteres);
+    pSaisieItems.add(Box.createHorizontalGlue());
+    pSaisieItems.add(pStyleParagraphes);
+   JPanel  pCommandesValidation = new JPanel(new FlowLayout(FlowLayout.CENTER));
+    JButton valideModifs = new JButton(
+            new GAction("Valider") {
+              public void executer() {
+                validerModifs();
+              }
+              ;
+            });
+    JButton annuleModifs = new JButton(
+            new GAction("Annuler") {
+              public void executer() {
+                dispose();
+              }
+              ;
+            });
+    pCommandesValidation.add(valideModifs);
+    pCommandesValidation.add(annuleModifs);
+    // cadre global de la fenêtre
+    JPanel cadre = new JPanel(new BorderLayout());
+    cadre.add(pStyleCaracteres, BorderLayout.WEST);
+   cadre.add(pStyleParagraphes, BorderLayout.EAST);
+    cadre.add(pCommandesValidation, BorderLayout.SOUTH);
+    setContentPane(cadre);
+    pack();
+    setVisible(true);
+    addWindowListener(new WindowAdapter() {
+      @Override
+      public void windowClosing(WindowEvent evt) {
+      }
+    });
+  }
+  private void validerModifs() {
+    int entierSaisi;
+    float decimalSaisi;
+    StyleConstants.setFontFamily(att, (String) saisiePolice.getSelectedItem());
+    StyleConstants.setForeground(att, (Color) saisieCouleur.getSelectedItem());
+    StyleConstants.setBackground(att, (Color) saisieFond.getSelectedItem());
+    try {
+      entierSaisi = Integer.parseInt((String) saisieTaille.getSelectedItem());
+    } catch (NumberFormatException numberFormatException) {
+      entierSaisi = StyleConstants.getFontSize(att);
+    }
+    StyleConstants.setFontSize(att, entierSaisi);
+    StyleConstants.setBold(att, (boolean) saisieGras.isSelected());
+    StyleConstants.setItalic(att, (boolean) saisieItalique.isSelected());
+    StyleConstants.setUnderline(att, (boolean) saisieSouligne.isSelected());
+    StyleConstants.setAlignment(att, PanneauTexte.codeAlignement((String) saisieAlignement.getSelectedItem()));
+    try {
+      decimalSaisi = Float.parseFloat((String) saisieEspaceAvant.getSelectedItem());
+    } catch (NumberFormatException numberFormatException) {
+      decimalSaisi = StyleConstants.getSpaceAbove(att);
+    }
+    StyleConstants.setSpaceAbove(att, decimalSaisi);
+    try {
+      decimalSaisi = Float.parseFloat((String) saisieEspaceApres.getSelectedItem());
+    } catch (NumberFormatException numberFormatException) {
+      decimalSaisi = StyleConstants.getSpaceBelow(att);
+    }
+    StyleConstants.setSpaceBelow(att, decimalSaisi);
+    try {
+      decimalSaisi = Float.parseFloat((String) saisieIndentGauche.getSelectedItem());
+    } catch (NumberFormatException numberFormatException) {
+      decimalSaisi = StyleConstants.getLeftIndent(att);
+    }
+    StyleConstants.setLeftIndent(att, decimalSaisi);
+    try {
+      decimalSaisi = Float.parseFloat((String) saisieIndentDroite.getSelectedItem());
+    } catch (NumberFormatException numberFormatException) {
+      decimalSaisi = StyleConstants.getRightIndent(att);
+    }
+    StyleConstants.setRightIndent(att, decimalSaisi);
+    try {
+      decimalSaisi = Float.parseFloat((String) saisieIndentPrem.getSelectedItem());
+    } catch (NumberFormatException numberFormatException) {
+      decimalSaisi = StyleConstants.getFirstLineIndent(att);
+    }
+    StyleConstants.setFirstLineIndent(att, decimalSaisi);
+    try {
+      decimalSaisi = Float.parseFloat((String) saisieInterligne.getSelectedItem());
+    } catch (NumberFormatException numberFormatException) {
+      decimalSaisi = (Float) StyleConstants.getLineSpacing(att);
+    }
+    StyleConstants.setLineSpacing(att, decimalSaisi);
+    pEditeur.changerStyleTexte(att);
+    dispose();
+  }
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/VisuStyleTexte.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauOccurrences.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauOccurrences.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauOccurrences.java	(revision 3653)
@@ -0,0 +1,172 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.texte;
+
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+import visuAnalec.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class PanneauOccurrences extends JTable implements ListSelectionListener {
+  ModeleTableauOcc modele;
+  ModeleTableur modeleTableur;
+  Vue vue;
+  PanneauEditeur pEditeur;
+  Element[] listElt;
+  final static int EMPAN = 80;  // paramètre à saisir (un jour)
+  public PanneauOccurrences(Vue vue, PanneauEditeur pEditeur) {
+    super();
+    modele = new ModeleTableauOcc();
+    setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+    setModel(modele);
+    modeleTableur = new ModeleTableur();
+    getSelectionModel().addListSelectionListener(this);
+    this.vue = vue;
+    this.pEditeur = pEditeur;
+  }
+  public TableModel getModeleTableur() {
+    return modeleTableur;
+  }
+  public void initVide() {
+    listElt = new Element[0];
+    getTableHeader().setVisible(false);
+    modele.clear();
+    modeleTableur.clear();
+  }
+  public void init(Class<? extends Element> classe, String type, Element[] listElt) {
+    this.listElt = listElt;
+    if (listElt.length==0) {
+      initVide();
+      return;
+    }
+    getTableHeader().setVisible(true);
+    String[] ids = vue.getIdListeElements(classe, type, listElt);
+    String[][] concordances = vue.getCorpus().getConcordances(listElt, EMPAN);
+    String[] champs = vue.getNomsChamps(classe, type);
+    String[][] valeurs = vue.getValeursChampsListeElements(champs, listElt);
+    modele.setModele(ids, concordances);
+    modeleTableur.setModele(ids, concordances, champs, valeurs);
+    getColumnModel().getColumn(0).setPreferredWidth(150);
+    getColumnModel().getColumn(1).setMinWidth(1200);
+  }
+  @Override
+  public void valueChanged(ListSelectionEvent evt) {
+    try {
+      if (evt.getValueIsAdjusting()) return;
+      if (evt.getSource().equals(getSelectionModel())) {
+        int row = getSelectedRow();
+        if (row>=0) pEditeur.editerElement(listElt[row]);
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.toString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+
+  private static class ModeleTableauOcc extends AbstractTableModel {
+    final static String STYLE_HTML = "<html>";
+    final static String STYLE_DEB_SELECT =
+            "<span style=\"font-weight:bold; background-color:#FFFF80\">";
+    final static String STYLE_FIN_SELECT = "</span>";
+    String[] ids;
+    String[] extraits;
+    public ModeleTableauOcc() {
+      super();
+      clear();
+    }
+    public int getRowCount() {
+      return ids.length;
+    }
+    public int getColumnCount() {
+      return 2;
+    }
+    @Override
+    public String getColumnName(int columnIndex) {
+      return columnIndex==0 ? "Identifiants" : "Occurrences";
+    }
+    public Object getValueAt(int rowIndex, int columnIndex) {
+      return columnIndex==0 ? ids[rowIndex] : extraits[rowIndex];
+
+    }
+    private void clear() {
+      ids = new String[0];
+    }
+    private void setModele(String[] ids, String[][] concordances) {
+      this.ids = ids;
+      extraits = new String[ids.length];
+      for (int i = 0; i<ids.length; i++)
+        extraits[i] = formerExtrait(concordances[i]);
+      fireTableDataChanged();
+    }
+    private String formerExtrait(String[] concordance) {
+      return STYLE_HTML+concordance[0]+STYLE_DEB_SELECT+concordance[1]
+              +STYLE_FIN_SELECT+concordance[2];
+    }
+  }
+
+  private static class ModeleTableur extends AbstractTableModel {
+    String[] ids;
+    String[][] concordances;
+    String[] champs;
+    String[][] valeurs;
+    public ModeleTableur() {
+      super();
+      clear();
+    }
+    public int getRowCount() {
+      return ids.length;
+    }
+    public int getColumnCount() {
+      return 4+champs.length;
+    }
+    @Override
+    public String getColumnName(int columnIndex) {
+      switch (columnIndex) {
+        case 0:
+          return "Identifiants";
+        case 1:
+          return "Contexte gauche";
+        case 2:
+          return "Elément";
+        case 3:
+          return "Contexte droit";
+        default:
+          return champs[columnIndex-4];
+      }
+    }
+    public Object getValueAt(int rowIndex, int columnIndex) {
+      switch (columnIndex) {
+        case 0:
+          return ids[rowIndex];
+        case 1:
+        case 2:
+        case 3:
+          return concordances[rowIndex][columnIndex-1];
+        default:
+          return valeurs[rowIndex][columnIndex-4];
+      }
+
+    }
+    private void clear() {
+      champs = ids = new String[0];
+    }
+    private void setModele(String[] ids, String[][] concordances,
+            String[] champs, String[][] valeurs) {
+      this.ids = ids;
+      this.concordances = concordances;
+      this.champs = champs;
+      this.valeurs = valeurs;
+      fireTableDataChanged();
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauOccurrences.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauCommandesModifTexte.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauCommandesModifTexte.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauCommandesModifTexte.java	(revision 3653)
@@ -0,0 +1,58 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package visuAnalec.texte;
+
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.Message.*;
+import visuAnalec.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class PanneauCommandesModifTexte extends Box  {
+  Vue vue;
+  PanneauModifTexte panneauTexte;
+  PanneauEditeur panneauEditeur;
+ public PanneauCommandesModifTexte( PanneauEditeur pEditeur, Vue vue, PanneauModifTexte pTexte) {
+    super(BoxLayout.X_AXIS);
+    this.panneauEditeur = pEditeur;
+    this.vue = vue;
+    this.panneauTexte = pTexte;
+        add(Box.createHorizontalGlue());
+    add( new JButton(new GAction("Valider") {
+      public void executer() {
+        validerModifTexte();
+        panneauEditeur.finModifTexte();
+      }
+    }));
+    add(Box.createHorizontalGlue());
+    add( new JButton(new GAction("Annuler") {
+      public void executer() {
+        panneauEditeur.finModifTexte();
+    }
+    }));
+    add(Box.createHorizontalGlue());
+  }
+ void validerModifTexte() {
+   int nbSupprimes = panneauTexte.preparerValiderModifTexte();
+  if (nbSupprimes > 0) {
+      int rep = JOptionPane.showOptionDialog(getTopLevelAncestor(),
+              "Les modifications du texte vont entraîner la suppression " +
+              (nbSupprimes == 1 ? "d'une unité" : "de " + nbSupprimes + " unités"), "Suppression d'unités",
+              JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+              null, new Object[]{"Continuer", "Annuler"}, "Annuler");
+      if (rep == 1 || rep == JOptionPane.CLOSED_OPTION) return;
+    }
+    panneauTexte.validerModifTexte();
+  }
+ }

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauCommandesModifTexte.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauAffChainesTexte.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauAffChainesTexte.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauAffChainesTexte.java	(revision 3653)
@@ -0,0 +1,77 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.texte;
+
+import java.awt.event.*;
+import java.util.*;
+import visuAnalec.chaines.*;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class PanneauAffChainesTexte extends PanneauTexte {
+  private ListenerSourisTexte sourisListener;
+  private VisuChaines visuChaines;
+  private Marquage marquage;
+  public PanneauAffChainesTexte(Corpus corpus, VisuChaines visuChaines) {
+    super(corpus);
+    setEditable(false);
+    this.visuChaines = visuChaines;
+    setSourisListener(visuChaines);
+    marquage = new Marquage(this);
+  }
+  protected void setSourisListener(VisuChaines vChaines) {
+    sourisListener = new ListenerSourisTexte(this, vChaines);
+    addMouseListener(sourisListener);
+  }
+  public void pasDeMarquage() {
+    marquerUnites(marquage, new TypeMarquage[0], null);
+  }
+  public void montrerUnite(Unite unit, TypeMarquage typeSelectUnite) {
+    TypeMarquage[] typesMarq = new TypeMarquage[]{typeSelectUnite};
+    EnumMap<TypeMarquage, Unite[]> unites = new EnumMap<TypeMarquage, Unite[]>(TypeMarquage.class);
+    unites.put(typeSelectUnite, new Unite[]{unit});
+    marquerUnites(marquage, typesMarq, unites);
+    placerAscenseur(unit);
+  }
+  public void montrerUnite(Unite unit, TypeMarquage typeSelectUnite, Unite[] unitsChaine,
+          TypeMarquage typeSelectChaine) {
+    TypeMarquage[] typesMarq = new TypeMarquage[]{typeSelectUnite, typeSelectChaine};
+    EnumMap<TypeMarquage, Unite[]> unites = new EnumMap<TypeMarquage, Unite[]>(TypeMarquage.class);
+    unites.put(typeSelectUnite, new Unite[]{unit});
+    unites.put(typeSelectChaine, unitsChaine);
+    marquerUnites(marquage, typesMarq, unites);
+    placerAscenseur(unit);
+  }
+  public void colorerUnites(Unite[] units, TypeMarquage typeColorChaines) {
+    TypeMarquage[] typesMarq = new TypeMarquage[]{typeColorChaines};
+    EnumMap<TypeMarquage, Unite[]> unites = new EnumMap<TypeMarquage, Unite[]>(TypeMarquage.class);
+    unites.put(typeColorChaines, units);
+    marquerUnites(marquage, typesMarq, unites);
+  }
+
+  protected static class ListenerSourisTexte extends MouseAdapter {
+    private PanneauAffChainesTexte panneauTexte;
+    private VisuChaines visuChaines;
+    public ListenerSourisTexte(PanneauAffChainesTexte pTexte, VisuChaines vChaines) {
+      this.panneauTexte = pTexte;
+      this.visuChaines = vChaines;
+    }
+    @Override
+    public void mouseClicked(MouseEvent e) {
+ try {
+   Unite uniteVisee = panneauTexte.getUniteVisee(panneauTexte.marquage, e.getPoint());
+      if (uniteVisee == null){  /*visuChaines.traiterAffTexteClicVide();*/}
+      else  if (e.getClickCount() == 2){/* visuChaines.traiterAffTexteDoubleClic(uniteVisee);*/}
+     } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+   }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauAffChainesTexte.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauAffTexte.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauAffTexte.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauAffTexte.java	(revision 3653)
@@ -0,0 +1,318 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.texte;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.texte.PanneauAffTexte.ListenerSourisTexte.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import static visuAnalec.texte.PanneauAffTexte.SourisEvent.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class PanneauAffTexte extends PanneauTexte {
+  private PanneauCommandes panneauCommandes;
+  private ListenerSourisTexte sourisListener;
+  protected Marquage marquage = new Marquage(this);
+  public PanneauAffTexte(Corpus corpus) {
+    super(corpus);
+    coloriage = new Coloriage(this);
+    setEditable(false);
+    setSourisListener();
+  }
+  @Override
+  public String getToolTipText() {
+    Point pt = getMousePosition();
+    if (pt == null) return "";
+    Unite[] unitesVisees = getUnitesVisees(marquage, pt);
+    if (unitesVisees.length == 0) return "";
+    ArrayList<String> textes = new ArrayList<String>();
+    ArrayList<String> idsElementsVises = new ArrayList<String>();
+    for (Unite unit : unitesVisees) {
+      String texte = getTexteUnite(unit);
+      for (ElementMarque eltMarque : panneauCommandes.trouverElementsVises(unit,
+              marquage.getMarquage(unit), true)) {
+        idsElementsVises.add(eltMarque.id);
+        textes.add(texte);
+      }
+    }
+    return GVisu.styleIdTooltip(textes, idsElementsVises);
+  }
+  protected void setSourisListener() {
+    sourisListener = new ListenerSourisTexte(this);
+    addMouseListener(sourisListener);
+  }
+  public void setCommandes(PanneauCommandes panneauCommandes) {
+    this.panneauCommandes = panneauCommandes;
+    sourisListener.setCommandes(panneauCommandes);
+  }
+  private void deselecterUnite(Unite unite) {  // utilisé uniquement pour rectifier une borne
+    int debUnite = indexToPosition(unite.getDeb());
+    int finUnite = indexToPosition(unite.getFin());
+    doc.setCharacterAttributes(debUnite, finUnite - debUnite, AttributsStandard, true);
+  }
+  private void selecterUnite(Unite unite) {   // utilisé uniquement pour rectifier une borne
+    int debUnite = indexToPosition(unite.getDeb());
+    int finUnite = indexToPosition(unite.getFin());
+    doc.setCharacterAttributes(debUnite, finUnite - debUnite, SELECTION_1, true);
+  }
+  public void pasDeMarquage() {
+    marquerUnites(marquage, new TypeMarquage[0], null);
+    sourisListener.setEtat(EtatClic.SAISIE);
+  }
+  public void saisir(Unite amontrer, Unite[] lUnites, TypeMarquage type) {
+    TypeMarquage[] typesMarq = {type};
+    EnumMap<TypeMarquage, Unite[]> unites = new EnumMap<TypeMarquage, Unite[]>(TypeMarquage.class);
+    unites.put(type, lUnites);
+    marquerUnites(marquage, typesMarq, unites);
+    if (amontrer != null) placerAscenseur(amontrer);
+    sourisListener.setEtat(EtatClic.SAISIE);
+  }
+  public void saisir(Unite amontrer, Unite[] lUnites1, TypeMarquage type1, Unite[] lUnites2, TypeMarquage type2) {
+    TypeMarquage[] typesMarq = {type1, type2};
+    EnumMap<TypeMarquage, Unite[]> unites = new EnumMap<TypeMarquage, Unite[]>(TypeMarquage.class);
+    unites.put(type1, lUnites1);
+    unites.put(type2, lUnites2);
+    marquerUnites(marquage, typesMarq, unites);
+    if (amontrer != null) placerAscenseur(amontrer);
+    sourisListener.setEtat(EtatClic.SAISIE);
+  }
+  public void saisir(Unite amontrer, Unite[] lUnites1, TypeMarquage type1,
+          Unite[] lUnites2, TypeMarquage type2, Unite[] lUnites3, TypeMarquage type3) {
+    TypeMarquage[] typesMarq = {type1, type2, type3};
+    EnumMap<TypeMarquage, Unite[]> unites = new EnumMap<TypeMarquage, Unite[]>(TypeMarquage.class);
+    unites.put(type1, lUnites1);
+    unites.put(type2, lUnites2);
+    unites.put(type3, lUnites3);
+    marquerUnites(marquage, typesMarq, unites);
+    if (amontrer != null) placerAscenseur(amontrer);
+    sourisListener.setEtat(EtatClic.SAISIE);
+  }
+  public void saisir(Unite amontrer, Unite[] lUnites1, TypeMarquage type1, Unite[] lUnites2, TypeMarquage type2,
+          Unite[] lUnites3, TypeMarquage type3, Unite[] lUnites4, TypeMarquage type4) {
+    TypeMarquage[] typesMarq = {type1, type2, type3, type4};
+    EnumMap<TypeMarquage, Unite[]> unites = new EnumMap<TypeMarquage, Unite[]>(TypeMarquage.class);
+    unites.put(type1, lUnites1);
+    unites.put(type2, lUnites2);
+    unites.put(type3, lUnites3);
+    unites.put(type4, lUnites4);
+    marquerUnites(marquage, typesMarq, unites);
+    if (amontrer != null) placerAscenseur(amontrer);
+    sourisListener.setEtat(EtatClic.SAISIE);
+  }
+  public void rectifierBorneUnite(Unite unite) {
+    sourisListener.etatChtBornes(unite);
+  }
+  void changerBornes(Unite unite, int borneGauche, int borneDroite) {
+    corpus.modifBornesUnite(unite, borneGauche, borneDroite);
+  }
+
+  public static class SourisEvent {
+    public enum TypeEvent {
+      SELECT_TEXTE, SELECT_RIEN, SELECT_ELEMENT
+    }
+    private TypeEvent type;
+    private Element elementVise;
+    private TypeMarquage marquageElementVise;
+    private int[] bornesSelectionTexte;
+    protected SourisEvent(TypeEvent type) {
+      this(type, null, null, null);
+    }
+    protected SourisEvent(TypeEvent type, Element elt, TypeMarquage marque) {
+      this(type, elt, marque, null);
+    }
+    protected SourisEvent(TypeEvent type, int[] bornes) {
+      this(type, null, null, bornes);
+    }
+    protected SourisEvent(TypeEvent type, Element elt, TypeMarquage marque, int[] bornes) {
+      this.type = type;
+      marquageElementVise = marque;
+      bornesSelectionTexte = bornes;
+      elementVise = elt;
+    }
+    public TypeEvent getTypeEvent() {
+      return type;
+    }
+    public TypeMarquage getMarquageElementVise() {
+      return marquageElementVise;
+    }
+    public int[] getBornesSelectionTexte() {
+      return bornesSelectionTexte;
+    }
+    public Element getElementVise() {
+      return elementVise;
+    }
+  }
+
+  protected static class ListenerSourisTexte extends MouseAdapter {
+    enum EtatClic {
+      INACTIF,
+      SAISIE,
+      BORNES,
+    }
+    private EtatClic etatClic;
+    private Unite uniteABorner;
+    private PanneauAffTexte panneauTexte;
+    private PanneauCommandes panneauCommandes;
+    private JPopupMenuUnites popupMenuUnites;
+    public ListenerSourisTexte(PanneauAffTexte pTexte) {
+      panneauTexte = pTexte;
+      popupMenuUnites = new JPopupMenuUnites(pTexte);
+    }
+    void setCommandes(PanneauCommandes commandes) {
+      panneauCommandes = commandes;
+      popupMenuUnites.setCommandes(commandes);
+    }
+    void setEtat(EtatClic etat) {
+      this.etatClic = etat;
+    }
+    void etatChtBornes(Unite uniteABorner) {
+      etatClic = EtatClic.BORNES;
+      this.uniteABorner = uniteABorner;
+      int deb = panneauTexte.indexToPosition(uniteABorner.getDeb());
+      int fin = panneauTexte.indexToPosition(uniteABorner.getFin());
+      panneauTexte.doc.setCharacterAttributes(deb, fin - deb, BORNAGE, true);
+    }
+    @Override
+    public void mousePressed(MouseEvent e) {
+      if (e.isPopupTrigger()) mousePopup(e);
+    }
+    @Override
+    public void mouseReleased(MouseEvent e) {
+      try {
+        if (e.isPopupTrigger()) {
+          mousePopup(e);
+          return;
+        }
+        switch (etatClic) {
+          case INACTIF:
+          case BORNES:
+            return;
+          case SAISIE:
+            if (panneauTexte.getSelectedText() != null) panneauCommandes.traiterSourisEvent(new SourisEvent(
+                      TypeEvent.SELECT_TEXTE, panneauTexte.getIndSelection()));
+            return;
+          default:
+            throw new UnsupportedOperationException("Cas non prévu d'étatClic");
+        }
+      } catch (Throwable ex) {
+        GMessages.erreurFatale(ex);
+      }
+    }
+    @Override
+    public void mouseClicked(MouseEvent e) {
+      try {
+        if (e.getButton() != MouseEvent.BUTTON1) return;
+        if (e.getClickCount() > 1) return;
+        switch (etatClic) {
+          case INACTIF:  // peut-être inutile ??
+            return;
+          case SAISIE:
+            Unite uniteVisee = panneauTexte.getUniteVisee(panneauTexte.marquage, e.getPoint());
+            if (uniteVisee == null) {
+              panneauCommandes.traiterSourisEvent(new SourisEvent(TypeEvent.SELECT_RIEN));
+              return;
+            }
+            ElementMarque eltM = panneauCommandes.trouverElementsVises(uniteVisee,
+                    panneauTexte.marquage.getMarquage(uniteVisee), false).get(0);
+            panneauCommandes.traiterSourisEvent(new SourisEvent(TypeEvent.SELECT_ELEMENT,
+                    eltM.elt, eltM.marque));
+            return;
+          case BORNES: // à revoir
+            int olddeb = uniteABorner.getDeb();
+            int oldfin = uniteABorner.getFin();
+            int newdeb = olddeb;
+            int newfin = oldfin;
+            int newborne = panneauTexte.positionToIndex(panneauTexte.viewToModel(e.getPoint()));
+            if (2 * newborne < olddeb + oldfin) newdeb = newborne;
+            else newfin = newborne;
+            panneauTexte.deselecterUnite(uniteABorner);
+            panneauTexte.changerBornes(uniteABorner, newdeb, newfin);
+            panneauTexte.selecterUnite(uniteABorner);
+            etatClic = EtatClic.SAISIE;
+            return;
+          default:
+            throw new UnsupportedOperationException("Cas non prévu d'état d'AffTexte");
+        }
+      } catch (Throwable ex) {
+        GMessages.erreurFatale(ex);
+      }
+    }
+    public void mousePopup(MouseEvent e) {
+      Unite[] unitesVisees = panneauTexte.getUnitesVisees(panneauTexte.marquage, e.getPoint());
+      if (unitesVisees.length > 0) {
+        popupMenuUnites.reinitialiser(unitesVisees);
+        popupMenuUnites.show(e.getComponent(), e.getX(), e.getY());
+      }
+    }
+  }
+
+  private static class JPopupMenuUnites extends JPopupMenu {
+    private PanneauAffTexte panneauTexte;
+    private PanneauCommandes panneauCommandes;
+    private ArrayList<ElementMarque> elementsMarques = new ArrayList<ElementMarque>();
+    private Element[] elementsVises;
+    private String[] idsElementsVises;
+    private TypeMarquage[] marquesElementsVises;
+    public JPopupMenuUnites(PanneauAffTexte panneauTexte) {
+      super();
+      this.panneauTexte = panneauTexte;
+    }
+    void setCommandes(PanneauCommandes commandes) {
+      panneauCommandes = commandes;
+    }
+    void reinitialiser(Unite[] unitesVisees) {
+      removeAll();
+      elementsMarques.clear();
+      elementsVises = new Element[unitesVisees.length];
+      idsElementsVises = new String[unitesVisees.length];
+      marquesElementsVises = new TypeMarquage[unitesVisees.length];
+      int no = 0;
+      ArrayList<ElementMarque> eltsMARajouter = new ArrayList<ElementMarque>();
+      ArrayList<String> descrsARajouter = new ArrayList<String>();
+      for (Unite unit : unitesVisees) {
+        String texte = panneauTexte.getTexteUnite(unit);
+        ArrayList<TypeMarquage> typesM = panneauTexte.marquage.getMarquages(unit);
+        for (ElementMarque eltM : panneauCommandes.trouverElementsVises(unit, typesM.get(0), true)) {
+          elementsMarques.add(eltM);
+          String descr = GVisu.styleIdPopup(texte, eltM.id);
+          add(new ActionSelectionUnites(descr, no++));
+        }
+        for (TypeMarquage typeM : typesM.subList(1, typesM.size()))
+          for (ElementMarque eltM : panneauCommandes.trouverElementsVises(unit, typeM, true)) {
+            eltsMARajouter.add(eltM);
+            descrsARajouter.add(GVisu.styleIdPopup(texte, eltM.id));
+          }
+      }
+      for (int i = 0; i < eltsMARajouter.size(); i++) {
+        elementsMarques.add(eltsMARajouter.get(i));
+        add(new ActionSelectionUnites(descrsARajouter.get(i), no++));
+      }
+    }
+
+    private class ActionSelectionUnites extends GAction {
+      int no;
+      private ActionSelectionUnites(String descr, int no) {
+        super(descr);
+        this.no = no;
+      }
+      public void executer() {
+        panneauCommandes.traiterSourisEvent(new SourisEvent(TypeEvent.SELECT_ELEMENT,
+                elementsMarques.get(no).elt, elementsMarques.get(no).marque));
+      }
+    }
+  }
+}
+
+      
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/texte/PanneauAffTexte.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/Courbe.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/Courbe.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/Courbe.java	(revision 3653)
@@ -0,0 +1,146 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package visuAnalec.chaines;
+import java.awt.*;
+import javax.swing.JPopupMenu;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.data.xy.XYDataset;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+import visuAnalec.util.GMessages.GAction;
+/**
+ *
+ * @author Marc
+ */
+//requiert des donnees positives
+public class Courbe{
+    
+
+
+
+public static ChartPanel courbeFactory(){
+    
+        
+        final XYSeriesCollection dataset = new XYSeriesCollection();
+        
+        final JFreeChart chart = ChartFactory.createXYLineChart(
+            "Courbe vide",      // chart title
+            "X",                      // x axis label
+            "Y",                      // y axis label
+            dataset,                  // data
+            PlotOrientation.VERTICAL,
+            true,                     // include legend
+            true,                     // tooltips
+            false                     // urls
+        );
+
+
+        chart.setBackgroundPaint(Color.white);
+
+        final XYPlot plot = chart.getXYPlot();
+        plot.setBackgroundPaint(Color.lightGray);
+
+        plot.setDomainGridlinePaint(Color.white);
+        plot.setRangeGridlinePaint(Color.white);
+        
+        final XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
+        renderer.setSeriesLinesVisible(0, false);
+        renderer.setSeriesShapesVisible(1, false);
+        plot.setRenderer(renderer);
+
+
+        final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
+        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
+        
+        final ChartPanel chartPanel = new ChartPanel(chart);
+        chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
+
+        
+        JPopupMenu save = (JPopupMenu) chartPanel.getPopupMenu().getSubElements()[2].getSubElements()[0];
+        save.add(new GAction("Exporter en PDF") {
+        @Override
+        public void executer() {
+        ExportCSV.writeChartToPDF(chartPanel,500,400);
+        }
+      });
+      save.add(new GAction("Exporter en CSV") {
+        @Override
+        public void executer() {
+        XYDataset dataSet = chartPanel.getChart().getXYPlot().getDataset();
+        if(dataSet.getSeriesCount()>0 && dataSet.getItemCount(0)>0){
+        Object[][] Donnees = new Object[dataSet.getItemCount(0)][dataSet.getSeriesCount()*2];
+        for(int i = 0 ; i < dataSet.getItemCount(0) ; i++){
+            for(int j = 0 ; j < dataSet.getSeriesCount() ; j++){
+                Donnees[i][2*j]=dataSet.getXValue(j, i);
+                Donnees[i][2*j+1]=dataSet.getYValue(j, i);
+            }
+        }
+        ExportCSV.exporterCSV(Donnees);
+        }
+        }
+      });
+    return chartPanel;
+}
+
+
+
+
+public static void updatePanel(ChartPanel window,String titre,Integer[] xData,Integer[] yData,Color couleur, int maxheight, 
+           String abscisse,String ordonnee){
+    
+        final XYSeries series1 = new XYSeries("Point");
+        final XYSeriesCollection dataset = new XYSeriesCollection();
+        for(int i = 0 ; i < xData.length;i++){
+            series1.add(xData[i],yData[i]);
+        }
+        dataset.addSeries(series1);
+        
+        final JFreeChart chart = ChartFactory.createXYLineChart(
+            titre,      // chart title
+            abscisse,                      // x axis label
+            ordonnee,                      // y axis label
+            dataset,                  // data
+            PlotOrientation.VERTICAL,
+            true,                     // include legend
+            true,                     // tooltips
+            false                     // urls
+        );
+
+
+        chart.setBackgroundPaint(Color.white);
+
+        final XYPlot plot = chart.getXYPlot();
+        plot.setBackgroundPaint(Color.lightGray);
+
+        plot.setDomainGridlinePaint(Color.white);
+        plot.setRangeGridlinePaint(Color.white);
+        
+        final XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
+        plot.setRenderer(renderer);
+
+
+        final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
+        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
+        
+        window.setChart(chart);
+        window.setPreferredSize(new java.awt.Dimension(500, 270));
+
+    
+}
+ 
+
+ 
+   
+ 
+    
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/Courbe.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/Histogramme.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/Histogramme.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/Histogramme.java	(revision 3653)
@@ -0,0 +1,115 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package visuAnalec.chaines;
+import java.awt.*;
+import javax.swing.JPopupMenu;
+import org.jfree.chart.*;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.data.statistics.*;
+import org.jfree.data.xy.XYDataset;
+import visuAnalec.util.GMessages.GAction;
+
+import visuAnalec.vue.Vue;
+/**
+ *
+ * @author Marc
+ * inspiré par la page 
+ * http://sebastien-estienne.developpez.com/tutoriels/java/exercices-graphisme-java2d/?page=exo1#LI-3
+ */
+public class Histogramme{
+    
+
+ 
+
+
+
+public static ChartPanel histogrammeFactory(){
+    double[] value = new double[1];
+    value[0]=1.0f;
+    int number = 1;
+    HistogramDataset dataset = new HistogramDataset();
+    dataset.setType(HistogramType.RELATIVE_FREQUENCY);
+    dataset.addSeries("Histogram",value,number);
+    String plotTitle = "Histogram"; 
+    String xaxis = "";
+    String yaxis = ""; 
+    PlotOrientation orientation = PlotOrientation.VERTICAL; 
+    boolean show = false; 
+    boolean toolTips = false;
+    boolean urls = false; 
+    JFreeChart chart = ChartFactory.createHistogram( plotTitle, xaxis, yaxis, 
+    dataset, orientation, show, toolTips, urls);
+    final ChartPanel chartPanel = new ChartPanel(chart);
+    chartPanel.setFillZoomRectangle(true);
+    chartPanel.setMouseWheelEnabled(true);
+    chartPanel.setPreferredSize(new Dimension(500,270));
+    chartPanel.setVisible(true);
+    JPopupMenu save = (JPopupMenu) chartPanel.getPopupMenu().getSubElements()[2].getSubElements()[0];
+        save.add(new GAction("Exporter en PDF") {
+        @Override
+        public void executer() {
+        ExportCSV.writeChartToPDF(chartPanel,500,400);
+        }
+      });
+      save.add(new GAction("Exporter en CSV") {
+        @Override
+        public void executer() {
+        XYDataset dataSet = chartPanel.getChart().getXYPlot().getDataset();
+        if(dataSet.getSeriesCount()>0 && dataSet.getItemCount(0)>0){
+        Object[][] Donnees = new Object[dataSet.getItemCount(0)][dataSet.getSeriesCount()*2];
+        for(int i = 0 ; i < dataSet.getItemCount(0) ; i++){
+            for(int j = 0 ; j < dataSet.getSeriesCount() ; j++){
+                Donnees[i][2*j]=dataSet.getXValue(j, i);
+                Donnees[i][2*j+1]=dataSet.getYValue(j, i);
+            }
+        }
+        ExportCSV.exporterCSV(Donnees);
+        }
+        }
+      });
+    return chartPanel;
+}
+
+
+
+public static void updatePanel(ChartPanel window,String titre,ModeleChaines data,int nb_classes,Color couleur, int maxheight, 
+           String abscisse,String ordonnee,Vue vue){
+    
+        double[] value = new double[data.getUnites().length];
+    for (int i=1; i < data.getUnites().length; i++) {
+            value[i] = (double) data.getUnites()[i].getDeb();
+    }
+    HistogramDataset dataset = new HistogramDataset();
+    dataset.setType(HistogramType.RELATIVE_FREQUENCY);
+    dataset.addSeries("Histogram",value,nb_classes,0.0f,(double) vue.getCorpus().getTexte().length());
+    String plotTitle = "Distribution spatiale des unités"; 
+    String xaxis = abscisse;
+    String yaxis = ordonnee; 
+    PlotOrientation orientation = PlotOrientation.VERTICAL; 
+    boolean show = false; 
+    boolean toolTips = false;
+    boolean urls = false; 
+    JFreeChart chart = ChartFactory.createHistogram( plotTitle, xaxis, yaxis, 
+    dataset, orientation, show, toolTips, urls);
+    window.setChart(chart);
+    window.revalidate();
+    window.repaint();
+    window.setFillZoomRectangle(true);
+    window.setMouseWheelEnabled(true);
+    window.setPreferredSize(new Dimension(500,270));
+    window.setVisible(true);
+    
+}
+ 
+
+
+   
+ 
+
+} 
+
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/Histogramme.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ModeleChaines.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ModeleChaines.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ModeleChaines.java	(revision 3653)
@@ -0,0 +1,807 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.chaines;
+
+import java.awt.*;
+import java.util.*;
+import java.util.ArrayList;
+import visuAnalec.elements.*;
+import visuAnalec.texte.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class ModeleChaines {
+	
+	static class Chainon {
+		
+		Unite unite;
+		
+		String texte;
+		
+		Schema chaine = null;
+		
+		int nbEltsChaine = 0;
+		
+		String idChaine = "";
+		
+		int noChaine = 0;
+		
+		Chainon(Unite unite, String texte) {
+			this.unite = unite;
+			this.texte = texte;
+		}
+	}
+	
+	private Vue vue;
+	
+	private GChaines panneauGraphique;
+	
+	private Unite[] listeUnites;
+	
+	private boolean peutafficher = true;
+	
+	private HashMap<Unite, Schema> chainesUnitesNonFiltrees = new HashMap<>();
+	
+	private int[] seuilsValsNbElements = new int[0];
+	
+	private HashMap<Unite, Chainon> chainonsUnites = new HashMap<>();
+	
+	private HashMap<Schema, ArrayList<Unite>> unitesChaines = new HashMap<>();
+	
+	private HashMap<String, HashSet<String>> valsMasqueesChamp = new HashMap<>();
+	
+	private HashSet<String> valNulleMasqueeChamp = new HashSet<>();
+	
+	private boolean[] valsMasqueesNbElements = new boolean[0];
+	
+	public ModeleChaines(Vue vue, GChaines panneauGraphique) {
+		this.vue = vue;
+		this.panneauGraphique = panneauGraphique;
+	}
+	
+	Schema getChaine(Unite unit) {
+		return chainonsUnites.get(unit).chaine;
+	}
+	
+	public HashMap<Unite, Chainon> getChainonUnites() {
+		return chainonsUnites;
+	}
+	
+	Unite[] getUnites() {
+		return listeUnites;
+	}
+	
+	Unite[] getUnitesChaine(Schema chaine) {
+		ArrayList<Unite> units = unitesChaines.get(chaine);
+		return units.toArray(new Unite[0]);
+	}
+	
+	boolean isMasqueeValChamp(String champ, String val) {
+		return valsMasqueesChamp.containsKey(champ)
+				&& valsMasqueesChamp.get(champ).contains(val);
+	}
+	
+	boolean isMasqueeValNulleChamp(String champ) {
+		return valNulleMasqueeChamp.contains(champ);
+	}
+	
+	boolean isMasqueeValNbElements(int i) {
+		return i >= valsMasqueesNbElements.length ? false : valsMasqueesNbElements[i];
+	}
+	
+	public HashMap<String, HashSet<String>> getValsMasqueesChamp() {
+		return valsMasqueesChamp;
+	}
+	
+	public HashSet<String> getValsNulleMasqueesChamp() {
+		return valNulleMasqueeChamp;
+	}
+	
+	public HashMap<Unite, Schema> getchainesUnitesNonFiltrees() {
+		return chainesUnitesNonFiltrees;
+	}
+	
+	public boolean[] getValsNbMasqueesChamp() {
+		return valsMasqueesNbElements;
+	}
+	
+	public void setValsMasqueesChamp(HashMap<String, HashSet<String>> valsMasqueesChamp) {
+		this.valsMasqueesChamp = valsMasqueesChamp;
+	}
+	
+	public void setValsNulleMasqueesChamp(HashSet<String> valNulleMasqueeChamp) {
+		this.valNulleMasqueeChamp = valNulleMasqueeChamp;
+	}
+	
+	public void setValsNbMasqueesChamp(boolean[] valsMasqueesNbElements) {
+		this.valsMasqueesNbElements = valsMasqueesNbElements;
+	}
+	
+	// retourne le nombre de valeurs masquees pour le champ
+	public int nbvaleursmasquees(String champ) {
+		int resultat = 0;
+		if (champ == null) {// si le champ affiché est le nombre de chainons
+			for (boolean val : valsMasqueesNbElements) {
+				if (val) {
+					resultat = resultat + 1;
+				}
+			}
+		}
+		else {
+			resultat = valsMasqueesChamp.get(champ).size();
+		}
+		return resultat;
+	}
+	
+	void demasquerToutesValsChamp(String champ) {
+		valsMasqueesChamp.get(champ).clear();
+		valNulleMasqueeChamp.remove(champ);
+	}
+	
+	void demasquerToutesValsNbElts(String champ) {
+		for (int i = 0; i < valsMasqueesNbElements.length; i++) {
+			valsMasqueesNbElements[i] = false;
+		}
+	}
+	
+	void setGChaine(GChaines panneaugraphique) {
+		this.panneauGraphique = panneaugraphique;
+	}
+	
+	void setUnites(Unite[] donnees) {
+		this.listeUnites = donnees;
+	}
+	
+	void permettreaffichage(boolean autorisation) {
+		this.peutafficher = autorisation;
+	}
+	
+	boolean peutetreafficher() {
+		return this.peutafficher;
+	}
+	
+	void masquerAutresValsChamp(String typeunite, String champ, String val) {
+		for (String v : vue.getValeursChamp(Unite.class, typeunite, champ))
+			valsMasqueesChamp.get(champ).add(v);
+		valsMasqueesChamp.get(champ).remove(val);
+		valNulleMasqueeChamp.add(champ);
+	}
+	
+	void masquerValChamp(boolean yes, String champ, String val) {
+		if (yes) valsMasqueesChamp.get(champ).add(val);
+		else valsMasqueesChamp.get(champ).remove(val);
+	}
+	
+	void masquerValsNonNullesChamp(String typeunite, String champ) {
+		for (String v : vue.getValeursChamp(Unite.class, typeunite, champ))
+			valsMasqueesChamp.get(champ).add(v);
+		valNulleMasqueeChamp.remove(champ);
+	}
+	
+	void masquerValNulleChamp(boolean yes, String champ) {
+		if (yes) valNulleMasqueeChamp.add(champ);
+		else valNulleMasqueeChamp.remove(champ);
+	}
+	
+	void masquerAutresValsNbElts(String champ, int i0) {
+		for (int i = 0; i < valsMasqueesNbElements.length; i++) {
+			valsMasqueesNbElements[i] = i != i0;
+		}
+	}
+	
+	void masquerValNbElements(boolean yes, int i) {
+		valsMasqueesNbElements[i] = yes;
+	}
+	
+	void init(String typeChaines, String typeUnites, int[] seuils)
+			throws UnsupportedOperationException {
+		seuilsValsNbElements = seuils;
+		String[] champs = vue.getNomsChamps(Unite.class, typeUnites);
+		valsMasqueesChamp.clear();
+		for (String champ : champs)
+			valsMasqueesChamp.put(champ, new HashSet<String>());
+		valNulleMasqueeChamp.clear();
+		valsMasqueesNbElements = new boolean[seuils.length + 3];
+		calculerChainesUnitesNonFiltrees(typeChaines, typeUnites);
+		calculerDonnees(typeChaines, typeUnites);
+	}
+	
+	// struture qui n'est pas filtrées mais qui associe à une unité qui correspond au bon type d'unités
+	// la chaine qui la contient et qui est elle aussi du bon type de Schéma
+	private void calculerChainesUnitesNonFiltrees(String typeChaines,
+			String typeUnites) throws UnsupportedOperationException {
+		chainesUnitesNonFiltrees.clear();
+		for (Schema chaine : vue.getSchemasAVoir(typeChaines))
+			for (Element elt : chaine.getContenu()) {
+				if (elt.getClass() == Unite.class && elt.getType().equals(typeUnites)) {
+					if (chainesUnitesNonFiltrees.containsKey(elt)) {
+						throw new UnsupportedOperationException("L'unité " + vue.getIdElement(elt)
+								+ " appartient à deux chaînes : " + vue.getIdElement(chaine) + " et "
+								+ vue.getIdElement(chainesUnitesNonFiltrees.get(elt)));
+					}
+					else
+						chainesUnitesNonFiltrees.put((Unite) elt, chaine);
+				}
+			}
+	}
+	
+	void modifMasqueVals(String typeChaines, String typeUnites) {
+		calculerDonnees(typeChaines, typeUnites);
+	}
+	
+	void modifMasqueValsChampChaine(String typeChaines, String typeUnites, ArrayList noparagraphecachees, String champ, String Valeur) {
+		calculerDonnees(typeChaines, typeUnites, noparagraphecachees, champ, Valeur);
+	}
+	
+	private void filtrerListeUnites(String typeUnites, String typeChaines) {
+		Unite[] unites = vue.getUnitesAVoir(typeUnites);
+		Schema[] chaines = vue.getSchemasAVoir(typeChaines);
+		unitesChaines.clear();
+		for (Schema chaine : chaines)
+			unitesChaines.put(chaine, new ArrayList<Unite>());
+		ArrayList<Integer> indFiltrees = new ArrayList<>();
+		String[] champs = vue.getNomsChamps(Unite.class, typeUnites);
+		boolean agarder;
+		for (int i = 0; i < unites.length; i++) {
+			agarder = true;
+			for (String champ : champs) {// pour tous les champs
+				String val = vue.getValeurChamp(unites[i], champ);// je recupere la valeur du champ
+				if (val.isEmpty()) {
+					if (valNulleMasqueeChamp.contains(champ)) {
+						agarder = false;
+						break;
+					}
+				}
+				else {
+					if (valsMasqueesChamp.get(champ).contains(val)) {
+						agarder = false;
+						break;
+					}
+				}
+			}
+			if (agarder) {
+				indFiltrees.add(i);
+				if (chainesUnitesNonFiltrees.containsKey(unites[i])) {
+					Schema chaine = chainesUnitesNonFiltrees.get(unites[i]);
+					unitesChaines.get(chaine).add(unites[i]);
+				}
+			}
+		}
+		ArrayList<Integer> indIndFiltrees = new ArrayList<>();
+		for (int k = 0; k < indFiltrees.size(); k++) {
+			Unite unit = unites[indFiltrees.get(k)];
+			if (chainesUnitesNonFiltrees.containsKey(unit)) {
+				if (!isMasqueeValNbElements(calculerValNbElements(
+						unitesChaines.get(chainesUnitesNonFiltrees.get(unit)).size())))
+					indIndFiltrees.add(k);
+			}
+			else {
+				if (!isMasqueeValNbElements(0)) indIndFiltrees.add(k);
+			}
+		}
+		listeUnites = new Unite[indIndFiltrees.size()];
+		for (int k = 0; k < listeUnites.length; k++) {
+			listeUnites[k] = unites[indFiltrees.get(indIndFiltrees.get(k))];
+		}
+		for (Schema chaine : chaines) {
+			int nb = unitesChaines.get(chaine).size();
+			if (nb == 0 || isMasqueeValNbElements(calculerValNbElements(nb)))
+				unitesChaines.remove(chaine);
+		}
+	}
+	
+	private void calculerDonnees(String typeChaines, String typeUnites) {
+		filtrerListeUnites(typeUnites, typeChaines);
+		Chainon[] chainons = new Chainon[listeUnites.length];
+		for (int i = 0; i < listeUnites.length; i++) {
+			Unite unit = listeUnites[i];
+			chainons[i] = new Chainon(unit, vue.getTexteUnite(unit));
+			if (chainesUnitesNonFiltrees.containsKey(unit)) {
+				Schema chaine = chainesUnitesNonFiltrees.get(unit);
+				chainons[i].chaine = chaine;
+				chainons[i].nbEltsChaine = unitesChaines.get(chaine).size();
+				chainons[i].idChaine = vue.getIdElement(chaine);
+			}
+			chainonsUnites.put(listeUnites[i], chainons[i]);
+		}
+		HashMap<Schema, Integer> noChaine = new HashMap<>();
+		int no = 0;
+		for (Schema chaine : vue.getSchemasAVoir(typeChaines)) {
+			if (unitesChaines.containsKey(chaine)) {
+				int nbElts = unitesChaines.get(chaine).size();
+				noChaine.put(chaine, nbElts > 1 ? ++no : 0);
+			}
+		}
+		for (Unite unit : listeUnites) {
+			Chainon chainon = chainonsUnites.get(unit);
+			if (chainon.chaine != null) chainon.noChaine = noChaine.get(chainon.chaine);
+		}
+		int[] noPar = vue.getCorpus().calculerNoParagraphe(listeUnites);
+		if (peutafficher) {
+			panneauGraphique.setDonnees(chainons, noPar);
+		}
+	}
+	
+	void initVide() {
+		listeUnites = new Unite[0];
+		chainesUnitesNonFiltrees.clear();
+		seuilsValsNbElements = new int[0];
+		chainonsUnites.clear();
+		unitesChaines.clear();
+		if (peutafficher) {
+			panneauGraphique.setDonnees(new Chainon[0], new int[0]);
+			panneauGraphique.setCouleurs(new Color[0]);
+			panneauGraphique.setTaille(new int[0]);
+			panneauGraphique.setForme(new int[0]);
+			panneauGraphique.setSurTexte(new String[0]);
+			panneauGraphique.setSousTexte(new String[0]);
+		}
+		valNulleMasqueeChamp.clear();
+		valsMasqueesChamp.clear();
+		valsMasqueesNbElements = new boolean[0];
+	}
+	
+	void setChampAffiche(String champ, HashMap<String, Color> couleursValeursChamp) {
+		if (peutafficher) {
+			panneauGraphique.setCouleurs(colorerChamp(champ, couleursValeursChamp));
+		}
+	}
+	
+	void setChampAfficheTaille(String champ, HashMap<String, Integer> TaillesValeursChamp) {
+		if (peutafficher) {
+			panneauGraphique.setTaille(ReduireChamp(champ, TaillesValeursChamp));
+		}
+	}
+	
+	void setChampAfficheForme(String champ, HashMap<String, Integer> FormesValeursChamp) {
+		if (peutafficher) {
+			panneauGraphique.setForme(FormerChamp(champ, FormesValeursChamp));
+		}
+	}
+	
+	void setChampAfficheSurTexte(String champ, HashMap<String, String> SurTexteValeursChamp) {
+		if (peutafficher) {
+			panneauGraphique.setSurTexte(SurTexteChamp(champ, SurTexteValeursChamp));
+		}
+	}
+	
+	void setChampAfficheSousTexte(String champ, HashMap<String, String> SousTexteValeursChamp) {
+		if (peutafficher) {
+			panneauGraphique.setSousTexte(SousTexteChamp(champ, SousTexteValeursChamp));
+		}
+	}
+	
+	void setChampAfficheNbElts(Color[] couleurs) {
+		if (peutafficher) {
+			panneauGraphique.setCouleurs(colorerNbElts(couleurs));
+		}
+	}
+	
+	
+	
+	void setChampAfficheTailleNbElts(int[] taille) {
+		if (peutafficher) {
+			panneauGraphique.setTaille(ReduireNbElts(taille));
+		}
+	}
+	
+	void setChampAfficheFormeNbElts(int[] forme) {
+		if (peutafficher) {
+			panneauGraphique.setForme(FormeNbElts(forme));
+		}
+	}
+	
+	void setChampAfficheSurTexteNbElts(String[] SurTexte) {
+		if (peutafficher) {
+			panneauGraphique.setSurTexte(SurTexteNbElts(SurTexte));
+		}
+	}
+	
+	void setChampAfficheSousTexteNbElts(String[] SousTexte) {
+		if (peutafficher) {
+			panneauGraphique.setSousTexte(SousTexteNbElts(SousTexte));
+		}
+	}
+	
+	private Color[] colorerNbElts(Color[] couleurs) {
+		Color[] couls = new Color[listeUnites.length];
+		for (int i = 0; i < listeUnites.length; i++) {
+			Chainon ch = chainonsUnites.get(listeUnites[i]);
+			if (ch.chaine == null) couls[i] = couleurs[0];
+			else {
+				int nbElts = ch.nbEltsChaine;
+				couls[i] = couleurs[calculerValNbElements(nbElts)];
+			}
+		}
+		return couls;
+	}
+	
+	private int[] FormeNbElts(int[] formes) {
+		int[] forme = new int[listeUnites.length];
+		for (int i = 0; i < listeUnites.length; i++) {
+			Chainon ch = chainonsUnites.get(listeUnites[i]);
+			if (ch.chaine == null) forme[i] = formes[0];
+			else {
+				int nbElts = ch.nbEltsChaine;
+				forme[i] = formes[calculerValNbElements(nbElts)];
+			}
+		}
+		return forme;
+	}
+	
+	private int[] ReduireNbElts(int[] tailles) {
+		int[] taille = new int[listeUnites.length];
+		for (int i = 0; i < listeUnites.length; i++) {
+			Chainon ch = chainonsUnites.get(listeUnites[i]);
+			if (ch.chaine == null) taille[i] = tailles[0];
+			else {
+				int nbElts = ch.nbEltsChaine;
+				taille[i] = tailles[calculerValNbElements(nbElts)];
+			}
+		}
+		return taille;
+	}
+	
+	private String[] SurTexteNbElts(String[] SurTextes) {
+		String[] SurTexte = new String[listeUnites.length];
+		for (int i = 0; i < listeUnites.length; i++) {
+			Chainon ch = chainonsUnites.get(listeUnites[i]);
+			if (ch.chaine == null) SurTexte[i] = SurTextes[0];
+			else {
+				int nbElts = ch.nbEltsChaine;
+				SurTexte[i] = SurTextes[calculerValNbElements(nbElts)];
+			}
+		}
+		return SurTexte;
+	}
+	
+	private String[] SousTexteNbElts(String[] SousTextes) {
+		String[] SousTexte = new String[listeUnites.length];
+		for (int i = 0; i < listeUnites.length; i++) {
+			Chainon ch = chainonsUnites.get(listeUnites[i]);
+			if (ch.chaine == null) SousTexte[i] = SousTextes[0];
+			else {
+				int nbElts = ch.nbEltsChaine;
+				SousTexte[i] = SousTextes[calculerValNbElements(nbElts)];
+			}
+		}
+		return SousTexte;
+	}
+	
+	
+	private Color[] colorerChamp(String champ, HashMap<String, Color> couleursValeursChamp) {
+		Color[] couls = new Color[listeUnites.length];
+		for (int i = 0; i < listeUnites.length; i++) {
+			Chainon ch = chainonsUnites.get(listeUnites[i]);
+			couls[i] = couleursValeursChamp.get(vue.getValeurChamp(ch.unite, champ));
+		}
+		return couls;
+	}
+	
+	// même chose que colorer champ mais en influant la taille des chainons
+	private int[] ReduireChamp(String champ, HashMap<String, Integer> TaillesValeursChamp) {
+		int[] taille = new int[listeUnites.length];
+		for (int i = 0; i < listeUnites.length; i++) {
+			Chainon ch = chainonsUnites.get(listeUnites[i]);
+			taille[i] = TaillesValeursChamp.get(vue.getValeurChamp(ch.unite, champ));
+		}
+		return taille;
+	}
+	
+	// même chose que colorer champ mais en influant la forme des chainons
+	private int[] FormerChamp(String champ, HashMap<String, Integer> FormesValeursChamp) {
+		int[] forme = new int[listeUnites.length];
+		for (int i = 0; i < listeUnites.length; i++) {
+			Chainon ch = chainonsUnites.get(listeUnites[i]);
+			forme[i] = FormesValeursChamp.get(vue.getValeurChamp(ch.unite, champ));
+		}
+		return forme;
+	}
+	
+	// même chose que colorer champ mais en influant le texte au dessus des chainons
+	private String[] SurTexteChamp(String champ, HashMap<String, String> SurTexteValeursChamp) {
+		String[] SurTexte = new String[listeUnites.length];
+		for (int i = 0; i < listeUnites.length; i++) {
+			Chainon ch = chainonsUnites.get(listeUnites[i]);
+			SurTexte[i] = SurTexteValeursChamp.get(vue.getValeurChamp(ch.unite, champ));
+		}
+		return SurTexte;
+	}
+	
+	// même chose que colorer champ mais en influant le texte au dessous des chainons
+	private String[] SousTexteChamp(String champ, HashMap<String, String> SousTexteValeursChamp) {
+		String[] SousTexte = new String[listeUnites.length];
+		for (int i = 0; i < listeUnites.length; i++) {
+			Chainon ch = chainonsUnites.get(listeUnites[i]);
+			SousTexte[i] = SousTexteValeursChamp.get(vue.getValeurChamp(ch.unite, champ));
+		}
+		return SousTexte;
+	}
+	
+	
+	public int calculerValNbElements(int nbElts) {
+		return nbElts == 1 ? 1 : nbElts <= seuilsValsNbElements[0] ? 2 : nbElts <= seuilsValsNbElements[1] ? 3 : 4;
+	}
+	
+	
+	
+	// retourne un tableau contenant les numéros de paragraphe qui contiennent des unités du modele
+	public Integer[] listenumeroparagraphe() {
+		int[] noparagraphe = (vue.getCorpus()).calculerNoParagraphe(listeUnites);
+		ArrayList<Integer> resultat = new ArrayList<>();
+		int former = -1;
+		for (int i = 0; i < noparagraphe.length; i++) {
+			if (former != noparagraphe[i]) {
+				resultat.add(noparagraphe[i]);
+				former = noparagraphe[i];
+			}
+		}
+		Integer[] resultatconversion = new Integer[resultat.size()];
+		return (resultat.toArray(resultatconversion));
+	}
+	
+	
+	// renvoie un Hashmap quidécrit la répartition des unités en position
+	// au sein du texte
+	// @require : listesUnites est trié selon la position de debut de ses éléments
+	public ArrayList<int[]> dispositionunites(int nbclasses) {
+		Unite[] unites = listeUnites;
+		ArrayList<int[]> locationunites = new ArrayList<>(nbclasses);
+		int longueurtexte = vue.getCorpus().getTexte().length();
+		int[] listeposition = ChaineUtil.discretisation(0, longueurtexte, nbclasses + 1);
+		int posprev = 0;
+		if (nbclasses > 0) {
+			int posactuel = 1;
+			int compte = 0;
+			int k = 0;
+			while (k < unites.length || posactuel < nbclasses + 1) {
+				if (k < unites.length && unites[k].getDeb() < listeposition[posactuel]
+						&& unites[k].getDeb() >= listeposition[posprev]) {
+					// si l'unite est dans cette partie du texte alors on incrémente le compteur
+					compte = compte + 1;
+					k = k + 1;
+				}
+				else {
+					posprev = posactuel;// on actualise la position precedente
+					locationunites.add(new int[] { listeposition[posprev], compte });
+					compte = 0;
+					posactuel = posactuel + 1;
+				}
+			}
+		}
+		return locationunites;
+	}
+	
+	
+	
+	
+	// renvoie un tableau contenant les fréquences de chaque valeur d'un champ de la chaine dans la liste d'unités
+	public HashMap<String, Float> calculerfrequencechaine(Unite[] donnees, String typeChaines, String Champcible, HashSet<String> valeurinterdite) {
+		String[] valsdisponibles = vue.getValeursChamp(Schema.class, typeChaines, Champcible);
+		HashMap<String, Float> tableaufrequence = new HashMap<>(valsdisponibles.length + 1);
+		String valeurchamp;
+		// on initialise le tableau résultat
+		for (String valeur : valsdisponibles) {
+			tableaufrequence.put(valeur, 0.0f);
+		}
+		tableaufrequence.put("", 0.0f);
+		int compteur = 0;
+		// on compte le nombre d'occurences
+		for (Unite unit : donnees) {
+			valeurchamp = chainesUnitesNonFiltrees.containsKey(unit) ? vue.getValeurChamp(chainesUnitesNonFiltrees.get(unit), Champcible) : null;
+			if (valeurchamp != null && !valeurinterdite.contains(valeurchamp)) {
+				compteur = compteur + 1;
+				tableaufrequence.put(valeurchamp, tableaufrequence.get(valeurchamp) + 1);
+			}
+		}
+		// on calcule les pourcentages
+		for (String valeur : valsdisponibles) {
+			tableaufrequence.put(valeur, compteur == 0 ? 0.0f
+					: tableaufrequence.get(valeur) * 10000.0f /
+							compteur / 100.0f);
+		}
+		tableaufrequence.put("", compteur == 0 ? 0.0f
+				: tableaufrequence.get("") * 10000.0f /
+						compteur / 100.0f);
+		
+		return tableaufrequence;
+	}
+	
+	// renvoie un tableau contenant les fréquences de chaque longueur des chaines de la liste d'unités
+	public HashMap<String, Float> calculerfrequencenbelt(Unite[] donnees, String typeUnites, String[] valsdisponibles) {
+		HashMap<String, Float> tableaufrequence = new HashMap<>(valsdisponibles.length);
+		String valeurchamp;
+		// on initialise le tableau résultat
+		for (String valeur : valsdisponibles) {
+			tableaufrequence.put(valeur, 0.0f);
+		}
+		int compte = 0;
+		// on compte le nombre d'occurences
+		for (Unite unit : donnees) {
+			Schema chaine = chainesUnitesNonFiltrees.containsKey(unit) ? chainesUnitesNonFiltrees.get(unit)
+					: null;
+			int nb = chaine == null ? 0 : unitesChaines.get(chaine).size();
+			if (isMasqueeValNbElements(calculerValNbElements(nb))) {
+				
+			}
+			else if (nb == 0) {
+				valeurchamp = valsdisponibles[0];
+				tableaufrequence.put(valeurchamp, tableaufrequence.get(valeurchamp) + 1);
+				compte = compte + 1;
+			}
+			else {
+				valeurchamp = valsdisponibles[calculerValNbElements(nb)];
+				tableaufrequence.put(valeurchamp, tableaufrequence.get(valeurchamp) + 1);
+				compte = compte + 1;
+			}
+		}
+		
+		
+		// on calcule les pourcentages
+		for (String valeur : valsdisponibles) {
+			tableaufrequence.put(valeur, tableaufrequence.get(valeur) * 10000.0f /
+					compte / 100.0f);
+		}
+		
+		
+		return tableaufrequence;
+	}
+	
+	
+	
+	
+	// on enlève les unités dont les valeurs des chaines les contenant sont masquees
+	public Unite[] filtrechaine(Unite[] donnees, String Champ, HashSet<String> Valeurcachees) {
+		ArrayList<Unite> unitefiltrees = new ArrayList<>();
+		for (Unite unit : donnees) {
+			if (chainesUnitesNonFiltrees.containsKey(unit) && !(Valeurcachees.contains(vue.getValeurChamp(chainesUnitesNonFiltrees.get(unit), Champ)))) {
+				unitefiltrees.add(unit);
+			}
+		}
+		Unite[] resultat = unitefiltrees.toArray(new Unite[0]);
+		return resultat;
+	}
+	
+	// on ne garde que les unités dont les chaines les contenant possèdent la valeur "valeur" pour le champ
+	// "Champ"
+	public Unite[] filtrevaleurchaine(Unite[] donnees, String Champ, String valeur) {
+		ArrayList<Unite> uniteduchamp = new ArrayList<>();
+		ArrayList<Unite> unitefiltrees = new ArrayList<>();
+		for (Schema chaine : unitesChaines.keySet()) {
+			// on trie les unités dont les chaines contenant ont la bonne valeur pour le champ
+			if ((vue.getValeurChamp(chaine, Champ)).equals(valeur)) {
+				uniteduchamp.addAll(unitesChaines.get(chaine));
+			}
+		}
+		// on ne garde que les unités passée en paramètre
+		for (int i = 0; i < donnees.length; i++) {
+			if (uniteduchamp.contains(donnees[i])) {
+				unitefiltrees.add(donnees[i]);
+			}
+		}
+		// on met le résultat sous forme de tableau
+		Unite[] resultat = (Unite[]) unitefiltrees.toArray();
+		return resultat;
+	}
+	
+	
+	// renvoioe la chaine qui contient l'unité dans ModeleChaine
+	public Schema getSchemacontenantunite(Unite unit) {
+		return chainesUnitesNonFiltrees.get(unit);
+	}
+	
+	// filtre qui remplit les mêmes fonctions que le précédent mais également qui filtre suivant une liste de
+	// paragraphes interdits et ne garde que les unités appartenant aux chaines ayant pour le champ Champ la valeur
+	// Valeur
+	private void filtrerListeUnites(String typeUnites, String typeChaines, ArrayList<Integer> noparagraphecachees,
+			String Champ, String Valeur) {
+		Unite[] unites = vue.getUnitesAVoir(typeUnites);
+		Schema[] chaines = vue.getSchemasAVoir(typeChaines);
+		unitesChaines.clear();
+		int[] noparagraphe = (vue.getCorpus()).calculerNoParagraphe(unites);
+		for (Schema chaine : chaines)
+			unitesChaines.put(chaine, new ArrayList<Unite>());
+		ArrayList<Integer> indFiltrees = new ArrayList<>();
+		String[] champs = vue.getNomsChamps(Unite.class, typeUnites);
+		boolean agarder;
+		for (int i = 0; i < unites.length; i++) {
+			agarder = true;
+			for (String champ : champs) {// pour tous les champs
+				String val = vue.getValeurChamp(unites[i], champ);// je recupere la valeur du champ
+				if (val.isEmpty()) {
+					if (valNulleMasqueeChamp.contains(champ)) {
+						agarder = false;
+						break;
+					}
+				}
+				else {
+					if (valsMasqueesChamp.get(champ).contains(val)) {
+						agarder = false;
+						break;
+					}
+				}
+			}
+			// si l'unité appartient à un paragraphe interdit
+			if (noparagraphecachees.contains(noparagraphe[i])) {
+				agarder = false;
+			}
+			// si la chaine contenant l'unité a une mauvaise valeur pour le champ ou si l'unité est sans chaine
+			if (!chainesUnitesNonFiltrees.containsKey(unites[i]) ||
+					!vue.getValeurChamp(chainesUnitesNonFiltrees.get(unites[i]), Champ).equals(Valeur)) {
+				agarder = false;
+			}
+			if (agarder) {
+				indFiltrees.add(i);
+				if (chainesUnitesNonFiltrees.containsKey(unites[i])) {
+					Schema chaine = chainesUnitesNonFiltrees.get(unites[i]);
+					unitesChaines.get(chaine).add(unites[i]);
+				}
+			}
+		}
+		ArrayList<Integer> indIndFiltrees = new ArrayList<>();
+		for (int k = 0; k < indFiltrees.size(); k++) {
+			Unite unit = unites[indFiltrees.get(k)];
+			if (chainesUnitesNonFiltrees.containsKey(unit)) {
+				if (!isMasqueeValNbElements(calculerValNbElements(
+						unitesChaines.get(chainesUnitesNonFiltrees.get(unit)).size())))
+					indIndFiltrees.add(k);
+			}
+			else {
+				if (!isMasqueeValNbElements(0)) indIndFiltrees.add(k);
+			}
+		}
+		listeUnites = new Unite[indIndFiltrees.size()];
+		for (int k = 0; k < listeUnites.length; k++) {
+			listeUnites[k] = unites[indFiltrees.get(indIndFiltrees.get(k))];
+		}
+		for (Schema chaine : chaines) {
+			int nb = unitesChaines.get(chaine).size();
+			if (nb == 0 || isMasqueeValNbElements(calculerValNbElements(nb)))
+				unitesChaines.remove(chaine);
+		}
+	}
+	
+	// permet de calculer les données pour une valeur de champ de la chaine
+	private void calculerDonnees(String typeChaines, String typeUnites, ArrayList<Integer> noparagraphecachees, String champ, String Valeur) {
+		filtrerListeUnites(typeUnites, typeChaines, noparagraphecachees, champ, Valeur);
+		Chainon[] chainons = new Chainon[listeUnites.length];
+		for (int i = 0; i < listeUnites.length; i++) {
+			Unite unit = listeUnites[i];
+			chainons[i] = new Chainon(unit, vue.getTexteUnite(unit));
+			if (chainesUnitesNonFiltrees.containsKey(unit)) {
+				Schema chaine = chainesUnitesNonFiltrees.get(unit);
+				chainons[i].chaine = chaine;
+				chainons[i].nbEltsChaine = unitesChaines.get(chaine).size();
+				chainons[i].idChaine = vue.getIdElement(chaine);
+			}
+			chainonsUnites.put(listeUnites[i], chainons[i]);
+		}
+		HashMap<Schema, Integer> noChaine = new HashMap<>();
+		int no = 0;
+		for (Schema chaine : vue.getSchemasAVoir(typeChaines)) {
+			if (unitesChaines.containsKey(chaine)) {
+				int nbElts = unitesChaines.get(chaine).size();
+				noChaine.put(chaine, nbElts > 1 ? ++no : 0);
+			}
+		}
+		for (Unite unit : listeUnites) {
+			Chainon chainon = chainonsUnites.get(unit);
+			if (chainon.chaine != null) chainon.noChaine = noChaine.get(chainon.chaine);
+		}
+		int[] noPar = vue.getCorpus().calculerNoParagraphe(listeUnites);
+		if (peutafficher) {
+			panneauGraphique.setDonnees(chainons, noPar);
+		}
+	}
+	
+	
+	
+	
+	
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ModeleChaines.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/GChaines.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/GChaines.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/GChaines.java	(revision 3653)
@@ -0,0 +1,1027 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.chaines;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.chaines.ModeleChaines.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.fichiers.FichiersGraphique;
+/**
+ *
+ * @author Bernard
+ */
+public class GChaines extends JPanel {//donnée de la chaine
+  final static Font FONTE_ID = Font.decode("Arial bold 10");
+  final static int RAYON_DISQUES = 12;
+  final static int MARGE_DISQUES = 2;
+  final static int LARGEUR_INTER_CHAINONS = 10;
+  final static int MARGE_DEBUT_LIGNE = 15;
+  final static int HAUTEUR_LIGNES = 80;
+  final static int HAUTEUR_SEGMENT = 40;
+  final static int HAUTEUR_CHAINONS = 60;
+  final static int policeTailleSVG = 10;
+  final static String policeSVG = "font-size:50px;font-family:'Trebuchet MS', Verdana, serif;";
+  final static String SYMBOLE_SEGMENT = "§";
+//    final static int hauteurinfLien = 25;
+//    final static int deltahauteurLien = 5;
+//    final static int deltasupArcs = 95;
+//    final static int hauteurinfArcs = 5;
+//  final static int HAUTEUR_PANNEAU = 120;
+  final static String PAS_DE_NUMERO = "~";
+
+  static class GChainon extends JButton {//permet de créer un chainon hérite d'un bouton
+    VisuChaines visu;
+    VisuCoref visucoref;
+    Chainon chainon;
+    public GChainon(Chainon ch, VisuChaines vis) {
+      super();//on recupere le bouton
+      this.visu = vis;//on récupère le chainon et le visu
+      this.chainon = ch;
+      Icon d = new DisqueCouleurIcone(Color.WHITE, RAYON_DISQUES, MARGE_DISQUES);
+      setAction(new GAction(null, d) {
+        public void executer() {
+          //visu.afficherOccurrences(chainon.unite, chainon.chaine);
+        }
+      });
+  
+      setSize(2*(RAYON_DISQUES+MARGE_DISQUES), 2*(RAYON_DISQUES+MARGE_DISQUES));//on calcule la taille
+      setBorderPainted(false);
+      String t2 = "<html><div style=\"font-size:11pt\"><span style=\"font-style:italic\">"+chainon.texte
+              +"</span><p>"+chainon.idChaine+"<p>"+chainon.nbEltsChaine+" occurences </div>";//cree les metadonnees
+      setToolTipText(t2);
+      setBackground(Color.WHITE);//arrière plan
+      setFocusPainted(false);
+    }
+    public GChainon(Chainon ch, VisuCoref vis) {
+      super();//on recupere le bouton
+      this.visucoref = vis;//on récupère le chainon et le visu
+      this.chainon = ch;
+      Icon d = new DisqueCouleurIcone(Color.WHITE, RAYON_DISQUES, MARGE_DISQUES);
+      setAction(new GAction(null, d) {
+        public void executer() {
+          //visu.afficherOccurrences(chainon.unite, chainon.chaine);
+        }
+      }); 
+        
+      setSize(2*(RAYON_DISQUES+MARGE_DISQUES), 2*(RAYON_DISQUES+MARGE_DISQUES));//on calcule la taille
+      setBorderPainted(false);
+      String t2 = "<html><div style=\"font-size:11pt\"><span style=\"font-style:italic\">"+chainon.texte
+              +"</span><p>"+chainon.idChaine+"<p>"+chainon.nbEltsChaine+" occurences </div>";//cree les metadonnees
+      setToolTipText(t2);
+      setBackground(Color.WHITE);//arrière plan
+      setFocusPainted(false);
+    }
+      
+    @Override
+    public JToolTip createToolTip() {
+      JToolTip jt = new JToolTip();
+      jt.setBackground(Color.WHITE);
+      return jt;
+    }
+    void changerCouleur(Color couleur) {//change couleur du disque
+      setIcon(new DisqueCouleurIcone(couleur, RAYON_DISQUES, MARGE_DISQUES));
+    }
+    void changerCouleur(Color couleur,int taillediviseur,int forme) {
+    //change couleur,forme et taille du chainon
+        switch(forme){
+            case 0 :
+                setIcon(new DisqueCouleurIcone(couleur, RAYON_DISQUES / taillediviseur
+                        , MARGE_DISQUES));
+                break;
+            case 1 :
+                setIcon(new CarreCouleurIcone(couleur, RAYON_DISQUES / taillediviseur
+                        , MARGE_DISQUES));
+                break;
+            case 2 :
+                setIcon(new CroixCouleurIcone(couleur, RAYON_DISQUES / taillediviseur
+                        , MARGE_DISQUES));
+                break;
+            case 3 :
+                setIcon(new TriangleCouleurIcone(couleur, RAYON_DISQUES / taillediviseur
+                        , MARGE_DISQUES));
+                break;
+            default :
+                setIcon(new TriangleinverseCouleurIcone(couleur, RAYON_DISQUES / taillediviseur
+                        , MARGE_DISQUES));
+                break;
+        }
+    }    
+    
+  }
+
+  static class GNoChainon extends JLabel {//pas de chainon mais du texte
+    public GNoChainon(String contenu) {
+      super(contenu);
+      setFont(FONTE_ID);//police de texte
+      setSize(21,13);
+    }
+    void localiser(Point chainonPosition, Dimension chainonTaille) {
+      int x = chainonPosition.x+chainonTaille.width/2-getSize().width/2;
+      int y = chainonPosition.y-getSize().height;
+      setLocation(x, y);
+    }
+    
+  }
+  
+  static class GNoSousChainon extends JLabel {//pas de chainon mais du texte
+    public GNoSousChainon(String contenu) {
+      super(contenu);
+      setFont(FONTE_ID);//police de texte
+      setSize(21,13);
+    }
+    void localiser(Point chainonPosition, Dimension chainonTaille) {
+      int x = chainonPosition.x+chainonTaille.width/2-getSize().width/2;
+      int y = chainonPosition.y+2*(RAYON_DISQUES+MARGE_DISQUES);
+      setLocation(x, y);
+    }
+  }  
+
+  private enum TypeSegment {//segment correspondant au paragraphe 
+    COMPLET("", ""),
+    DEBUT("", "-"),
+    MILIEU("-", "-"),
+    FIN("-", "");
+    String marqueAvant, marqueApres;
+    private TypeSegment(String avant, String apres) {
+      marqueAvant = avant;
+      marqueApres = apres;
+    }
+  }
+
+  static class GSegment extends JLabel {//on ajoute des propriétés à un label texte
+    int xmin, xmax;
+    int ybas, yhaut;
+    int no;
+    TypeSegment type;
+    GSegment(int xmin, int xmax, int ybas, int yhaut, int no, TypeSegment type) {
+      super(type.marqueAvant+SYMBOLE_SEGMENT+Integer.toString(no)+type.marqueApres);
+      setFont(FONTE_ID);//police de texte
+      this.xmin = xmin;
+      this.xmax = xmax;
+      this.ybas = ybas;
+      this.yhaut = yhaut;
+      this.type = type;
+      setSize(getPreferredSize());
+    }
+    void localiser() {//on localise où placer le symbole du paragraphe
+      setLocation((xmin+xmax)/2-getSize().width/2, yhaut-getSize().height);
+    }
+    void dessinerTraits(Graphics graphics) {//dessine les traits du pragraphe
+      Graphics2D g = (Graphics2D) graphics;
+      g.setColor(Color.BLACK);
+      Point p0 = new Point(xmin, ybas);
+      Point p1 = new Point(xmin, yhaut);
+      Point p2 = new Point(xmax, yhaut);
+      Point p3 = new Point(xmax, ybas);
+      switch (type) {
+        case COMPLET:
+          g.draw(new Line2D.Float(p0, p1));
+          g.draw(new Line2D.Float(p1, p2));
+          g.draw(new Line2D.Float(p2, p3));
+          break;
+        case DEBUT:
+          g.draw(new Line2D.Float(p0, p1));
+          g.draw(new Line2D.Float(p1, p2));
+          break;
+        case FIN:
+          g.draw(new Line2D.Float(p1, p2));
+          g.draw(new Line2D.Float(p2, p3));
+          break;
+        case MILIEU:
+          g.draw(new Line2D.Float(p1, p2));
+          break;
+      }
+    }
+  }
+  /*
+   * Champs de la classeGChaines
+   */
+  VisuChaines visu;
+  VisuCoref visucoref;
+  Chainon[] chainons = new Chainon[0];
+  int[] noSegments = new int[0];
+  Color[] couleurs = new Color[0];
+  int[] taille = new int[0];
+  int[] forme = new int[0];
+  String[] SurTexte = new String[0];
+  String[] SousTexte = new String[0];  
+  boolean couperparagraphe = false;
+  GChainon[] gChainons;
+  GNoChainon[] gNoChainon;
+  GNoSousChainon[] gNoSousChainon;
+  JButton exporter;
+  boolean permettreSousTexte = false;
+  ArrayList<GSegment> gSegments = new ArrayList<GSegment>();
+  private int nbChainonsParLigne = 1000;
+  GChaines(VisuChaines vc) {
+    super((LayoutManager) null);
+    setBackground(Color.WHITE);
+    this.visu = vc;
+    addMouseListener(new MouseAdapter() {
+      @Override
+      public void mouseClicked(MouseEvent e) {
+       // visu.traiterAffTexteClicVide();
+      }
+    });
+  }
+  GChaines(VisuCoref vc) {
+    super((LayoutManager) null);
+    setBackground(Color.WHITE);
+    this.visucoref = vc;
+    addMouseListener(new MouseAdapter() {
+      @Override
+      public void mouseClicked(MouseEvent e) {
+       // visu.traiterAffTexteClicVide();
+      }
+    });
+  }  
+  GChaines(VisuStatGenerale vc) {
+    super((LayoutManager) null);
+    setBackground(Color.WHITE);
+    addMouseListener(new MouseAdapter() {
+      @Override
+      public void mouseClicked(MouseEvent e) {
+       // visu.traiterAffTexteClicVide();
+      }
+    });
+  }    
+  void setNbChainonsParLigne(int nb) {
+    nbChainonsParLigne = nb;
+    afficher();
+    colorer();
+  }
+  void setDonnees(Chainon[] chainons, int[] noSegments) {
+    this.chainons = chainons;
+    this.noSegments = noSegments;
+    afficher();
+  }
+  void setcouperparagraphe(boolean couperparagraphe){
+      this.couperparagraphe = couperparagraphe;
+  }
+  //cherche la longueur du paragraphe
+  private int longueurpara(int[] nosegments,int deb){
+      for(int  i = deb; i < nosegments.length - 1;i++){
+          if(noSegments[i+1]>noSegments[i]){
+              return i + 1 - deb;
+          }
+      }
+      return -1;
+  }
+  private void afficher() {
+    effacerTout();
+    if (chainons.length==0) return;
+    gChainons = new GChainon[chainons.length];
+    int xCourant = MARGE_DEBUT_LIGNE+LARGEUR_INTER_CHAINONS;
+    int yCourant = 0;
+    gNoChainon = new GNoChainon[chainons.length];
+    if(permettreSousTexte){
+    gNoSousChainon = new GNoSousChainon[chainons.length];
+    }
+    int positionligne = 0;
+    int xminSeg = MARGE_DEBUT_LIGNE+LARGEUR_INTER_CHAINONS/2+2;
+    GSegment gseg;
+    int xmaxSeg = 0;
+    int xmaxligne = 0;
+    for (int i = 0; i<chainons.length; i++) {
+        if(visu==null){
+      gChainons[i] = new GChainon(chainons[i], visu);
+        }
+        else{
+        gChainons[i] = new GChainon(chainons[i], visucoref);    
+        }
+      add(gChainons[i]);
+      gChainons[i].setLocation(xCourant, yCourant+HAUTEUR_CHAINONS);
+      add(gNoChainon[i] = new GNoChainon(chainons[i].texte.length()<4 ? 
+              chainons[i].texte.substring(0, chainons[i].texte.length()) 
+              : chainons[i].texte.substring(0,4)));
+      gNoChainon[i].localiser(gChainons[i].getLocation(), gChainons[i].getSize());
+      if(permettreSousTexte){
+      add(gNoSousChainon[i] = new GNoSousChainon(chainons[i].texte.length()<4 ? 
+              chainons[i].texte.substring(0, chainons[i].texte.length()) 
+              : chainons[i].texte.substring(0,4)));
+      gNoSousChainon[i].localiser(gChainons[i].getLocation(), gChainons[i].getSize());  
+      }
+      xCourant += gChainons[i].getWidth()+LARGEUR_INTER_CHAINONS;
+      xmaxligne = Math.max(xCourant, xmaxligne);
+      xmaxSeg = xCourant-LARGEUR_INTER_CHAINONS/2-2;
+      if (i+1==chainons.length||noSegments[i+1]>noSegments[i]) {
+        // fin de paragraphe, donc on trace un segment terminal  
+        if (xminSeg>0) {  // le paragraphe a commencé sur cette ligne
+          add(gseg = new GSegment(xminSeg, xmaxSeg, yCourant+HAUTEUR_CHAINONS,
+                  yCourant+HAUTEUR_SEGMENT, noSegments[i], TypeSegment.COMPLET));
+        } else {  // le paragraphe a commencé avant cette ligne
+          xminSeg = MARGE_DEBUT_LIGNE+LARGEUR_INTER_CHAINONS/2+2;
+          add(gseg = new GSegment(xminSeg, xmaxSeg, yCourant+HAUTEUR_CHAINONS,
+                  yCourant+HAUTEUR_SEGMENT, noSegments[i], TypeSegment.FIN));
+        }
+        gseg.localiser();
+        gSegments.add(gseg);
+        xminSeg = xmaxSeg+4;
+      }
+      if (i+1!=chainons.length && ((!couperparagraphe && (i+1)%nbChainonsParLigne==0) || 
+              (couperparagraphe && (((positionligne+1)%nbChainonsParLigne==0) || (noSegments[i+1]>noSegments[i]
+              && longueurpara(noSegments,i+1) <= nbChainonsParLigne && (nbChainonsParLigne - positionligne - 1) < 
+              longueurpara(noSegments,i+1)))))) {  // on va changer de ligne
+        if (xminSeg>xmaxSeg) {  // ça tombe bien : on change aussi de segment
+          xminSeg = MARGE_DEBUT_LIGNE+LARGEUR_INTER_CHAINONS/2+2;
+        } else { // ca tombe pas bien : il faut tracer un segment non terminal
+          if (xminSeg>0) { // le paragraphe a commencé sur cette ligne
+            add(gseg = new GSegment(xminSeg, xmaxSeg, yCourant+HAUTEUR_CHAINONS,
+                    yCourant+HAUTEUR_SEGMENT, noSegments[i], TypeSegment.DEBUT));
+          } else {  // le paragraphe a commencé avant cette ligne
+            xminSeg = MARGE_DEBUT_LIGNE+LARGEUR_INTER_CHAINONS/2+2;
+            add(gseg = new GSegment(xminSeg, xmaxSeg, yCourant+HAUTEUR_CHAINONS,
+                    yCourant+HAUTEUR_SEGMENT, noSegments[i], TypeSegment.MILIEU));
+          }
+          gseg.localiser();
+          gSegments.add(gseg);
+          xminSeg = -1;
+        }
+        xCourant = MARGE_DEBUT_LIGNE+LARGEUR_INTER_CHAINONS;
+        yCourant += HAUTEUR_LIGNES;
+        positionligne = -1;
+      }
+      positionligne = positionligne + 1;
+    }
+    exporter = new JButton("exporter en SVG");
+    exporter.setAction(new GAction("exporter en SVG") {
+        public void executer() {
+          exporterEnSvg();
+        }
+      });
+    add(exporter);
+    exporter.setLocation(100, yCourant +2*HAUTEUR_LIGNES);
+    exporter.setSize(150, 40);
+    exporter.setVisible(true);
+    
+    setPreferredSize(new Dimension(xmaxligne+30, yCourant+3*HAUTEUR_LIGNES+30));
+  }
+  void setCouleurs(Color[] couleurs) {//on affecte la couleur 
+    this.couleurs = couleurs;
+    colorer();
+  }
+  void setTaille(int[] tailles) {//on affecte la couleur 
+    this.taille = tailles;
+    Reduire();
+  }
+    void setForme(int[] formes) {//on affecte la couleur 
+    this.forme = formes;
+    Former();
+  }
+    void setSurTexte(String[] SurTexte) {//on affecte la couleur 
+    this.SurTexte = SurTexte;
+    SurTitrer();
+  }
+    void setSousTexte(String[] SousTexte) {//on affecte la couleur 
+    this.SousTexte = SousTexte;
+    SousTitrer();
+  }
+    
+    
+  private void colorer() {//on colore les chainons
+      boolean taillenoninitialisee=false;
+      boolean formenoninitialisee=false;
+      boolean SurTextenoninitialisee=false;
+      boolean SousTextenoninitialisee=false;
+        if(couleurs.length != taille.length){ 
+//dans le cas ou on n'a pas encore défini la tailleb et la forme des chainons
+            this.taille = new int[gChainons.length];
+            taillenoninitialisee = true;
+        }
+        if(couleurs.length != forme.length){
+            this.forme = new int[gChainons.length];
+            formenoninitialisee = true;
+        }
+        if(couleurs.length != SurTexte.length){
+            this.SurTexte = new String[gChainons.length];
+            SurTextenoninitialisee = true;
+        }
+        if(couleurs.length != SousTexte.length){
+            this.SousTexte = new String[gChainons.length];
+            SousTextenoninitialisee = true;
+        }
+    for (int i = 0; i<gChainons.length; i++) {
+        if(taillenoninitialisee){
+            this.taille[i] = 1;  
+        }
+        if(formenoninitialisee){
+            this.forme[i] = 0;          
+        }
+        if(SurTextenoninitialisee){
+            this.SurTexte[i] = "";          
+        }
+        if(SousTextenoninitialisee){
+            this.SousTexte[i] = "";          
+        }
+        gChainons[i].changerCouleur(couleurs[i],this.taille[i],this.forme[i]);
+        if(permettreSousTexte){
+            gNoChainon[i].setText(this.SurTexte[i]);
+            gNoSousChainon[i].setText(this.SousTexte[i]);
+        }
+        
+    }
+    if(exporter!=null){
+        exporter.setVisible(true);
+    }
+    revalidate();
+    repaint();
+  }
+
+  private void Reduire() {//on reduit les chainons
+      boolean couleurnoninitialisee=false;
+      boolean formenoninitialisee=false;
+      boolean SurTextenoninitialisee=false;
+      boolean SousTextenoninitialisee=false;
+        if(taille.length != couleurs.length){ 
+            this.couleurs = new Color[gChainons.length];
+            couleurnoninitialisee = true;
+        }
+        if(taille.length != forme.length){
+            this.forme = new int[gChainons.length];
+            formenoninitialisee = true;
+        }
+        if(taille.length != SurTexte.length){
+            this.SurTexte = new String[gChainons.length];
+            SurTextenoninitialisee = true;
+        }
+        if(taille.length != SousTexte.length){
+            this.SousTexte = new String[gChainons.length];
+            SousTextenoninitialisee = true;
+        }
+    for (int i = 0; i<gChainons.length; i++) {
+        if(couleurnoninitialisee){
+            this.couleurs[i] = Color.WHITE;  
+        }
+        if(formenoninitialisee){
+            this.forme[i] = 0;          
+        }
+        if(SurTextenoninitialisee){
+            this.SurTexte[i] = "";          
+        }
+        if(SousTextenoninitialisee){
+            this.SousTexte[i] = "";          
+        }
+        gChainons[i].changerCouleur(this.couleurs[i],taille[i],this.forme[i]);
+        if(permettreSousTexte){
+            gNoChainon[i].setText(this.SurTexte[i]);
+            gNoSousChainon[i].setText(this.SousTexte[i]);
+        }
+    }
+    if(exporter!=null){
+        exporter.setVisible(true);
+    }
+    revalidate();
+    repaint();
+  }
+  
+  private void Former() {//on change la forme des chainons
+      boolean couleurnoninitialisee=false;
+      boolean taillenoninitialisee=false;
+      boolean SurTextenoninitialisee=false;
+      boolean SousTextenoninitialisee=false;
+        if(forme.length != couleurs.length){ 
+            this.couleurs = new Color[gChainons.length];
+            couleurnoninitialisee = true;
+        }
+        if(forme.length != taille.length){
+            this.taille = new int[gChainons.length];
+            taillenoninitialisee = true;
+        }
+        if(forme.length != SurTexte.length){
+            this.SurTexte = new String[gChainons.length];
+            SurTextenoninitialisee = true;
+        }
+        if(forme.length != SousTexte.length){
+            this.SousTexte = new String[gChainons.length];
+            SousTextenoninitialisee = true;
+        }
+    for (int i = 0; i<gChainons.length; i++) {
+        if(couleurnoninitialisee){
+            this.couleurs[i] = Color.WHITE;  
+        }
+        if(taillenoninitialisee){
+            this.taille[i] = 1;          
+        }
+        if(SurTextenoninitialisee){
+            this.SurTexte[i] = "";          
+        }
+        if(SousTextenoninitialisee){
+            this.SousTexte[i] = "";          
+        }
+        gChainons[i].changerCouleur(this.couleurs[i],this.taille[i],this.forme[i]);
+        if(permettreSousTexte){
+            gNoChainon[i].setText(this.SurTexte[i]);
+            gNoSousChainon[i].setText(this.SousTexte[i]);
+        }
+    }
+    if(exporter!=null){
+        exporter.setVisible(true);
+    }
+    revalidate();
+    repaint();
+  }
+  private void SurTitrer() {//on change le texte au dessus des chainons
+      boolean couleurnoninitialisee=false;
+      boolean taillenoninitialisee=false;
+      boolean Formenoninitialisee=false;
+      boolean SousTextenoninitialisee=false;
+        if(SurTexte.length != couleurs.length){ 
+            this.couleurs = new Color[gChainons.length];
+            couleurnoninitialisee = true;
+        }
+        if(SurTexte.length != taille.length){
+            this.taille = new int[gChainons.length];
+            taillenoninitialisee = true;
+        }
+        if(SurTexte.length != forme.length){
+            this.forme = new int[gChainons.length];
+            Formenoninitialisee = true;
+        }
+        if(SurTexte.length != SousTexte.length){
+            this.SousTexte = new String[gChainons.length];
+            SousTextenoninitialisee = true;
+        }
+    for (int i = 0; i<gChainons.length; i++) {
+        if(couleurnoninitialisee){
+            this.couleurs[i] = Color.WHITE;  
+        }
+        if(taillenoninitialisee){
+            this.taille[i] = 1;          
+        }
+        if(Formenoninitialisee){
+            this.forme[i] = 0;          
+        }
+        if(SousTextenoninitialisee){
+            this.SousTexte[i] = "";          
+        }
+        gChainons[i].changerCouleur(this.couleurs[i],this.taille[i],this.forme[i]);
+        if(permettreSousTexte){
+            gNoChainon[i].setText(this.SurTexte[i]);
+            gNoSousChainon[i].setText(this.SousTexte[i]);
+        }
+    }
+    if(exporter!=null){
+        exporter.setVisible(true);
+    }
+    revalidate();
+    repaint();
+  } 
+  
+  private void SousTitrer() {//on change le texte au dessus des chainons
+      boolean couleurnoninitialisee=false;
+      boolean taillenoninitialisee=false;
+      boolean Formenoninitialisee=false;
+      boolean SurTextenoninitialisee=false;
+        if(SousTexte.length != couleurs.length){ 
+            this.couleurs = new Color[gChainons.length];
+            couleurnoninitialisee = true;
+        }
+        if(SousTexte.length != taille.length){
+            this.taille = new int[gChainons.length];
+            taillenoninitialisee = true;
+        }
+        if(SousTexte.length != forme.length){
+            this.forme = new int[gChainons.length];
+            Formenoninitialisee = true;
+        }
+        if(SousTexte.length != SurTexte.length){
+            this.SurTexte = new String[gChainons.length];
+            SurTextenoninitialisee = true;
+        }
+    for (int i = 0; i<gChainons.length; i++) {
+        if(couleurnoninitialisee){
+            this.couleurs[i] = Color.WHITE;  
+        }
+        if(taillenoninitialisee){
+            this.taille[i] = 1;          
+        }
+        if(Formenoninitialisee){
+            this.forme[i] = 0;          
+        }
+        if(SurTextenoninitialisee){
+            this.SurTexte[i] = "";          
+        }
+        gChainons[i].changerCouleur(this.couleurs[i],this.taille[i],this.forme[i]);
+        if(permettreSousTexte){
+            gNoChainon[i].setText(this.SurTexte[i]);
+            gNoSousChainon[i].setText(this.SousTexte[i]);
+        }
+    }
+    if(exporter!=null){
+        exporter.setVisible(true);
+    }
+    revalidate();
+    repaint();
+  }  
+
+  private void effacerTout() {//on efface tous les chainons
+    removeAll();
+    gChainons = new GChainon[0];
+    gSegments.clear();
+    repaint();
+  }
+  private void effacer(Graphics graphics) {//on efface le graphique 
+    graphics.setColor(Color.WHITE);
+    graphics.fillRect(0, 0, getWidth(), getHeight());
+  }
+  @Override
+  protected void paintComponent(Graphics graphics) {//a voir
+    effacer(graphics);
+    for (GSegment gs : gSegments) gs.dessinerTraits(graphics);
+  }
+  public void autoriserSousTexte(boolean permettresoustexte){
+      this.permettreSousTexte = permettresoustexte;
+  } 
+  public static String ecrireSVGIcon(GChainon icone){
+      String balise ="";
+      int x = icone.getX() + icone.getWidth()/2 - icone.getIcon().getIconWidth()/2;
+      int y = icone.getY()+ icone.getHeight()/2 - icone.getIcon().getIconHeight()/2;
+      if(icone.getIcon().getClass()== DisqueCouleurIcone.class){
+          DisqueCouleurIcone figure = (DisqueCouleurIcone) icone.getIcon();
+          balise="<ellipse cx=\""+(x + figure.getMarge() + figure.getRayon()
+                  )+"\" cy=\""+(y + figure.getMarge() + figure.getRayon()
+                  )+"\" rx=\""+ figure.getRayon()+"\" ry=\""+ figure.getRayon()+"\" "
+                  + "style=\" fill:rgb("+figure.getColor().getRed()+","+figure.getColor().getGreen()
+                  +","+figure.getColor().getBlue()+"); stroke:black\"/>"+System.getProperty("line.separator");
+      }
+      if(icone.getIcon().getClass()== CarreCouleurIcone.class){
+          CarreCouleurIcone figure = (CarreCouleurIcone) icone.getIcon();
+          balise="<rect x=\""+(x + figure.getMarge()) +
+                  "\" y=\""+(y + figure.getMarge())+"\" width=\""+figure.getRayon()*2+"\" height=\""
+                  +figure.getRayon()*2+"\" "+"style=\" fill:rgb("+figure.getColor().getRed()+
+                  ","+figure.getColor().getGreen()+","+figure.getColor().getBlue()+"); stroke:black\"/>"
+                  +System.getProperty("line.separator");
+      }      
+      if(icone.getIcon().getClass()== TriangleCouleurIcone.class){
+          TriangleCouleurIcone figure = (TriangleCouleurIcone) icone.getIcon();
+          balise="<polygon points=\"";
+          balise = balise + (x + figure.getMarge()) + "," 
+                  + (y + figure.getMarge()+ 2 * figure.getRayon());
+          balise = balise + " " + (x + figure.getMarge() + figure.getRayon()) + "," 
+                  + (y + figure.getMarge());
+          balise = balise + " " + (x + figure.getMarge() + 2 *figure.getRayon()) + "," 
+                  + (y + figure.getMarge()+ 2 * figure.getRayon());
+          balise = balise + "\" "+"style=\" fill:rgb("+figure.getColor().getRed()+
+                  ","+figure.getColor().getGreen()+","+figure.getColor().getBlue()+"); stroke:black\"/>"
+                  +System.getProperty("line.separator");
+      }       
+      if(icone.getIcon().getClass()== CroixCouleurIcone.class){
+          CroixCouleurIcone figure = (CroixCouleurIcone) icone.getIcon();
+          balise="<polygon points=\"";
+          balise = balise + (x + figure.getMarge()) + "," 
+                  + (y + figure.getMarge()+figure.getRayon()-1);
+          balise = balise + " " + (x + figure.getMarge() + figure.getRayon() - 1) + "," 
+                  + (y + figure.getMarge()+figure.getRayon()-1);
+          balise = balise + " " + (x + figure.getMarge() + figure.getRayon() - 1) + "," 
+                  + (y + figure.getMarge());
+          balise = balise + " " + (x + figure.getMarge() + figure.getRayon() + 1) + "," 
+                  + (y + figure.getMarge());
+          balise = balise + " " + (x + figure.getMarge() + figure.getRayon() + 1) + "," 
+                  + (y + figure.getMarge()+figure.getRayon()-1);
+          balise = balise + " " + (x + figure.getMarge() + 2 *figure.getRayon()) + "," 
+                  + (y + figure.getMarge()+figure.getRayon()-1);
+          balise = balise + " " + (x + figure.getMarge() + 2* figure.getRayon()) + "," 
+                  + (y + figure.getMarge()+figure.getRayon()+1);
+          balise = balise + " " + (x + figure.getMarge() + figure.getRayon() + 1) + "," 
+                  + (y + figure.getMarge()+figure.getRayon()+1);
+          balise = balise + " " + (x + figure.getMarge() + figure.getRayon() + 1) + "," 
+                  + (y + figure.getMarge()+ 2 * figure.getRayon());
+          balise = balise + " " + (x + figure.getMarge() + figure.getRayon() - 1) + "," 
+                  + (y + figure.getMarge()+2*figure.getRayon());
+          balise = balise + " " + (x + figure.getMarge() + figure.getRayon() - 1) + "," 
+                  + (y + figure.getMarge()+figure.getRayon()+1);
+          balise = balise + " " + (x + figure.getMarge()) + "," 
+                  + (y + figure.getMarge()+figure.getRayon()+1);
+          balise = balise + "\" "+"style=\" fill:rgb("+figure.getColor().getRed()+
+                  ","+figure.getColor().getGreen()+","+figure.getColor().getBlue()+"); stroke:black\"/>"
+                  +System.getProperty("line.separator");
+      }        
+      if(icone.getIcon().getClass()== TriangleinverseCouleurIcone.class){
+          TriangleinverseCouleurIcone figure = (TriangleinverseCouleurIcone) icone.getIcon();
+          balise="<polygon points=\"";
+          balise = balise + (x + figure.getMarge()) + "," 
+                  + (y + figure.getMarge());
+          balise = balise + " " + (x + figure.getMarge() + 2*figure.getRayon()) + "," 
+                  + (y + figure.getMarge());
+          balise = balise + " " + (x + figure.getMarge() + figure.getRayon()) + "," 
+                  + (y + figure.getMarge()+ 2 * figure.getRayon());
+          balise = balise + "\" "+"style=\" fill:rgb("+figure.getColor().getRed()+
+                  ","+figure.getColor().getGreen()+","+figure.getColor().getBlue()+"); stroke:black\"/>"
+                  +System.getProperty("line.separator");
+      }        
+      return balise;
+  }
+  
+  public static String ecrireSVGGsegment(GSegment seg){
+      String balise = "";
+      switch (seg.type) {
+        case COMPLET:
+            balise = balise + "<line x1=\""+seg.xmin+"\" y1=\""+seg.ybas+"\" x2=\""+seg.xmin+"\" y2=\""+seg.yhaut
+                    +"\" style=\" fill:black; stroke:black\"/>"+System.getProperty("line.separator");
+            balise = balise + "<line x1=\""+seg.xmin+"\" y1=\""+seg.yhaut+"\" x2=\""+seg.xmax+"\" y2=\""+seg.yhaut
+                    +"\" style=\" fill:black; stroke:black\"/>"+System.getProperty("line.separator");
+            balise = balise + "<line x1=\""+seg.xmax+"\" y1=\""+seg.yhaut+"\" x2=\""+seg.xmax+"\" y2=\""+seg.ybas
+                    +"\" style=\" fill:black; stroke:black\"/>"+System.getProperty("line.separator");
+          break;
+        case DEBUT:
+            balise = balise + "<line x1=\""+seg.xmin+"\" y1=\""+seg.ybas+"\" x2=\""+seg.xmin+"\" y2=\""+seg.yhaut
+                    +"\" style=\" fill:black; stroke:black\"/>"+System.getProperty("line.separator");
+            balise = balise + "<line x1=\""+seg.xmin+"\" y1=\""+seg.yhaut+"\" x2=\""+seg.xmax+"\" y2=\""+seg.yhaut
+                    +"\" style=\" fill:black; stroke:black\"/>"+System.getProperty("line.separator");
+          break;
+        case FIN:
+            balise = balise + "<line x1=\""+seg.xmin+"\" y1=\""+seg.yhaut+"\" x2=\""+seg.xmax+"\" y2=\""+seg.yhaut
+                    +"\" style=\" fill:black; stroke:black\"/>"+System.getProperty("line.separator");
+            balise = balise + "<line x1=\""+seg.xmax+"\" y1=\""+seg.yhaut+"\" x2=\""+seg.xmax+"\" y2=\""+seg.ybas
+                    +"\" style=\" fill:black; stroke:black\"/>"+System.getProperty("line.separator");
+          break;
+        case MILIEU:
+            balise = balise + "<line x1=\""+seg.xmin+"\" y1=\""+seg.yhaut+"\" x2=\""+seg.xmax+"\" y2=\""+seg.yhaut
+                    +"\" style=\" fill:black; stroke:black\"/>"+System.getProperty("line.separator");
+          break;
+      }
+      balise = balise + "<text x=\""+seg.getX()+"\" y=\""+(seg.getY() + seg.getHeight() - 4)+"\" "
+              + "style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+seg.getText()+"</text>"
+              +System.getProperty("line.separator");
+      return balise;
+  }
+  
+  public static String ecrireSVGSurTexte(GNoChainon sur){
+      String balise = "<text x=\""+sur.getX()+"\" y=\""+(sur.getY() + sur.getHeight())+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+sur.getText()+
+              "</text>"+System.getProperty("line.separator");
+      return balise;
+  }  
+  public static String ecrireSVGSousTexte(GNoSousChainon sous){
+      String balise = "<text x=\""+sous.getX()+"\" y=\""+(sous.getY() + sous.getHeight())+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+sous.getText()+
+              "</text>"+System.getProperty("line.separator");
+      return balise;
+  }
+  public static String ecrireSVGLegende (JTable legende,int posx, int posy){
+      String balise = "";
+      int x = posx;
+      int y = posy;
+      Object cellule;
+      for(int i = 0 ; i < legende.getRowCount();i++){
+          cellule = legende.getValueAt(i, 0)!=null ? legende.getValueAt(i, 0) : "99";
+          if(cellule.getClass()!=String.class){
+            y = y + (legende.getRowHeight(i) - ((Icon) cellule).getIconHeight())/2;
+          }
+          if(cellule.getClass()== DisqueCouleurIcone.class){
+              DisqueCouleurIcone figure = (DisqueCouleurIcone) cellule;
+              if(figure.getColor()!=null){
+              balise= balise + "<ellipse cx=\""+(x + figure.getMarge() + figure.getRayon()
+                      )+"\" cy=\""+(y + figure.getMarge() + figure.getRayon()
+                      )+"\" rx=\""+ figure.getRayon()+"\" ry=\""+ figure.getRayon()+"\" "
+                      + "style=\" fill:rgb("+figure.getColor().getRed()+","+figure.getColor().getGreen()
+                      +","+figure.getColor().getBlue()+"); stroke:black\"/>"+System.getProperty("line.separator");
+              }
+              else{
+              balise = balise + "<text x=\""+x+"\" y=\""+(y + (policeTailleSVG + legende.getRowHeight(i))/2
+                      - (legende.getRowHeight(i) - ((Icon) cellule).getIconHeight())/2)+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+"X"+
+              "</text>"+System.getProperty("line.separator");
+              }
+          }
+          if(cellule.getClass()== CarreCouleurIcone.class){
+              CarreCouleurIcone figure = (CarreCouleurIcone) cellule;
+              if(figure.getColor()!=null){
+              balise= balise + "<rect x=\""+(x + figure.getMarge()) +
+                      "\" y=\""+(y + figure.getMarge())+"\" width=\""+figure.getRayon()*2+"\" height=\""
+                      +figure.getRayon()*2+"\" "+"style=\" fill:rgb("+figure.getColor().getRed()+
+                      ","+figure.getColor().getGreen()+","+figure.getColor().getBlue()+"); stroke:black\"/>"
+                      +System.getProperty("line.separator");
+              }
+              else{
+              balise = balise + "<text x=\""+x+"\" y=\""+(y + (policeTailleSVG + legende.getRowHeight(i))/2
+                      - (legende.getRowHeight(i) - ((Icon) cellule).getIconHeight())/2)+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+"X"+
+              "</text>"+System.getProperty("line.separator");
+              }
+              
+          }      
+          if(cellule.getClass()== TriangleCouleurIcone.class){
+              TriangleCouleurIcone figure = (TriangleCouleurIcone) cellule;
+              if(figure.getColor()!=null){
+              balise= balise + "<polygon points=\"";
+              balise = balise + (x + figure.getMarge()) + "," 
+                      + (y + figure.getMarge()+ 2 * figure.getRayon());
+              balise = balise + " " + (x + figure.getMarge() + figure.getRayon()) + "," 
+                      + (y + figure.getMarge());
+              balise = balise + " " + (x + figure.getMarge() + 2 *figure.getRayon()) + "," 
+                      + (y + figure.getMarge()+ 2 * figure.getRayon());
+              balise = balise + "\" "+"style=\" fill:rgb("+figure.getColor().getRed()+
+                      ","+figure.getColor().getGreen()+","+figure.getColor().getBlue()+"); stroke:black\"/>"
+                      +System.getProperty("line.separator");
+              }
+              else{
+              balise = balise + "<text x=\""+x+"\" y=\""+(y + (policeTailleSVG + legende.getRowHeight(i))/2
+                      - (legende.getRowHeight(i) - ((Icon) cellule).getIconHeight())/2)+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+"X"+
+              "</text>"+System.getProperty("line.separator");
+              }
+          }       
+          if(cellule.getClass()== CroixCouleurIcone.class){
+              CroixCouleurIcone figure = (CroixCouleurIcone) cellule;
+              if(figure.getColor()!=null){
+              balise= balise + "<polygon points=\"";
+              balise = balise + (x + figure.getMarge()) + "," 
+                      + (y + figure.getMarge()+figure.getRayon()-1);
+              balise = balise + " " + (x + figure.getMarge() + figure.getRayon() - 1) + "," 
+                      + (y + figure.getMarge()+figure.getRayon()-1);
+              balise = balise + " " + (x + figure.getMarge() + figure.getRayon() - 1) + "," 
+                      + (y + figure.getMarge());
+              balise = balise + " " + (x + figure.getMarge() + figure.getRayon() + 1) + "," 
+                      + (y + figure.getMarge());
+              balise = balise + " " + (x + figure.getMarge() + figure.getRayon() + 1) + "," 
+                      + (y + figure.getMarge()+figure.getRayon()-1);
+              balise = balise + " " + (x + figure.getMarge() + 2 *figure.getRayon()) + "," 
+                      + (y + figure.getMarge()+figure.getRayon()-1);
+              balise = balise + " " + (x + figure.getMarge() + 2* figure.getRayon()) + "," 
+                      + (y + figure.getMarge()+figure.getRayon()+1);
+              balise = balise + " " + (x + figure.getMarge() + figure.getRayon() + 1) + "," 
+                      + (y + figure.getMarge()+figure.getRayon()+1);
+              balise = balise + " " + (x + figure.getMarge() + figure.getRayon() + 1) + "," 
+                      + (y + figure.getMarge()+ 2 * figure.getRayon());
+              balise = balise + " " + (x + figure.getMarge() + figure.getRayon() - 1) + "," 
+                      + (y + figure.getMarge()+2*figure.getRayon());
+              balise = balise + " " + (x + figure.getMarge() + figure.getRayon() - 1) + "," 
+                      + (y + figure.getMarge()+figure.getRayon()+1);
+              balise = balise + " " + (x + figure.getMarge()) + "," 
+                      + (y + figure.getMarge()+figure.getRayon()+1);
+              balise = balise + "\" "+"style=\" fill:rgb("+figure.getColor().getRed()+
+                      ","+figure.getColor().getGreen()+","+figure.getColor().getBlue()+"); stroke:black\"/>"
+                      +System.getProperty("line.separator");
+              }
+              else{
+              balise = balise + "<text x=\""+x+"\" y=\""+(y + (policeTailleSVG + legende.getRowHeight(i))/2
+                      - (legende.getRowHeight(i) - ((Icon) cellule).getIconHeight())/2)+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+"X"+
+              "</text>"+System.getProperty("line.separator");
+              }
+          }        
+          if(cellule.getClass()== TriangleinverseCouleurIcone.class){
+              TriangleinverseCouleurIcone figure = (TriangleinverseCouleurIcone) cellule;
+              if(figure.getColor()!=null){
+              balise= balise + "<polygon points=\"";
+              balise = balise + (x + figure.getMarge()) + "," 
+                      + (y + figure.getMarge());
+              balise = balise + " " + (x + figure.getMarge() + 2*figure.getRayon()) + "," 
+                      + (y + figure.getMarge());
+              balise = balise + " " + (x + figure.getMarge() + figure.getRayon()) + "," 
+                      + (y + figure.getMarge()+ 2 * figure.getRayon());
+              balise = balise + "\" "+"style=\" fill:rgb("+figure.getColor().getRed()+
+                      ","+figure.getColor().getGreen()+","+figure.getColor().getBlue()+"); stroke:black\"/>"
+                      +System.getProperty("line.separator");
+              }
+              else{
+              balise = balise + "<text x=\""+x+"\" y=\""+(y + (policeTailleSVG + legende.getRowHeight(i))/2
+                      - (legende.getRowHeight(i) - ((Icon) cellule).getIconHeight())/2)+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+"X"+
+              "</text>"+System.getProperty("line.separator");
+              }
+          }
+          if(cellule.getClass() == String.class){
+              String texte = cellule.toString();
+              balise = balise + "<text x=\""+x+"\" y=\""+(y + legende.getRowHeight(i))+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+texte+
+              "</text>"+System.getProperty("line.separator");
+          }
+          if(cellule.getClass()!=String.class){
+            y = y - (legende.getRowHeight(i) - ((Icon) cellule).getIconHeight())/2;
+          }
+          y = y + legende.getRowHeight(i);
+      }
+      x = x + legende.getColumnModel().getColumn(0).getWidth();
+      y = posy;
+      for(int i = 0 ; i < legende.getRowCount();i++){
+              String texte = legende.getValueAt(i, 1).toString();
+              //si le texte commence par une balise html comme pour la valeur <autre> on enlève les balises
+              if(texte.charAt(0)=='<'){
+                  texte=texte.substring(1, texte.length()-1);
+              }
+              balise = balise + "<text x=\""+x+"\" y=\""+(y + (policeTailleSVG+legende.getRowHeight(i))/2)+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+texte+
+              "</text>"+System.getProperty("line.separator");
+              y = y + legende.getRowHeight(i);
+      }
+      x = x + legende.getColumnModel().getColumn(1).getWidth();
+      y = posy;
+      for(int i = 0 ; i < legende.getRowCount();i++){
+              String texte = (legende.getValueAt(i, 2)==null ? "NC" : legende.getValueAt(i, 2).toString());
+              balise = balise + "<text x=\""+x+"\" y=\""+(y + (policeTailleSVG+legende.getRowHeight(i))/2)+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+texte+
+              "</text>"+System.getProperty("line.separator");
+              y = y + legende.getRowHeight(i);
+      }
+      return balise;
+  }  
+  
+  public void exporterEnSvg(){
+      String graphique = "";
+      String fin = "</svg>";
+      for(GChainon figure : this.gChainons){
+        graphique = graphique + ecrireSVGIcon(figure);
+      }
+      for(GSegment figure : this.gSegments){
+        graphique = graphique + ecrireSVGGsegment(figure);
+      }
+      for(GNoChainon figure : this.gNoChainon){
+        graphique = graphique + ecrireSVGSurTexte(figure);
+      }
+      if(this.gNoSousChainon!=null){
+        for(GNoSousChainon figure : this.gNoSousChainon){
+            graphique = graphique + ecrireSVGSousTexte(figure);
+        }
+      }
+      int x = 40;
+      int y = (int) Math.round(this.getPreferredSize().getHeight() + 30);
+      if(this.visu==null){
+          graphique = graphique + this.visucoref.getSelection(policeTailleSVG,x,y,policeSVG);
+          y =  y + policeTailleSVG * 7;//on laisse de la place pour le texte
+          y = y + 30;
+      }
+      else{
+          graphique = graphique + this.visu.getSelection(policeTailleSVG,x,y,policeSVG);
+          y =  y + policeTailleSVG * 10;//on laisse de la place pour le texte
+          y = y +30;
+      }
+      int ymax = y;
+      int xtot =  x;
+      if(visu==null){
+          graphique = graphique + "<text x=\""+x+"\" y=\""+(y + policeTailleSVG)+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+"Champ 1 :"+
+              "</text>"+System.getProperty("line.separator");
+          graphique = graphique + ecrireSVGLegende(visucoref.getLegende(),x,y+2*policeTailleSVG);
+          ymax = y + visucoref.getLegende().getHeight()+2*policeTailleSVG;
+          xtot = xtot + visucoref.getLegende().getWidth();
+      }
+      else{
+          graphique = graphique + "<text x=\""+x+"\" y=\""+(y + policeTailleSVG)+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+"Champ 1 :"+
+              "</text>"+System.getProperty("line.separator");
+          graphique = graphique + ecrireSVGLegende(visu.getLegende(0),x,y+2*policeTailleSVG);
+          x=x+visu.getLegende(0).getWidth() + 40;
+          if(y + visu.getLegende(0).getHeight()+2*policeTailleSVG>ymax){
+              ymax = y + visu.getLegende(0).getHeight()+2*policeTailleSVG;
+          }
+          xtot = xtot + visu.getLegende(0).getWidth();
+          graphique = graphique + "<text x=\""+x+"\" y=\""+(y + policeTailleSVG)+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+"Champ 2 :"+
+              "</text>"+System.getProperty("line.separator");
+          graphique = graphique + ecrireSVGLegende(visu.getLegende(1),x,y+2*policeTailleSVG);
+          x=x+visu.getLegende(1).getWidth() + 40;
+          if(y + visu.getLegende(1).getHeight()+2*policeTailleSVG>ymax){
+              ymax = y + visu.getLegende(1).getHeight()+2*policeTailleSVG;
+          }
+          xtot = xtot + visu.getLegende(1).getWidth();
+          graphique = graphique + "<text x=\""+x+"\" y=\""+(y + policeTailleSVG)+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+"Champ 3 :"+
+              "</text>"+System.getProperty("line.separator");
+          graphique = graphique + ecrireSVGLegende(visu.getLegende(2),x,y+2*policeTailleSVG);
+          x=x+visu.getLegende(2).getWidth() + 40;
+          if(y + visu.getLegende(2).getHeight()+2*policeTailleSVG>ymax){
+              ymax = y + visu.getLegende(2).getHeight()+2*policeTailleSVG;
+          }
+          xtot = xtot + visu.getLegende(2).getWidth();
+          x= 40;
+          y = ymax +20;
+          graphique = graphique + "<text x=\""+x+"\" y=\""+(y + policeTailleSVG)+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+"Champ 4 :"+
+              "</text>"+System.getProperty("line.separator");
+          graphique = graphique + ecrireSVGLegende(visu.getLegende(3),x,y+2*policeTailleSVG);
+          x=x+visu.getLegende(3).getWidth() + 40;
+          if(y + visu.getLegende(3).getHeight()+2*policeTailleSVG>ymax){
+              ymax = y + visu.getLegende(3).getHeight()+2*policeTailleSVG;
+          }
+          graphique = graphique + "<text x=\""+x+"\" y=\""+(y + policeTailleSVG)+"\""
+              + " style=\" fill:black; stroke:black ;font-size:"+policeTailleSVG+"px "+policeSVG+"\">"+"Champ 5 :"+
+              "</text>"+System.getProperty("line.separator");
+          graphique = graphique + ecrireSVGLegende(visu.getLegende(4),x,y+2*policeTailleSVG);
+          if(y + visu.getLegende(4).getHeight()+2*policeTailleSVG>ymax){
+              ymax = y + visu.getLegende(4).getHeight()+2*policeTailleSVG;
+          }
+          xtot = xtot + visu.getLegende(4).getWidth();
+      }
+      String debut = "<?xml version=\"1.0\" standalone=\"no\"?>" +System.getProperty("line.separator")
+             + "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">"
+                +System.getProperty("line.separator")+ 
+              "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\""+(Math.round(this.getPreferredSize().getWidth()) <
+              xtot ? xtot : Math.round(this.getPreferredSize().getWidth()))+"\" height=\""+(ymax+100)+"\">"+
+              System.getProperty("line.separator");
+      FichiersGraphique.exporterGChaineSVG(debut + graphique + fin);
+      
+      
+  }
+ 
+}
+ 
+ 

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/GChaines.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuChaines.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuChaines.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuChaines.java	(revision 3653)
@@ -0,0 +1,1575 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.chaines;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import org.jfree.chart.ChartPanel;
+import visuAnalec.*;
+import visuAnalec.elements.*;
+import visuAnalec.fichiers.FichiersJava;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.GAction;
+import visuAnalec.util.GVisu.LegendeLabel;
+import visuAnalec.util.GVisu.LegendeModeleTable;
+import visuAnalec.util.GVisu.LegendeModeleTableTexte;
+import visuAnalec.util.GVisu.TypeComboBox;
+import visuAnalec.util.GVisu.Val0ComboBox;
+import visuAnalec.vue.*;
+import visuAnalec.vue.Vue.VueListener;
+
+/**
+ *
+ * @author Bernard
+ */
+public class VisuChaines extends JFrame implements VueListener, ActionListener {
+	
+	private static final int[] seuilsValsNbElts = { 3, 10 };
+	
+	private static final Color[] couleursNbElts = { Color.WHITE, GVisu.getCouleurSansValeur(),
+			GVisu.getCouleur(0), GVisu.getCouleur(3), GVisu.getCouleur(1) };
+	
+	private static final int[] TaillesNbElts = { 1, 2, 3, 4, 4 };
+	
+	private static final int[] FormesNbElts = { 0, 1, 2, 3, 4 };
+	
+	private static final String[] TexteNbElts = { "00", "01", "02", "03", "04" };
+	
+	private final int colwidth = 50;
+	
+	private final int colheight = 30;
+	
+	private static final String[] labelsNbElements = {
+			"pas de chaîne associée",
+			"chaîne d'un seul chaînon",
+			"chaîne de 2-" + Integer.toString(seuilsValsNbElts[0]) + " chaînons",
+			"chaîne de " + Integer.toString(seuilsValsNbElts[0] + 1) + "-"
+					+ Integer.toString(seuilsValsNbElts[1]) + "  chaînons",
+			"chaîne de plus de " + Integer.toString(seuilsValsNbElts[1]) + " chaînons"
+	};
+	
+	private final Vue vue;
+	
+	private final ModeleChaines donneesChaines;
+	
+	private String typeChaines;
+	
+	private String typeUnites;
+	
+	private String[] valsAffichees;
+	
+	private String[] valsAffichees1;
+	
+	private String[] valsAffichees2;
+	
+	private String[] valsAffichees3;
+	
+	private String[] valsAffichees4;
+	
+	private HashMap<String, HashMap<String, String>> codeLegende = new HashMap();
+	
+	private final TypeComboBox saisieTypeChaines;
+	
+	private final TypeComboBox saisieTypeUnites;
+	
+	private Val0ComboBox saisieChampAffiche;
+	
+	private Val0ComboBox saisieChampAffiche1;
+	
+	private Val0ComboBox saisieChampAffiche2;
+	
+	private Val0ComboBox saisieChampAffiche3;
+	
+	private Val0ComboBox saisieChampAffiche4;
+	
+	private final JComboBox saisieTailleLigne;
+	
+	private ChartPanel histochaine;
+	
+	/* private JComboBox saisieTailleLigne; */
+	private JTable legendeChampAffiche;
+	
+	private LegendeModeleTable legendeChampAfficheModele;
+	
+	private JTable legendeChampAffiche1;
+	
+	private LegendeModeleTable legendeChampAfficheModele1;
+	
+	private JTable legendeChampAffiche2;
+	
+	private LegendeModeleTable legendeChampAfficheModele2;
+	
+	private JTable legendeChampAffiche3;
+	
+	private LegendeModeleTableTexte legendeChampAfficheModele3;
+	
+	private JTable legendeChampAffiche4;
+	
+	private LegendeModeleTableTexte legendeChampAfficheModele4;
+	
+	private JPopupMenu popupChamp = new JPopupMenu();
+	
+	private JPopupMenu popupChamp1 = new JPopupMenu();
+	
+	private JPopupMenu popupChamp2 = new JPopupMenu();
+	
+	private JPopupMenu popupChamp3 = new JPopupMenu();
+	
+	private JPopupMenu popupChamp4 = new JPopupMenu();
+	
+	private final GChaines panneauGraphique;// affichage graphique des chaines
+	
+	private final PanneauEditeur panneauEditeur;
+	
+	private final JCheckBox activeCouperParagraphe;
+	
+	private NgrammesPanel ngrammes;
+	
+	private final JSplitPane split2;
+	
+	private final JMenuBar menuBar = new JMenuBar();
+	
+	public VisuChaines(Container fenetre, Vue vue, PanneauEditeur pEditeur) {
+		super("Analyse des suites d'occurences");
+		Point pos = new Point(fenetre.getX() + 20, fenetre.getY() + 20);
+		Dimension dim = new Dimension(fenetre.getWidth(), fenetre.getHeight());
+		setLocation(pos);
+		setSize(dim);
+		this.vue = vue;
+		vue.addEventListener(this);
+		this.panneauEditeur = pEditeur;
+		saisieTypeChaines = new TypeComboBox(Schema.class);
+		saisieTypeChaines.setModele(vue.getTypesSchemasAVoir());
+		saisieTypeChaines.addActionListener(this);
+		saisieTypeUnites = new TypeComboBox(Unite.class);
+		saisieTypeUnites.setModele(vue.getTypesUnitesAVoir());
+		saisieTypeUnites.addActionListener(this);
+		saisieTailleLigne = new JComboBox(
+				new String[] { "<tous>", "10", "20", "30", "40", "50" });
+		saisieTailleLigne.setEditable(true);
+		saisieTailleLigne.setMaximumSize(getPreferredSize());
+		saisieTailleLigne.addActionListener(this);
+		saisieChampAffiche = new Val0ComboBox("Nombre de chaînons");
+		saisieChampAffiche.addActionListener(this);
+		saisieChampAffiche1 = new Val0ComboBox("Nombre de chaînons");
+		saisieChampAffiche1.addActionListener(this);
+		saisieChampAffiche2 = new Val0ComboBox("Nombre de chaînons");
+		saisieChampAffiche2.addActionListener(this);
+		saisieChampAffiche3 = new Val0ComboBox("Nombre de chaînons");
+		saisieChampAffiche3.addActionListener(this);
+		saisieChampAffiche4 = new Val0ComboBox("Nombre de chaînons");
+		saisieChampAffiche4.addActionListener(this);
+		// Panneau de présentation du graphique
+		JPanel pGraphique = new JPanel(new BorderLayout());
+		Box commandes = Box.createVerticalBox();
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Chaînes : "));
+		commandes.add(saisieTypeChaines);
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Unites : "));
+		commandes.add(saisieTypeUnites);
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Nb de chainons par ligne : "));
+		commandes.add(saisieTailleLigne);
+		commandes.add(Box.createVerticalGlue());
+		activeCouperParagraphe = new JCheckBox("Ne pas couper ls paragraphes");
+		commandes.add(activeCouperParagraphe);
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Champ à afficher : "));
+		commandes.add(saisieChampAffiche);
+		commandes.add(Box.createVerticalGlue());
+		
+		
+		legendeChampAfficheModele = new LegendeModeleTable();
+		legendeChampAffiche = new JTable(new Object[0][0], new String[] { "Icone", "Valeur de champ", "Fréquence" });
+		legendeChampAffiche.addMouseListener(new MouseAdapter() {
+			
+			@Override
+			public void mousePressed(MouseEvent e) {// on gère les évènements de la souris
+				check(e);
+			}
+			
+			@Override
+			public void mouseReleased(MouseEvent e) {
+				check(e);
+			}
+			
+			public void check(MouseEvent e) {
+				if (e.isPopupTrigger()) {// if the event shows the menu
+					popupChampInit(legendeChampAffiche.rowAtPoint(e.getPoint()), 0);
+					popupChamp.show(legendeChampAffiche, e.getX(), e.getY());
+				}
+			}
+		});
+		
+		commandes.add(legendeChampAffiche);
+		
+		
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Champ à afficher : "));
+		commandes.add(saisieChampAffiche1);
+		commandes.add(Box.createVerticalGlue());
+		
+		legendeChampAfficheModele1 = new LegendeModeleTable();
+		legendeChampAffiche1 = new JTable(legendeChampAfficheModele1);
+		legendeChampAffiche1.addMouseListener(new MouseAdapter() {
+			
+			@Override
+			public void mousePressed(MouseEvent e) {// on gère les évènements de la souris
+				check(e);
+			}
+			
+			@Override
+			public void mouseReleased(MouseEvent e) {
+				check(e);
+			}
+			
+			public void check(MouseEvent e) {
+				if (e.isPopupTrigger()) {// if the event shows the menu
+					popupChampInit(legendeChampAffiche1.rowAtPoint(e.getPoint()), 1);
+					popupChamp1.show(legendeChampAffiche1, e.getX(), e.getY());
+				}
+			}
+		});
+		
+		commandes.add(legendeChampAffiche1);
+		
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Champ à afficher : "));
+		commandes.add(saisieChampAffiche2);
+		commandes.add(Box.createVerticalGlue());
+		
+		legendeChampAfficheModele2 = new LegendeModeleTable();
+		legendeChampAffiche2 = new JTable(legendeChampAfficheModele2);
+		legendeChampAffiche2.addMouseListener(new MouseAdapter() {
+			
+			@Override
+			public void mousePressed(MouseEvent e) {// on gère les évènements de la souris
+				check(e);
+			}
+			
+			@Override
+			public void mouseReleased(MouseEvent e) {
+				check(e);
+			}
+			
+			public void check(MouseEvent e) {
+				if (e.isPopupTrigger()) {// if the event shows the menu
+					popupChampInit(legendeChampAffiche2.rowAtPoint(e.getPoint()), 2);
+					popupChamp2.show(legendeChampAffiche2, e.getX(), e.getY());
+				}
+			}
+		});
+		commandes.add(legendeChampAffiche2);
+		
+		
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Champ à afficher : "));
+		commandes.add(saisieChampAffiche3);
+		commandes.add(Box.createVerticalGlue());
+		
+		legendeChampAfficheModele3 = new LegendeModeleTableTexte();
+		legendeChampAffiche3 = new JTable(legendeChampAfficheModele3);
+		legendeChampAffiche3.addMouseListener(new MouseAdapter() {
+			
+			@Override
+			public void mousePressed(MouseEvent e) {// on gère les évènements de la souris
+				check(e);
+			}
+			
+			@Override
+			public void mouseReleased(MouseEvent e) {
+				check(e);
+			}
+			
+			public void check(MouseEvent e) {
+				if (e.isPopupTrigger()) {// if the event shows the menu
+					popupChampInit(legendeChampAffiche3.rowAtPoint(e.getPoint()), 3);
+					popupChamp3.show(legendeChampAffiche3, e.getX(), e.getY());
+				}
+			}
+		});
+		commandes.add(legendeChampAffiche3);
+		
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Champ à afficher : "));
+		commandes.add(saisieChampAffiche4);
+		commandes.add(Box.createVerticalGlue());
+		
+		legendeChampAfficheModele4 = new LegendeModeleTableTexte();
+		legendeChampAffiche4 = new JTable(legendeChampAfficheModele4);
+		legendeChampAffiche4.addMouseListener(new MouseAdapter() {
+			
+			@Override
+			public void mousePressed(MouseEvent e) {// on gère les évènements de la souris
+				check(e);
+			}
+			
+			@Override
+			public void mouseReleased(MouseEvent e) {
+				check(e);
+			}
+			
+			public void check(MouseEvent e) {
+				if (e.isPopupTrigger()) {// if the event shows the menu
+					popupChampInit(legendeChampAffiche4.rowAtPoint(e.getPoint()), 4);
+					popupChamp4.show(legendeChampAffiche4, e.getX(), e.getY());
+				}
+			}
+		});
+		commandes.add(legendeChampAffiche4);
+		JScrollPane scrollLegende = new JScrollPane(commandes);
+		
+		panneauGraphique = new GChaines(this);
+		panneauGraphique.autoriserSousTexte(true);
+		
+		donneesChaines = new ModeleChaines(vue, panneauGraphique);
+		JScrollPane scrollGraphique = new JScrollPane(panneauGraphique);
+		histochaine = Histogramme.histogrammeFactory();
+		this.ngrammes = new NgrammesPanel(vue);
+		JScrollPane scrollstatresultat = new JScrollPane(this.ngrammes);
+		JScrollPane scrollHistogramme = new JScrollPane(histochaine);
+		split2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollHistogramme, scrollstatresultat);
+		JSplitPane split3 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollGraphique, split2);
+		pGraphique.add(split3, BorderLayout.CENTER);
+		saisieTypeChaines.setAlignmentX(0);
+		saisieTypeUnites.setAlignmentX(0);
+		saisieTailleLigne.setAlignmentX(0);
+		saisieChampAffiche.setAlignmentX(0);
+		saisieChampAffiche1.setAlignmentX(0);
+		saisieChampAffiche2.setAlignmentX(0);
+		saisieChampAffiche3.setAlignmentX(0);
+		saisieChampAffiche4.setAlignmentX(0);
+		legendeChampAffiche.setAlignmentX(0);
+		legendeChampAffiche1.setAlignmentX(0);
+		legendeChampAffiche2.setAlignmentX(0);
+		legendeChampAffiche3.setAlignmentX(0);
+		legendeChampAffiche4.setAlignmentX(0);
+		
+		
+		
+		JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollLegende, pGraphique);
+		getContentPane().add(split);
+		setVisible(true);
+		split.setDividerLocation(1. / 3);
+		split2.setDividerLocation(1. / 2);
+		split3.setDividerLocation(1. / 3);
+		setJMenuBar(menuBar);
+		JMenu corpusMenu = new JMenu("Paramètres d'affichage");
+		menuBar.add(corpusMenu);
+		corpusMenu.add(new GAction("Reprendre un affichage") {
+			
+			@Override
+			public void executer() {
+				importerAffichage();
+			}
+		});
+		corpusMenu.add(new GAction("Sauver les paramètres d'affichage") {
+			
+			@Override
+			public void executer() {
+				exporterAffichage();
+			}
+		});
+		JMenu csvMenu = new JMenu("Exporter les données");
+		menuBar.add(csvMenu);
+		final VisuChaines visu = this;
+		final Vue vues = this.vue;
+		final PanneauEditeur pEditeurs = pEditeur;
+		csvMenu.add(new GAction("Exporter les données de filtrage") {
+			
+			@Override
+			public void executer() {
+				new ExportCSV(getContentPane(), vues, pEditeurs, visu);
+			}
+		});
+		csvMenu.add(new GAction("Exporter le tableau statistique") {
+			
+			@Override
+			public void executer() {
+				ExportCSV.exporterCSV(ngrammes.donneesCSV());
+			}
+		});
+		csvMenu.add(new GAction("Exporter les fréquences pour le champ1") {
+			
+			@Override
+			public void executer() {
+				Object[][] donneesCSV = new Object[legendeChampAffiche.getRowCount() + 1][2];
+				for (int i = 0; i < legendeChampAffiche.getRowCount(); i++) {
+					donneesCSV[i + 1][0] = legendeChampAffiche.getValueAt(i, 1);
+					donneesCSV[i + 1][1] = legendeChampAffiche.getValueAt(i, 2) == null ? "0"
+							: legendeChampAffiche.getValueAt(i, 2);
+				}
+				donneesCSV[0][1] = "frequence";
+				donneesCSV[0][0] = saisieChampAffiche.pasdeSelection() ? "Nombre de Chainons"
+						: saisieChampAffiche.getSelection();
+				ExportCSV.exporterCSV(donneesCSV);
+			}
+		});
+		csvMenu.add(new GAction("Exporter les fréquences pour le champ2") {
+			
+			@Override
+			public void executer() {
+				Object[][] donneesCSV = new Object[legendeChampAffiche1.getRowCount() + 1][2];
+				for (int i = 0; i < legendeChampAffiche1.getRowCount(); i++) {
+					donneesCSV[i + 1][0] = legendeChampAffiche1.getValueAt(i, 1);
+					donneesCSV[i + 1][1] = legendeChampAffiche1.getValueAt(i, 2) == null ? "0"
+							: legendeChampAffiche1.getValueAt(i, 2);
+				}
+				donneesCSV[0][1] = "frequence";
+				donneesCSV[0][0] = saisieChampAffiche1.pasdeSelection() ? "Nombre de Chainons"
+						: saisieChampAffiche1.getSelection();
+				ExportCSV.exporterCSV(donneesCSV);
+			}
+		});
+		csvMenu.add(new GAction("Exporter les fréquences pour le champ3") {
+			
+			@Override
+			public void executer() {
+				Object[][] donneesCSV = new Object[legendeChampAffiche2.getRowCount() + 1][2];
+				for (int i = 0; i < legendeChampAffiche2.getRowCount(); i++) {
+					donneesCSV[i + 1][0] = legendeChampAffiche2.getValueAt(i, 1);
+					donneesCSV[i + 1][1] = legendeChampAffiche2.getValueAt(i, 2) == null ? "0"
+							: legendeChampAffiche2.getValueAt(i, 2);
+				}
+				donneesCSV[0][1] = "frequence";
+				donneesCSV[0][0] = saisieChampAffiche2.pasdeSelection() ? "Nombre de Chainons"
+						: saisieChampAffiche2.getSelection();
+				ExportCSV.exporterCSV(donneesCSV);
+			}
+		});
+		csvMenu.add(new GAction("Exporter les fréquences pour le champ4") {
+			
+			@Override
+			public void executer() {
+				Object[][] donneesCSV = new Object[legendeChampAffiche3.getRowCount() + 1][2];
+				for (int i = 0; i < legendeChampAffiche3.getRowCount(); i++) {
+					donneesCSV[i + 1][0] = legendeChampAffiche3.getValueAt(i, 1);
+					donneesCSV[i + 1][1] = legendeChampAffiche3.getValueAt(i, 2) == null ? "0"
+							: legendeChampAffiche3.getValueAt(i, 2);
+				}
+				donneesCSV[0][1] = "frequence";
+				donneesCSV[0][0] = saisieChampAffiche3.pasdeSelection() ? "Nombre de Chainons"
+						: saisieChampAffiche3.getSelection();
+				ExportCSV.exporterCSV(donneesCSV);
+			}
+		});
+		csvMenu.add(new GAction("Exporter les fréquences pour le champ5") {
+			
+			@Override
+			public void executer() {
+				Object[][] donneesCSV = new Object[legendeChampAffiche4.getRowCount() + 1][2];
+				for (int i = 0; i < legendeChampAffiche4.getRowCount(); i++) {
+					donneesCSV[i + 1][0] = legendeChampAffiche4.getValueAt(i, 1);
+					donneesCSV[i + 1][1] = legendeChampAffiche4.getValueAt(i, 2) == null ? "0"
+							: legendeChampAffiche4.getValueAt(i, 2);
+				}
+				donneesCSV[0][1] = "frequence";
+				donneesCSV[0][0] = saisieChampAffiche4.pasdeSelection() ? "Nombre de Chainons"
+						: saisieChampAffiche4.getSelection();
+				ExportCSV.exporterCSV(donneesCSV);
+			}
+		});
+		
+		// Fermeture de la fenêtre
+		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+		addWindowListener(new WindowAdapter() {
+			
+			@Override
+			public void windowClosing(WindowEvent evt) {
+				fermerFenetre();
+			}
+		});
+		// Initialisation
+		saisieTailleLigne.removeActionListener(this);
+		saisieTailleLigne.setSelectedIndex(0);
+		saisieTailleLigne.addActionListener(this);
+		saisieTailleLigne.setMaximumSize(getPreferredSize());
+		if (saisieTypeChaines.nbItems() == 1) {
+			saisieTypeChaines.setSelection(0);
+			if (saisieTypeUnites.nbItems() == 1) saisieTypeUnites.setSelection(0);
+			else saisieTypeUnites.effSelection();
+		}
+		else {
+			saisieTypeChaines.effSelection();
+			saisieTypeUnites.effSelection();
+		}
+	}
+	
+	private void fermerFenetre() {
+		vue.removeEventListener(this);
+		dispose();
+	}
+	
+	@Override
+	public void traiterEvent(Message evt) { // très grossier : à améliorer
+		switch (evt.getType()) {
+			case CLEAR_CORPUS:
+				fermerFenetre();
+				return;
+			case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+				throw new UnsupportedOperationException("Fenêtre chaines présente lors d'un message NEW_CORPUS ???");
+			case MODIF_TEXTE:
+				fermerFenetre();
+				return;
+			case MODIF_VUE:
+				fermerFenetre();
+				return;
+			case MODIF_STRUCTURE:
+				fermerFenetre();
+				return;
+			case MODIF_ELEMENT:
+				// ElementEvent evtE = (ElementEvent) evt;
+				// if (evtE.getModif() != TypeModifElement.BORNES_UNITE) fermerFenetre();
+				fermerFenetre();
+				return;
+			case CORPUS_SAVED:
+				fermerFenetre();
+				return;
+			default:
+				throw new UnsupportedOperationException("Cas " + evt.getType() + " oublié dans un switch");
+		}
+	}
+	
+	@Override
+	public void actionPerformed(ActionEvent evt) {
+		try {
+			panneauGraphique.setcouperparagraphe(activeCouperParagraphe.isSelected());
+			if (evt.getSource().equals(saisieTypeChaines)
+					|| evt.getSource().equals(saisieTypeUnites)) {
+				if (saisieTypeChaines.pasdeSelection() || saisieTypeUnites.pasdeSelection()) {
+					initVide();
+					return;
+				}
+				try {
+					init();
+				}
+				catch (UnsupportedOperationException ex) {
+					GMessages.impossibiliteAction("Erreur de type : " + ex.getMessage());
+					initVide();
+					return;
+				}
+				return;
+			}
+			if (evt.getSource().equals(saisieChampAffiche)) {
+				if (!saisieTypeChaines.pasdeSelection() && !saisieTypeUnites.pasdeSelection()) {
+					if (saisieChampAffiche.pasdeSelection()) initCouleursNbElts();
+					else initCouleursChamp(saisieChampAffiche.getSelection());
+				}
+				return;
+			}
+			if (evt.getSource().equals(saisieChampAffiche1)) {
+				if (!saisieTypeChaines.pasdeSelection() && !saisieTypeUnites.pasdeSelection()) {
+					if (saisieChampAffiche1.pasdeSelection()) initFormesNbElts();
+					else initFormesChamp(saisieChampAffiche1.getSelection());
+				}
+				return;
+			}
+			if (evt.getSource().equals(saisieChampAffiche2)) {
+				if (!saisieTypeChaines.pasdeSelection() && !saisieTypeUnites.pasdeSelection()) {
+					if (saisieChampAffiche2.pasdeSelection()) initTaillesNbElts();
+					else initTaillesChamp(saisieChampAffiche2.getSelection());
+				}
+				return;
+			}
+			if (evt.getSource().equals(saisieChampAffiche3)) {
+				if (!saisieTypeChaines.pasdeSelection() && !saisieTypeUnites.pasdeSelection()) {
+					if (saisieChampAffiche3.pasdeSelection()) initSurTexteNbElts();
+					else initSurTexteChamp(saisieChampAffiche3.getSelection());
+				}
+				return;
+			}
+			if (evt.getSource().equals(saisieChampAffiche4)) {
+				if (!saisieTypeChaines.pasdeSelection() && !saisieTypeUnites.pasdeSelection()) {
+					if (saisieChampAffiche4.pasdeSelection()) initSousTexteNbElts();
+					else initSousTexteChamp(saisieChampAffiche4.getSelection());
+				}
+				return;
+			}
+			throw new UnsupportedOperationException("Evénement non prévu : " + evt.paramString());
+		}
+		catch (Throwable ex) {
+			GMessages.erreurFatale(ex);
+		}
+	}
+	
+	private void initVide() {
+		typeChaines = null;
+		typeUnites = null;
+		donneesChaines.initVide();
+		saisieChampAffiche.setModeleVide();
+		saisieChampAffiche1.setModeleVide();
+		saisieChampAffiche2.setModeleVide();
+		saisieChampAffiche3.setModeleVide();
+		saisieChampAffiche4.setModeleVide();
+		this.ngrammes.init();
+		legendeChampAfficheModele = new LegendeModeleTable(new String[] { "icone", "nom du champ", "frequence" }, new LegendeLabel[0], new HashMap());
+		legendeChampAffiche.setModel(legendeChampAfficheModele);
+		legendeChampAfficheModele1 = new LegendeModeleTable(new String[] { "icone", "nom du champ", "frequence" }, new LegendeLabel[0], new HashMap());
+		legendeChampAffiche1.setModel(legendeChampAfficheModele1);
+		legendeChampAfficheModele2 = new LegendeModeleTable(new String[] { "icone", "nom du champ", "frequence" }, new LegendeLabel[0], new HashMap());
+		legendeChampAffiche2.setModel(legendeChampAfficheModele2);
+		legendeChampAfficheModele3 = new LegendeModeleTableTexte(new String[] { "Symbole", "nom du champ", "frequence" }, new LegendeLabel[0], new HashMap());
+		legendeChampAffiche3.setModel(legendeChampAfficheModele3);
+		legendeChampAfficheModele4 = new LegendeModeleTableTexte(new String[] { "Symbole", "nom du champ", "frequence" }, new LegendeLabel[0], new HashMap());
+		legendeChampAffiche4.setModel(legendeChampAfficheModele4);
+	}
+	
+	private void init() throws UnsupportedOperationException {
+		typeChaines = saisieTypeChaines.getTypeSelection();
+		typeUnites = saisieTypeUnites.getTypeSelection();
+		donneesChaines.init(typeChaines, typeUnites, seuilsValsNbElts);
+		initCouleursNbElts();
+		initTaillesNbElts();
+		initFormesNbElts();
+		initSurTexteNbElts();
+		initSousTexteNbElts();
+		saisieChampAffiche.removeActionListener(this);
+		saisieChampAffiche.setModele(vue.getNomsChamps(Unite.class, typeUnites));
+		saisieChampAffiche.addActionListener(this);
+		saisieChampAffiche1.removeActionListener(this);
+		saisieChampAffiche1.setModele(vue.getNomsChamps(Unite.class, typeUnites));
+		saisieChampAffiche1.addActionListener(this);
+		saisieChampAffiche2.removeActionListener(this);
+		saisieChampAffiche2.setModele(vue.getNomsChamps(Unite.class, typeUnites));
+		saisieChampAffiche2.addActionListener(this);
+		saisieChampAffiche3.removeActionListener(this);
+		saisieChampAffiche3.setModele(vue.getNomsChamps(Unite.class, typeUnites));
+		saisieChampAffiche3.addActionListener(this);
+		saisieChampAffiche4.removeActionListener(this);
+		saisieChampAffiche4.setModele(vue.getNomsChamps(Unite.class, typeUnites));
+		saisieChampAffiche4.addActionListener(this);
+		Histogramme.updatePanel(histochaine, "Titre", donneesChaines, 10, Color.BLUE, 200,
+				"position de l'unité", "Fréquence d'unités", vue);
+		this.ngrammes.setDonneesChaines(donneesChaines);
+		this.ngrammes.setTypeChaines(typeChaines);
+		this.ngrammes.setTypeUnites(typeUnites);
+		this.ngrammes.update();
+		
+		
+		
+	}
+	
+	private void initCouleursNbElts() {
+		HashMap<String, Float> freq = donneesChaines.calculerfrequencenbelt(donneesChaines.getUnites(), typeUnites, labelsNbElements);
+		donneesChaines.setChampAfficheNbElts(couleursNbElts);
+		legendeChampAfficheModele = new LegendeModeleTable(new String[] { "icone", "nom du champ", "frequence" }, creerLegendesNbElements(), freq);
+		legendeChampAffiche.setModel(legendeChampAfficheModele);
+		legendeChampAffiche.getColumnModel().getColumn(0).setMaxWidth(colwidth);
+		legendeChampAffiche.getColumnModel().getColumn(2).setMaxWidth(colwidth);
+		legendeChampAffiche.setRowHeight(colheight);
+	}
+	
+	private void initTaillesNbElts() {
+		HashMap<String, Float> freq = donneesChaines.calculerfrequencenbelt(donneesChaines.getUnites(), typeUnites, labelsNbElements);
+		donneesChaines.setChampAfficheTailleNbElts(TaillesNbElts);
+		legendeChampAfficheModele2 = new LegendeModeleTable(new String[] { "icone", "nom du champ", "frequence" }, creerLegendesTailleNbElements(), freq);
+		Histogramme.updatePanel(histochaine, "Titre", donneesChaines, 10, Color.BLUE, 200,
+				"position de l'unité", "Fréquence d'unités", vue);
+		legendeChampAffiche2.setModel(legendeChampAfficheModele2);
+		legendeChampAffiche2.getColumnModel().getColumn(0).setMaxWidth(colwidth);
+		legendeChampAffiche2.getColumnModel().getColumn(2).setMaxWidth(colwidth);
+		legendeChampAffiche2.setRowHeight(colheight);
+	}
+	
+	private void initFormesNbElts() {
+		HashMap<String, Float> freq = donneesChaines.calculerfrequencenbelt(donneesChaines.getUnites(), typeUnites, labelsNbElements);
+		donneesChaines.setChampAfficheFormeNbElts(FormesNbElts);
+		legendeChampAfficheModele1 = new LegendeModeleTable(new String[] { "icone", "nom du champ", "frequence" }, creerLegendesFormeNbElements(), freq);
+		legendeChampAffiche1.setModel(legendeChampAfficheModele1);
+		legendeChampAffiche1.getColumnModel().getColumn(0).setMaxWidth(colwidth);
+		legendeChampAffiche1.getColumnModel().getColumn(2).setMaxWidth(colwidth);
+		legendeChampAffiche1.setRowHeight(colheight);
+	}
+	
+	private void initSurTexteNbElts() {
+		HashMap<String, Float> freq = donneesChaines.calculerfrequencenbelt(donneesChaines.getUnites(), typeUnites, labelsNbElements);
+		donneesChaines.setChampAfficheSurTexteNbElts(TexteNbElts);
+		legendeChampAfficheModele3 = new LegendeModeleTableTexte(new String[] { "symbole", "nom du champ", "frequence" }, creerLegendesSurTexteNbElements(), freq);
+		legendeChampAffiche3.setModel(legendeChampAfficheModele3);
+		legendeChampAffiche3.getColumnModel().getColumn(0).setMaxWidth(colwidth);
+		legendeChampAffiche3.getColumnModel().getColumn(2).setMaxWidth(colwidth);
+	}
+	
+	private void initSousTexteNbElts() {
+		HashMap<String, Float> freq = donneesChaines.calculerfrequencenbelt(donneesChaines.getUnites(), typeUnites, labelsNbElements);
+		donneesChaines.setChampAfficheSousTexteNbElts(TexteNbElts);
+		legendeChampAfficheModele4 = new LegendeModeleTableTexte(new String[] { "symbole", "nom du champ", "frequence" }, creerLegendesSousTexteNbElements(), freq);
+		legendeChampAffiche4.setModel(legendeChampAfficheModele4);
+		legendeChampAffiche4.getColumnModel().getColumn(0).setMaxWidth(colwidth);
+		legendeChampAffiche4.getColumnModel().getColumn(2).setMaxWidth(colwidth);
+	}
+	
+	private LegendeLabel[] creerLegendesNbElements() {
+		LegendeLabel[] legendes = new LegendeLabel[couleursNbElts.length];
+		for (int i = 0; i < legendes.length; i++)
+			legendes[i] = new LegendeLabel(labelsNbElements[i],
+					donneesChaines.isMasqueeValNbElements(i) ? null : couleursNbElts[i]);
+		return legendes;
+	}
+	
+	private LegendeLabel[] creerLegendesFormeNbElements() {
+		LegendeLabel[] legendes = new LegendeLabel[FormesNbElts.length];
+		for (int i = 0; i < legendes.length; i++)
+			legendes[i] = new LegendeLabel(labelsNbElements[i], Color.WHITE, 1, (donneesChaines.isMasqueeValNbElements(i) ? -1 : FormesNbElts[i]), 12, 2);
+		return legendes;
+	}
+	
+	private LegendeLabel[] creerLegendesTailleNbElements() {
+		LegendeLabel[] legendes = new LegendeLabel[TaillesNbElts.length];
+		for (int i = 0; i < legendes.length; i++)
+			legendes[i] = new LegendeLabel(labelsNbElements[i], Color.WHITE, donneesChaines.isMasqueeValNbElements(i) ? -1 : TaillesNbElts[i], 0, 12, 2);
+		return legendes;
+	}
+	
+	private LegendeLabel[] creerLegendesSurTexteNbElements() {
+		LegendeLabel[] legendes = new LegendeLabel[TexteNbElts.length];
+		for (int i = 0; i < legendes.length; i++)
+			legendes[i] = new LegendeLabel(labelsNbElements[i], donneesChaines.isMasqueeValNbElements(i) ? null : TexteNbElts[i]);
+		return legendes;
+	}
+	
+	private LegendeLabel[] creerLegendesSousTexteNbElements() {
+		LegendeLabel[] legendes = new LegendeLabel[TexteNbElts.length];
+		for (int i = 0; i < legendes.length; i++)
+			legendes[i] = new LegendeLabel(labelsNbElements[i], donneesChaines.isMasqueeValNbElements(i) ? null : TexteNbElts[i]);
+		return legendes;
+	}
+	
+	
+	private void initCouleursChamp(String champ) {
+		valsAffichees = vue.getValeursChamp(Unite.class, typeUnites, champ);
+		HashMap<String, Float> freq = ChaineUtil.calculerfrequencechamp(donneesChaines.getUnites(), typeUnites, champ, vue);
+		ChaineUtil.triFusionMap(valsAffichees, freq);
+		HashMap<String, Color> couleursValeursChamp = new HashMap<>();
+		for (int i = 0, nocolor = 0; i < valsAffichees.length; i++)
+			if (!donneesChaines.isMasqueeValChamp(champ, valsAffichees[i]))
+				couleursValeursChamp.put(valsAffichees[i], GVisu.getCouleur(nocolor++));
+		if (!donneesChaines.isMasqueeValNulleChamp(champ))
+			couleursValeursChamp.put("", GVisu.getCouleurSansValeur());
+		donneesChaines.setChampAffiche(champ, couleursValeursChamp);
+		legendeChampAfficheModele = new LegendeModeleTable(new String[] { "icone", "nom du champ", "frequence" }, creerLegendesChamp(valsAffichees,
+				couleursValeursChamp), freq);
+		legendeChampAffiche.setModel(legendeChampAfficheModele);
+		legendeChampAffiche.getColumnModel().getColumn(0).setMaxWidth(colwidth);
+		legendeChampAffiche.getColumnModel().getColumn(2).setMaxWidth(colwidth);
+		legendeChampAffiche.setRowHeight(colheight);
+	}
+	
+	private void initTaillesChamp(String champ) {
+		valsAffichees2 = vue.getValeursChamp(Unite.class, typeUnites, champ);
+		HashMap<String, Float> freq = ChaineUtil.calculerfrequencechamp(donneesChaines.getUnites(), typeUnites, champ, vue);
+		ChaineUtil.triFusionMap(valsAffichees2, freq);
+		HashMap<String, Integer> TaillesValeursChamp = new HashMap<>();
+		for (int i = 0, nocolor = 0; i < valsAffichees2.length; i++)
+			if (!donneesChaines.isMasqueeValChamp(champ, valsAffichees2[i]))
+				TaillesValeursChamp.put(valsAffichees2[i], GVisu.getTaille(nocolor++));
+		if (!donneesChaines.isMasqueeValNulleChamp(champ))
+			TaillesValeursChamp.put("", GVisu.getTailleSansValeur());
+		donneesChaines.setChampAfficheTaille(champ, TaillesValeursChamp);
+		legendeChampAfficheModele2 = new LegendeModeleTable(new String[] { "icone", "nom du champ", "frequence" }, creerLegendesChampTaille(valsAffichees2,
+				TaillesValeursChamp), freq);
+		Histogramme.updatePanel(histochaine, "Titre", donneesChaines, 10, Color.BLUE, 200,
+				"position de l'unité", "Fréquence d'unités", vue);
+		legendeChampAffiche2.setModel(legendeChampAfficheModele2);
+		legendeChampAffiche2.getColumnModel().getColumn(0).setMaxWidth(colwidth);
+		legendeChampAffiche2.getColumnModel().getColumn(2).setMaxWidth(colwidth);
+		legendeChampAffiche2.setRowHeight(colheight);
+	}
+	
+	private void initFormesChamp(String champ) {
+		valsAffichees1 = vue.getValeursChamp(Unite.class, typeUnites, champ);
+		HashMap<String, Float> freq = ChaineUtil.calculerfrequencechamp(donneesChaines.getUnites(), typeUnites, champ, vue);
+		ChaineUtil.triFusionMap(valsAffichees1, freq);
+		HashMap<String, Integer> FormesValeursChamp = new HashMap<>();
+		for (int i = 0, nocolor = 0; i < valsAffichees1.length; i++)
+			if (!donneesChaines.isMasqueeValChamp(champ, valsAffichees1[i]))
+				FormesValeursChamp.put(valsAffichees1[i], GVisu.getForme(nocolor++));
+		if (!donneesChaines.isMasqueeValNulleChamp(champ))
+			FormesValeursChamp.put("", GVisu.getFormeSansValeur());
+		donneesChaines.setChampAfficheForme(champ, FormesValeursChamp);
+		legendeChampAfficheModele1 = new LegendeModeleTable(new String[] { "icone", "nom du champ", "frequence" }, creerLegendesChampForme(valsAffichees1,
+				FormesValeursChamp), freq);
+		legendeChampAffiche1.setModel(legendeChampAfficheModele1);
+		legendeChampAffiche1.getColumnModel().getColumn(0).setMaxWidth(colwidth);
+		legendeChampAffiche1.getColumnModel().getColumn(2).setMaxWidth(colwidth);
+		legendeChampAffiche1.setRowHeight(colheight);
+	}
+	
+	private void initSurTexteChamp(String champ) {
+		valsAffichees3 = vue.getValeursChamp(Unite.class, typeUnites, champ);
+		HashMap<String, Float> freq = ChaineUtil.calculerfrequencechamp(donneesChaines.getUnites(), typeUnites, champ, vue);
+		ChaineUtil.triFusionMap(valsAffichees3, freq);
+		HashMap<String, String> SurTexteValeursChamp = new HashMap<>();
+		for (int i = 0, nocolor = 0; i < valsAffichees3.length; i++)
+			if (!donneesChaines.isMasqueeValChamp(champ, valsAffichees3[i]))
+				SurTexteValeursChamp.put(valsAffichees3[i], codeLegende.containsKey(champ) &&
+						codeLegende.get(champ).containsKey(valsAffichees3[i]) ? codeLegende.get(champ).get(valsAffichees3[i])
+								: GVisu.getTexte(nocolor++));
+		if (!donneesChaines.isMasqueeValNulleChamp(champ))
+			SurTexteValeursChamp.put("", codeLegende.containsKey(champ) &&
+					codeLegende.get(champ).containsKey("") ? codeLegende.get(champ).get("")
+							: GVisu.getTexteSansValeur());
+		donneesChaines.setChampAfficheSurTexte(champ, SurTexteValeursChamp);
+		legendeChampAfficheModele3 = new LegendeModeleTableTexte(new String[] { "symbole", "nom du champ", "frequence" }, creerLegendesChampSurTexte(valsAffichees3,
+				SurTexteValeursChamp), freq);
+		legendeChampAffiche3.setModel(legendeChampAfficheModele3);
+		legendeChampAffiche3.getColumnModel().getColumn(0).setMaxWidth(colwidth);
+		legendeChampAffiche3.getColumnModel().getColumn(2).setMaxWidth(colwidth);
+	}
+	
+	private void initSousTexteChamp(String champ) {
+		valsAffichees4 = vue.getValeursChamp(Unite.class, typeUnites, champ);
+		HashMap<String, Float> freq = ChaineUtil.calculerfrequencechamp(donneesChaines.getUnites(), typeUnites, champ, vue);
+		ChaineUtil.triFusionMap(valsAffichees4, freq);
+		HashMap<String, String> SousTexteValeursChamp = new HashMap<>();
+		for (int i = 0, nocolor = 0; i < valsAffichees4.length; i++)
+			if (!donneesChaines.isMasqueeValChamp(champ, valsAffichees4[i]))
+				SousTexteValeursChamp.put(valsAffichees4[i], codeLegende.containsKey(champ) &&
+						codeLegende.get(champ).containsKey(valsAffichees4[i]) ? codeLegende.get(champ).get(valsAffichees4[i])
+								: GVisu.getTexte(nocolor++));
+		if (!donneesChaines.isMasqueeValNulleChamp(champ))
+			SousTexteValeursChamp.put("", codeLegende.containsKey(champ) &&
+					codeLegende.get(champ).containsKey("") ? codeLegende.get(champ).get("")
+							: GVisu.getTexteSansValeur());
+		donneesChaines.setChampAfficheSousTexte(champ, SousTexteValeursChamp);
+		legendeChampAfficheModele4 = new LegendeModeleTableTexte(new String[] { "symbole", "nom du champ", "frequence" }, creerLegendesChampSousTexte(valsAffichees4,
+				SousTexteValeursChamp), freq);
+		legendeChampAffiche4.setModel(legendeChampAfficheModele4);
+		legendeChampAffiche4.getColumnModel().getColumn(0).setMaxWidth(colwidth);
+		legendeChampAffiche4.getColumnModel().getColumn(2).setMaxWidth(colwidth);
+	}
+	
+	
+	private LegendeLabel[] creerLegendesChamp(String[] valsAffichees,
+			HashMap<String, Color> couleursValeursChamp) {
+		LegendeLabel[] legendes = new LegendeLabel[valsAffichees.length + 1];
+		for (int i = 0; i < valsAffichees.length; i++)
+			legendes[i] = new LegendeLabel(valsAffichees[i],
+					couleursValeursChamp.get(valsAffichees[i]));
+		legendes[valsAffichees.length] = new LegendeLabel("<aucune valeur>",
+				couleursValeursChamp.get(""));
+		return legendes;
+	}
+	
+	private LegendeLabel[] creerLegendesChampTaille(String[] valsAffichees,
+			HashMap<String, Integer> TaillesValeursChamp) {
+		LegendeLabel[] legendes = new LegendeLabel[valsAffichees.length + 1];
+		for (int i = 0; i < valsAffichees.length; i++)
+			legendes[i] = new LegendeLabel(valsAffichees[i], Color.WHITE,
+					donneesChaines.isMasqueeValChamp(saisieChampAffiche2.getSelection(),
+							valsAffichees[i]) ? -1 : (TaillesValeursChamp.get(valsAffichees[i])), 0, 12, 2);
+		legendes[valsAffichees.length] = new LegendeLabel("<aucune valeur>", Color.WHITE,
+				donneesChaines.isMasqueeValNulleChamp(saisieChampAffiche2.getSelection()) ? -1
+						: (TaillesValeursChamp.get("")), 0, 6, 2);
+		return legendes;
+	}
+	
+	private LegendeLabel[] creerLegendesChampForme(String[] valsAffichees,
+			HashMap<String, Integer> FormesValeursChamp) {
+		LegendeLabel[] legendes = new LegendeLabel[valsAffichees.length + 1];
+		for (int i = 0; i < valsAffichees.length; i++)
+			legendes[i] = new LegendeLabel(valsAffichees[i], Color.WHITE, 1,
+					donneesChaines.isMasqueeValChamp(saisieChampAffiche1.getSelection(),
+							valsAffichees[i]) ? -1 : (FormesValeursChamp.get(valsAffichees[i])), 12, 2);
+		legendes[valsAffichees.length] = new LegendeLabel("<aucune valeur>", Color.WHITE, 1,
+				donneesChaines.isMasqueeValNulleChamp(saisieChampAffiche1.getSelection()) ? -1
+						: (FormesValeursChamp.get("")), 12, 2);
+		return legendes;
+	}
+	
+	private LegendeLabel[] creerLegendesChampSurTexte(String[] valsAffichees,
+			HashMap<String, String> SurTexteValeursChamp) {
+		LegendeLabel[] legendes = new LegendeLabel[valsAffichees.length + 1];
+		for (int i = 0; i < valsAffichees.length; i++)
+			legendes[i] = new LegendeLabel(valsAffichees[i],
+					donneesChaines.isMasqueeValChamp(saisieChampAffiche3.getSelection(),
+							valsAffichees[i]) ? "" : (SurTexteValeursChamp.get(valsAffichees[i])));
+		legendes[valsAffichees.length] = new LegendeLabel("<aucune valeur>",
+				donneesChaines.isMasqueeValNulleChamp(saisieChampAffiche3.getSelection()) ? ""
+						: (SurTexteValeursChamp.get("")));
+		return legendes;
+	}
+	
+	private LegendeLabel[] creerLegendesChampSousTexte(String[] valsAffichees,
+			HashMap<String, String> SousTexteValeursChamp) {
+		LegendeLabel[] legendes = new LegendeLabel[valsAffichees.length + 1];
+		for (int i = 0; i < valsAffichees.length; i++)
+			legendes[i] = new LegendeLabel(valsAffichees[i],
+					donneesChaines.isMasqueeValChamp(saisieChampAffiche4.getSelection(),
+							valsAffichees[i]) ? "" : (SousTexteValeursChamp.get(valsAffichees[i])));
+		legendes[valsAffichees.length] = new LegendeLabel("<aucune valeur>",
+				donneesChaines.isMasqueeValNulleChamp(saisieChampAffiche4.getSelection()) ? ""
+						: (SousTexteValeursChamp.get("")));
+		return legendes;
+	}
+	
+	private void popupChampInit(final int index, final int champ) {
+		final boolean masquee;
+		String[] vals;
+		Val0ComboBox zonedesaisie;
+		JPopupMenu popup;
+		switch (champ) {
+			case 0:
+				vals = valsAffichees;
+				zonedesaisie = saisieChampAffiche;
+				popup = popupChamp;
+				break;
+			case 1:
+				vals = valsAffichees1;
+				zonedesaisie = saisieChampAffiche1;
+				popup = popupChamp1;
+				break;
+			case 2:
+				vals = valsAffichees2;
+				zonedesaisie = saisieChampAffiche2;
+				popup = popupChamp2;
+				break;
+			case 3:
+				vals = valsAffichees3;
+				zonedesaisie = saisieChampAffiche3;
+				popup = popupChamp3;
+				break;
+			case 4:
+				vals = valsAffichees4;
+				zonedesaisie = saisieChampAffiche4;
+				popup = popupChamp4;
+				break;
+			default:
+				vals = new String[0];
+				zonedesaisie = new Val0ComboBox("Nombre de chaînons");
+				popup = new JPopupMenu();
+				break;
+		}
+		popup.removeAll();
+		if (zonedesaisie.pasdeSelection()) {
+			masquee = donneesChaines.isMasqueeValNbElements(index);
+			popup.add(new GAction(masquee ? "Montrer cette valeur" : "Masquer cette valeur") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValNbElements(masquee, index, false, champ);
+				}
+			});
+			popup.add(new GAction(masquee ? "Montrer toutes les valeurs" : "Ne montrer que cette valeur") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValNbElements(masquee, index, true, champ);
+				}
+			});
+		}
+		else if (index == vals.length) {
+			masquee = donneesChaines.isMasqueeValNulleChamp(zonedesaisie.getSelection());
+			popup.add(new GAction(masquee ? "Montrer cette valeur" : "Masquer cette valeur") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValNulleChamp(masquee, false, champ);
+				}
+			});
+			popup.add(new GAction(masquee ? "Montrer toutes les valeurs" : "Ne montrer que cette valeur") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValNulleChamp(masquee, true, champ);
+				}
+			});
+			if (champ == 3 || champ == 4) {
+				popup.add(new GAction("Changer le code de la légende") {
+					
+					@Override
+					public void executer() {
+						changerCodeTexte(index, champ);
+					}
+				});
+			}
+		}
+		else {
+			masquee = donneesChaines.isMasqueeValChamp(zonedesaisie.getSelection(),
+					vals[index]);
+			popup.add(new GAction(masquee ? "Montrer cette valeur" : "Masquer cette valeur") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValChamp(masquee, index, false, champ);
+				}
+			});
+			popup.add(new GAction(masquee ? "Montrer toutes les valeurs" : "Ne montrer que cette valeur") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValChamp(masquee, index, true, champ);
+				}
+			});
+			if (champ == 3 || champ == 4) {
+				popup.add(new GAction("Changer le code de la légende") {
+					
+					@Override
+					public void executer() {
+						changerCodeTexte(index, champ);
+					}
+				});
+			}
+		}
+		
+	}
+	
+	// il doit y avoir une saisie pour saisieChampAffiche3 ou pour saisieChampAffiche4
+	private void changerCodeTexte(int index, int noLegende) {
+		JOptionPane saisieCode = new JOptionPane();
+		String ValAffichees;
+		Val0ComboBox saisiechampaffiche;
+		switch (noLegende) {
+			case 3:
+				saisiechampaffiche = saisieChampAffiche3;
+				ValAffichees = this.valsAffichees3[index];
+				break;
+			default:
+				saisiechampaffiche = saisieChampAffiche4;
+				ValAffichees = this.valsAffichees4[index];
+				break;
+		}
+		String code = saisieCode.showInputDialog(null, "Veuillez saisir un code légende d'au plus trois caractères",
+				"Changer le code", JOptionPane.QUESTION_MESSAGE);
+		if (code != null) {
+			code = code.length() > 3 ? code.substring(0, 2) : code;
+			if (!codeLegende.containsKey(saisiechampaffiche.getSelection())) {
+				codeLegende.put(saisiechampaffiche.getSelection(), new HashMap());
+			}
+			codeLegende.get(saisiechampaffiche.getSelection()).put(ValAffichees, code);
+			initSurTexteChamp(saisieChampAffiche3.getSelection());
+			initSousTexteChamp(saisieChampAffiche4.getSelection());
+		}
+	}
+	
+	private void modifierStatutValChamp(boolean masquee, int index, boolean tous, int source) {
+		String[] vals;
+		Val0ComboBox zonedesaisie;
+		switch (source) {
+			case 0:
+				vals = valsAffichees;
+				zonedesaisie = saisieChampAffiche;
+				break;
+			case 1:
+				vals = valsAffichees1;
+				zonedesaisie = saisieChampAffiche1;
+				break;
+			case 2:
+				vals = valsAffichees2;
+				zonedesaisie = saisieChampAffiche2;
+				break;
+			case 3:
+				vals = valsAffichees3;
+				zonedesaisie = saisieChampAffiche3;
+				break;
+			case 4:
+				vals = valsAffichees4;
+				zonedesaisie = saisieChampAffiche4;
+				break;
+			default:
+				vals = new String[0];
+				zonedesaisie = new Val0ComboBox("Nombre de chaînons");
+				break;
+		}
+		if (!tous) donneesChaines.masquerValChamp(!masquee,
+				zonedesaisie.getSelection(), vals[index]);
+		else if (masquee) donneesChaines.demasquerToutesValsChamp(
+				zonedesaisie.getSelection());
+		else donneesChaines.masquerAutresValsChamp(typeUnites,
+				zonedesaisie.getSelection(), vals[index]);
+		donneesChaines.modifMasqueVals(typeChaines, typeUnites);
+		if (saisieChampAffiche.pasdeSelection()) {
+			initCouleursNbElts();
+		}
+		else {
+			initCouleursChamp(saisieChampAffiche.getSelection());
+		}
+		if (saisieChampAffiche1.pasdeSelection()) {
+			initFormesNbElts();
+		}
+		else {
+			initFormesChamp(saisieChampAffiche1.getSelection());
+		}
+		if (saisieChampAffiche2.pasdeSelection()) {
+			initTaillesNbElts();
+		}
+		else {
+			initTaillesChamp(saisieChampAffiche2.getSelection());
+		}
+		if (saisieChampAffiche3.pasdeSelection()) {
+			initSurTexteNbElts();
+		}
+		else {
+			initSurTexteChamp(saisieChampAffiche3.getSelection());
+		}
+		if (saisieChampAffiche4.pasdeSelection()) {
+			initSousTexteNbElts();
+		}
+		else {
+			initSousTexteChamp(saisieChampAffiche4.getSelection());
+		}
+		
+		this.ngrammes.setDonneesChaines(donneesChaines);
+		this.ngrammes.setTypeChaines(typeChaines);
+		this.ngrammes.setTypeUnites(typeUnites);
+		this.ngrammes.update();
+	}
+	
+	private void modifierStatutValNulleChamp(boolean masquee, boolean tous, int source) {
+		Val0ComboBox zonedesaisie;
+		switch (source) {
+			case 0:
+				zonedesaisie = saisieChampAffiche;
+				break;
+			case 1:
+				zonedesaisie = saisieChampAffiche1;
+				break;
+			case 2:
+				zonedesaisie = saisieChampAffiche2;
+				break;
+			case 3:
+				zonedesaisie = saisieChampAffiche3;
+				break;
+			case 4:
+				zonedesaisie = saisieChampAffiche4;
+				break;
+			default:
+				zonedesaisie = new Val0ComboBox("Nombre de chaînons");
+				break;
+		}
+		if (!tous) donneesChaines.masquerValNulleChamp(!masquee, zonedesaisie.getSelection());
+		else if (masquee) donneesChaines.demasquerToutesValsChamp(
+				zonedesaisie.getSelection());
+		else donneesChaines.masquerValsNonNullesChamp(typeUnites,
+				zonedesaisie.getSelection());
+		donneesChaines.modifMasqueVals(typeChaines, typeUnites);
+		if (saisieChampAffiche.pasdeSelection()) {
+			initCouleursNbElts();
+		}
+		else {
+			initCouleursChamp(saisieChampAffiche.getSelection());
+		}
+		if (saisieChampAffiche1.pasdeSelection()) {
+			initFormesNbElts();
+		}
+		else {
+			initFormesChamp(saisieChampAffiche1.getSelection());
+		}
+		if (saisieChampAffiche2.pasdeSelection()) {
+			initTaillesNbElts();
+		}
+		else {
+			initTaillesChamp(saisieChampAffiche2.getSelection());
+		}
+		if (saisieChampAffiche3.pasdeSelection()) {
+			initSurTexteNbElts();
+		}
+		else {
+			initSurTexteChamp(saisieChampAffiche3.getSelection());
+		}
+		if (saisieChampAffiche4.pasdeSelection()) {
+			initSousTexteNbElts();
+		}
+		else {
+			initSousTexteChamp(saisieChampAffiche4.getSelection());
+		}
+		// initstat();
+		
+		this.ngrammes.setDonneesChaines(donneesChaines);
+		this.ngrammes.setTypeChaines(typeChaines);
+		this.ngrammes.setTypeUnites(typeUnites);
+		this.ngrammes.update();
+	}
+	
+	private void modifierStatutValNbElements(boolean masquee, int index, boolean tous, int source) {
+		Val0ComboBox zonedesaisie;
+		switch (source) {
+			case 0:
+				zonedesaisie = saisieChampAffiche;
+				break;
+			case 1:
+				zonedesaisie = saisieChampAffiche1;
+				break;
+			case 2:
+				zonedesaisie = saisieChampAffiche2;
+				break;
+			case 3:
+				zonedesaisie = saisieChampAffiche3;
+				break;
+			case 4:
+				zonedesaisie = saisieChampAffiche4;
+				break;
+			default:
+				zonedesaisie = new Val0ComboBox("Nombre de chaînons");
+				break;
+		}
+		if (!tous) donneesChaines.masquerValNbElements(!masquee, index);
+		else if (masquee) donneesChaines.demasquerToutesValsNbElts(
+				zonedesaisie.getSelection());
+		else donneesChaines.masquerAutresValsNbElts(
+				zonedesaisie.getSelection(), index);
+		donneesChaines.modifMasqueVals(typeChaines, typeUnites);
+		if (saisieChampAffiche.pasdeSelection()) {
+			initCouleursNbElts();
+		}
+		else {
+			initCouleursChamp(saisieChampAffiche.getSelection());
+		}
+		if (saisieChampAffiche1.pasdeSelection()) {
+			initFormesNbElts();
+		}
+		else {
+			initFormesChamp(saisieChampAffiche1.getSelection());
+		}
+		if (saisieChampAffiche2.pasdeSelection()) {
+			initTaillesNbElts();
+		}
+		else {
+			initTaillesChamp(saisieChampAffiche2.getSelection());
+		}
+		if (saisieChampAffiche3.pasdeSelection()) {
+			initSurTexteNbElts();
+		}
+		else {
+			initSurTexteChamp(saisieChampAffiche3.getSelection());
+		}
+		if (saisieChampAffiche4.pasdeSelection()) {
+			initSousTexteNbElts();
+		}
+		else {
+			initSousTexteChamp(saisieChampAffiche4.getSelection());
+		}
+		// initstat();
+		
+		this.ngrammes.setDonneesChaines(donneesChaines);
+		this.ngrammes.setTypeChaines(typeChaines);
+		this.ngrammes.setTypeUnites(typeUnites);
+		this.ngrammes.update();
+	}
+	
+	
+	public JTable getLegende(int index) {
+		JTable retour;
+		switch (index) {
+			case 0:
+				retour = this.legendeChampAffiche;
+				break;
+			case 1:
+				retour = this.legendeChampAffiche1;
+				break;
+			case 2:
+				retour = this.legendeChampAffiche2;
+				break;
+			case 3:
+				retour = this.legendeChampAffiche3;
+				break;
+			case 4:
+				retour = this.legendeChampAffiche4;
+				break;
+			default:
+				retour = new JTable();
+				break;
+		}
+		return retour;
+	}
+	
+	// retourne en format SVG la sélection
+	public String getSelection(int taillepolice, int x, int y, String police) {
+		String retour = "";
+		if (saisieTypeChaines.pasdeSelection()) {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Type de Schéma : aucun" + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		else {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Type de Schéma : " + saisieTypeChaines.getSelection() + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+			
+		}
+		if (saisieTypeUnites.pasdeSelection()) {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 2 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Type d'Unités : aucun" + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		else {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 2 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Type d'Unités : " + saisieTypeUnites.getSelection() + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		if (saisieChampAffiche.pasdeSelection()) {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 4 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Champ 1 : nombre de Chainons" + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		else {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 4 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Champ 1 : " + saisieChampAffiche.getSelection() + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		if (saisieChampAffiche1.pasdeSelection()) {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 6 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Champ 2 : nombre de Chainons" + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		else {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 6 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Champ 2 : " + saisieChampAffiche1.getSelection() + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		if (saisieChampAffiche2.pasdeSelection()) {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 8 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Champ 3 : nombre de Chainons" + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		else {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 8 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Champ 3 : " + saisieChampAffiche2.getSelection() + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		if (saisieChampAffiche3.pasdeSelection()) {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 10 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Champ 4 : nombre de Chainons" + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		else {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 10 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Champ 4 : " + saisieChampAffiche3.getSelection() + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		if (saisieChampAffiche4.pasdeSelection()) {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 12 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Champ 5 : nombre de Chainons" + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		else {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 12 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Champ 5 : " + saisieChampAffiche4.getSelection() + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		return retour;
+	}
+	
+	public void exporterAffichage() {
+		HashMap<String, Object> Choix = new HashMap();
+		HashMap<String, String> choixCommande = new HashMap();
+		
+		choixCommande.put("saisieTypeChaines", saisieTypeChaines.pasdeSelection() ? null : saisieTypeChaines.getSelection());
+		choixCommande.put("saisieTypeUnites", saisieTypeUnites.pasdeSelection() ? null : saisieTypeUnites.getSelection());
+		choixCommande.put("saisieTailleLigne", saisieTailleLigne.getSelectedItem().toString());
+		choixCommande.put("activeCouperParagraphe", activeCouperParagraphe.isSelected() ? "vrai" : "faux");
+		choixCommande.put("saisieChampAffiche", saisieChampAffiche.pasdeSelection() ? null : saisieChampAffiche.getSelection());
+		choixCommande.put("saisieChampAffiche1", saisieChampAffiche1.pasdeSelection() ? null : saisieChampAffiche1.getSelection());
+		choixCommande.put("saisieChampAffiche2", saisieChampAffiche2.pasdeSelection() ? null : saisieChampAffiche2.getSelection());
+		choixCommande.put("saisieChampAffiche3", saisieChampAffiche3.pasdeSelection() ? null : saisieChampAffiche3.getSelection());
+		choixCommande.put("saisieChampAffiche4", saisieChampAffiche4.pasdeSelection() ? null : saisieChampAffiche4.getSelection());
+		
+		Choix.put("valmasquees", donneesChaines.getValsMasqueesChamp());
+		Choix.put("valNbmasquees", donneesChaines.getValsNbMasqueesChamp());
+		Choix.put("valNullemasquees", donneesChaines.getValsNulleMasqueesChamp());
+		Choix.put("codeLegende", this.codeLegende);
+		Choix.put("choixCommande1", choixCommande);
+		Choix.put("ngrammes", this.ngrammes.exporterAffichage());
+		Choix.put("nomFichier", Fichiers.getNomFichierCourant(Fichiers.TypeFichier.DOC_ANALEC));
+		FichiersJava.enregistrerChaineSous(Choix);
+	}
+	
+	public void importerAffichage() {
+		HashMap<String, Object> choix = FichiersJava.ouvrirChaineVue();
+		if (choix != null && choix.containsKey("choixCommande1") &&
+				Fichiers.getNomFichierCourant(Fichiers.TypeFichier.DOC_ANALEC).equals(choix.get("nomFichier"))) {
+			HashMap<String, String> choixCommande = (HashMap<String, String>) choix.get("choixCommande1");
+			saisieTypeChaines.removeActionListener(this);
+			saisieTypeUnites.removeActionListener(this);
+			saisieTypeChaines.setSelectedItem(choixCommande.get("saisieTypeChaines"));
+			saisieTypeUnites.setSelectedItem(choixCommande.get("saisieTypeUnites"));
+			saisieTypeChaines.addActionListener(this);
+			saisieTypeUnites.addActionListener(this);
+			init();
+			// si on ne les paramètres d'affichage ont été enregistrés pour le même corpus
+			this.codeLegende = (HashMap<String, HashMap<String, String>>) choix.get("codeLegende");
+			donneesChaines.setValsMasqueesChamp((HashMap<String, HashSet<String>>) choix.get("valmasquees"));
+			donneesChaines.setValsNbMasqueesChamp((boolean[]) choix.get("valNbmasquees"));
+			donneesChaines.setValsNulleMasqueesChamp((HashSet<String>) choix.get("valNullemasquees"));
+			saisieTailleLigne.removeActionListener(this);
+			saisieChampAffiche.removeActionListener(this);
+			saisieChampAffiche1.removeActionListener(this);
+			saisieChampAffiche2.removeActionListener(this);
+			saisieChampAffiche3.removeActionListener(this);
+			saisieChampAffiche4.removeActionListener(this);
+			activeCouperParagraphe.setSelected(choixCommande.get("activeCouperParagraphe").equals("vrai"));
+			panneauGraphique.setcouperparagraphe(activeCouperParagraphe.isSelected());
+			saisieTailleLigne.setSelectedItem(choixCommande.get("saisieTailleLigne"));
+			int taille = saisieTailleLigne.getSelectedIndex() == 0 ? Integer.MAX_VALUE : Integer.parseInt((String) saisieTailleLigne.getSelectedItem());
+			panneauGraphique.setNbChainonsParLigne(taille);
+			if (choixCommande.get("saisieChampAffiche") != null) {
+				saisieChampAffiche.setSelectedItem(choixCommande.get("saisieChampAffiche"));
+			}
+			else {
+				saisieChampAffiche.effSelection();
+			}
+			if (choixCommande.get("saisieChampAffiche1") != null) {
+				saisieChampAffiche1.setSelectedItem(choixCommande.get("saisieChampAffiche1"));
+			}
+			else {
+				saisieChampAffiche1.effSelection();
+			}
+			if (choixCommande.get("saisieChampAffiche2") != null) {
+				saisieChampAffiche2.setSelectedItem(choixCommande.get("saisieChampAffiche2"));
+			}
+			else {
+				saisieChampAffiche2.effSelection();
+			}
+			if (choixCommande.get("saisieChampAffiche3") != null) {
+				saisieChampAffiche3.setSelectedItem(choixCommande.get("saisieChampAffiche3"));
+			}
+			else {
+				saisieChampAffiche3.effSelection();
+			}
+			if (choixCommande.get("saisieChampAffiche4") != null) {
+				saisieChampAffiche4.setSelectedItem(choixCommande.get("saisieChampAffiche4"));
+			}
+			else {
+				saisieChampAffiche4.effSelection();
+			}
+			saisieTailleLigne.addActionListener(this);
+			saisieChampAffiche.addActionListener(this);
+			saisieChampAffiche1.addActionListener(this);
+			saisieChampAffiche2.addActionListener(this);
+			saisieChampAffiche3.addActionListener(this);
+			saisieChampAffiche4.addActionListener(this);
+			donneesChaines.modifMasqueVals(typeChaines, typeUnites);
+			
+			if (saisieChampAffiche.pasdeSelection()) {
+				initCouleursNbElts();
+			}
+			else {
+				initCouleursChamp(saisieChampAffiche.getSelection());
+			}
+			if (saisieChampAffiche1.pasdeSelection()) {
+				initFormesNbElts();
+			}
+			else {
+				initFormesChamp(saisieChampAffiche1.getSelection());
+			}
+			if (saisieChampAffiche2.pasdeSelection()) {
+				initTaillesNbElts();
+			}
+			else {
+				initTaillesChamp(saisieChampAffiche2.getSelection());
+			}
+			if (saisieChampAffiche3.pasdeSelection()) {
+				initSurTexteNbElts();
+			}
+			else {
+				initSurTexteChamp(saisieChampAffiche3.getSelection());
+			}
+			if (saisieChampAffiche4.pasdeSelection()) {
+				initSousTexteNbElts();
+			}
+			else {
+				initSousTexteChamp(saisieChampAffiche4.getSelection());
+			}
+			this.ngrammes.setDonneesChaines(donneesChaines);
+			this.ngrammes.setTypeChaines(typeChaines);
+			this.ngrammes.setTypeUnites(typeUnites);
+			this.ngrammes.importerAffichage((HashMap) choix.get("ngrammes"));
+			this.ngrammes.update();
+		}
+		else {
+			JOptionPane.showMessageDialog(null, "le fichier des paramètres d'affichage n'est pas destiné à cette fenêtre"
+					+ System.getProperty("line.separator") +
+					"ou à ce corpus", "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+		}
+		
+		
+	}
+	
+	public ModeleChaines getDonneesChaines() {
+		return this.donneesChaines;
+	}
+	
+	public Object[][] donneesCSV(boolean[] champ) {
+		ArrayList<Object[]> donnees = new ArrayList<>();
+		int nbchamp = 0;
+		for (boolean tmp : champ) {
+			if (tmp) {
+				nbchamp = nbchamp + 1;
+			}
+		}
+		if (champ.length == 5) {
+			GChaines chaine = this.panneauGraphique;
+			Object[] titre = new Object[nbchamp + 1];
+			titre[0] = "unité";
+			int compteurTitre = 1;
+			for (int i = 0; i < champ.length; i++) {
+				if (champ[i]) {
+					switch (i) {
+						case 0:
+							titre[compteurTitre] = this.saisieChampAffiche.pasdeSelection() ? "Nombre de Chainons"
+									: this.saisieChampAffiche.getSelection();
+							break;
+						case 1:
+							titre[compteurTitre] = this.saisieChampAffiche1.pasdeSelection() ? "Nombre de Chainons"
+									: this.saisieChampAffiche1.getSelection();
+							break;
+						case 2:
+							titre[compteurTitre] = this.saisieChampAffiche2.pasdeSelection() ? "Nombre de Chainons"
+									: this.saisieChampAffiche2.getSelection();
+							break;
+						case 3:
+							titre[compteurTitre] = this.saisieChampAffiche3.pasdeSelection() ? "Nombre de Chainons"
+									: this.saisieChampAffiche3.getSelection();
+							break;
+						case 4:
+							titre[compteurTitre] = this.saisieChampAffiche4.pasdeSelection() ? "Nombre de Chainons"
+									: this.saisieChampAffiche4.getSelection();
+							break;
+					}
+					compteurTitre = compteurTitre + 1;
+				}
+			}
+			donnees.add(titre);
+			for (int j = 0; j < chaine.chainons.length; j++) {
+				ModeleChaines.Chainon unit = chaine.chainons[j];
+				Object[] row = new Object[nbchamp + 1];
+				row[0] = unit.texte;
+				int compteur = 1;
+				for (int i = 0; i < champ.length; i++) {
+					if (champ[i]) {
+						switch (i) {
+							case 0:
+								row[compteur] = this.saisieChampAffiche.pasdeSelection() ? labelsNbElements[donneesChaines.calculerValNbElements(unit.nbEltsChaine)]
+										: vue.getValeurChamp(unit.unite, this.saisieChampAffiche.getSelection());
+								break;
+							case 1:
+								row[compteur] = this.saisieChampAffiche1.pasdeSelection() ? labelsNbElements[donneesChaines.calculerValNbElements(unit.nbEltsChaine)]
+										: vue.getValeurChamp(unit.unite, this.saisieChampAffiche1.getSelection());
+								break;
+							case 2:
+								row[compteur] = this.saisieChampAffiche2.pasdeSelection() ? labelsNbElements[donneesChaines.calculerValNbElements(unit.nbEltsChaine)]
+										: vue.getValeurChamp(unit.unite, this.saisieChampAffiche2.getSelection());
+								break;
+							case 3:
+								row[compteur] = this.saisieChampAffiche3.pasdeSelection() ? labelsNbElements[donneesChaines.calculerValNbElements(unit.nbEltsChaine)]
+										: vue.getValeurChamp(unit.unite, this.saisieChampAffiche3.getSelection());
+								break;
+							case 4:
+								row[compteur] = this.saisieChampAffiche4.pasdeSelection() ? labelsNbElements[donneesChaines.calculerValNbElements(unit.nbEltsChaine)]
+										: vue.getValeurChamp(unit.unite, this.saisieChampAffiche4.getSelection());
+								break;
+						}
+						compteur = compteur + 1;
+					}
+				}
+				donnees.add(row);
+			}
+		}
+		return donnees.toArray(new Object[donnees.size()][nbchamp]);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuChaines.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ChaineUtil.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ChaineUtil.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ChaineUtil.java	(revision 3653)
@@ -0,0 +1,939 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package visuAnalec.chaines;
+
+import java.awt.*;
+import java.util.*;
+import java.util.ArrayList;
+import visuAnalec.elements.*;
+import visuAnalec.texte.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Marc
+ */
+public abstract class ChaineUtil {
+	
+	// renvoie un HashMap qui à un nombre de chainons de la chaine associe le nombre de chaines
+	// qui ont ce nombre de chainons
+	public static HashMap<Integer, Integer> calculerdonneecourbechainons(String[] typesdispo, Vue vue) {
+		String[] typesChaines = vue.getTypesSchemasAVoir();
+		HashMap<Integer, Integer> retour = new HashMap();
+		for (String typechaine : typesChaines) {
+			Schema[] chaines = vue.getSchemas(typechaine);
+			for (Schema chaine : chaines) {
+				HashSet<Element> contenu = chaine.getContenu();
+				int compte = 0;
+				for (Element elt : contenu) {
+					if (elt.getClass() == Unite.class && tableauRecherche(typesdispo, elt.getType())) {
+						compte = compte + 1;
+					}
+				}
+				if (retour.containsKey(compte)) {
+					retour.put(compte, retour.get(compte) + 1);
+				}
+				else {
+					retour.put(compte, 1);
+				}
+			}
+		}
+		return retour;
+	}
+	
+	
+	
+	
+	
+	// Calcule à partir de la position en caractères la position en mot dans une chaine de caractère
+	// @require : la position en caractère doit être inférieure à la longueur de la chaine
+	private static int calculerPositionMot(int poscaractere, String chaine, Vue vue) {
+		int compteur = 1;
+		int i = 0;
+		while (i < poscaractere) {
+			if (chaine.charAt(i) == '\n' || chaine.charAt(i) == ' ' || chaine.charAt(i) == '\r') {
+				while (i < poscaractere && (chaine.charAt(i) == '\n' || chaine.charAt(i) == ' '
+						|| chaine.charAt(i) == '\r')) {
+					i = i + 1;
+				}
+				compteur = compteur + 1;
+			}
+			i = i + 1;
+		}
+		return compteur;
+	}
+	
+	// cherche la position en nombre d'un caractère mot dans le corpus
+	public static int calculerPositionMotCorpus(int poscaractere, Vue vue) {
+		String corpus = vue.getCorpus().getTexte();
+		int resultat = 0;
+		Integer[] finparagraphe = vue.getCorpus().getFinParagraphes();
+		int finparagraphecourant = 0;
+		for (int i = 0; i < corpus.length(); i++) {
+			if (corpus.charAt(i) == ' ' || i > finparagraphe[finparagraphecourant]) {
+				resultat = resultat + 1;
+				if (i > finparagraphe[finparagraphecourant]) {
+					finparagraphecourant = finparagraphecourant + 1;
+				}
+			}
+			if (i == poscaractere) {
+				return resultat;
+			}
+		}
+		return resultat;
+	}
+	
+	// donne le nombre de paragraphes du corpus
+	public static int nbParagraphe(Vue vue) {
+		return vue.getCorpus().getFinParagraphes().length;
+	}
+	
+	// donne le nombre de caractères du corpus
+	public static int nbCaractere(Vue vue) {
+		return vue.getCorpus().getTexte().length();
+	}
+	
+	// donne le nombre de mots du Corpus
+	public static int nbMot(Vue vue) {
+		return calculerPositionMotCorpus(nbCaractere(vue) - 1, vue);
+	}
+	
+	// donne le nombre d'unité appartenant à une chaine
+	public static int nombreDeReference(String[] typesUnite, Vue vue) {
+		String[] types = vue.getTypesSchemasAVoir();
+		int compte = 0;
+		for (String type : types) {
+			Schema[] chaines = vue.getSchemas(type);
+			for (Schema chaine : chaines) {
+				for (Element unit : chaine.getContenu()) {
+					if (unit.getClass() == Unite.class && tableauRecherche(typesUnite, unit.getType())) {
+						compte = compte + 1;
+					}
+				}
+			}
+		}
+		return compte;
+	}
+	
+	// donne le nombre de chaines non vides
+	public static int nbChaines(Vue vue) {
+		String[] types = vue.getTypesSchemasAVoir();
+		int compte = 0;
+		for (String type : types) {
+			Schema[] chaines = vue.getSchemas(type);
+			for (Schema chaine : chaines) {
+				if (chaine.getContenu().size() > 0) {
+					compte = compte + 1;
+				}
+			}
+		}
+		return compte;
+	}
+	
+	// calcule le nombre de références par unité de longueur "choix"
+	public static float densiteReferentielle(String choix, String[] types, Vue vue) {
+		float compte = 0.0f;
+		compte = compte + nombreDeReference(types, vue);
+		switch (choix) {
+			case "Caractère":
+				compte = Math.round(compte * 10000.0f / nbCaractere(vue)) / 10000.0f;
+				break;
+			case "Mot":
+				compte = Math.round(compte * 10000.0f / nbMot(vue)) / 10000.0f;
+				break;
+			case "Paragraphe":
+				compte = Math.round(compte * 10000.0f / nbParagraphe(vue)) / 10000.0f;
+				break;
+			default:
+				break;
+			
+		}
+		return compte;
+	}
+	
+	// attention les unités sont dans le désordre
+	public static ArrayList<Integer> positionUnite(String[] types, Vue vue) {
+		ArrayList<Integer> retour = new ArrayList<>();
+		for (String type : types) {
+			Unite[] unites = vue.getUnites(type);
+			for (Unite unit : unites) {
+				retour.add(unit.getDeb());
+			}
+		}
+		return retour;
+	}
+	
+	// renvoie les unités dont le type est contenu dans le tableau "types" puis et triée par ordre d'apparition
+	// dans le corpus
+	public static Unite[] getUniteesTrieesEtFiltrees(String[] types, Vue vue) {
+		ArrayList<Unite> stockage = new ArrayList<>();
+		for (String type : types) {
+			Unite[] tmp = vue.getUnites(type);
+			for (int i = 0; i < tmp.length; i++) {
+				stockage.add(tmp[i]);
+			}
+		}
+		Unite[] retour = stockage.toArray(new Unite[stockage.size()]);
+		triFusionUnite(retour);
+		return retour;
+	}
+	
+	// calcule les position en nombre de mots au sein d'un corpus des unités dont le
+	// type est contenu dans le tableau "types" puis et triée par ordre d'apparition
+	public static ArrayList<Integer> positionUniteEnMot(String[] types, Vue vue) {
+		Unite[] donnees = getUniteesTrieesEtFiltrees(types, vue);
+		int postexte = 0;
+		int comptemot = 0;
+		String texte = vue.getCorpus().getTexte();
+		ArrayList<Integer> retour = new ArrayList<>();
+		for (int i = 0; i < donnees.length; i++) {
+			while (postexte < donnees[i].getDeb()) {
+				if (texte.charAt(postexte) == ' ' || texte.charAt(postexte) == '\n') {
+					comptemot = comptemot + 1;
+				}
+				postexte = postexte + 1;
+			}
+			retour.add(comptemot);
+		}
+		return retour;
+	}
+	
+	// calcule les écarts en nombre de caractères au sein d'un corpus des unités dont le
+	// type est contenu dans le tableau "types"
+	// les écarts sont la différence les positions de début de deux unités consécutives respectant toutes deux
+	// un type d'unités contenu dans "types"
+	public static ArrayList<Integer> ecartUniteCaractere(String[] types, Vue vue) {
+		ArrayList<Integer> retour = new ArrayList<>();
+		Unite[] unites = getUniteesTrieesEtFiltrees(types, vue);
+		for (int i = 0; i < unites.length - 1; i++) {
+			retour.add(unites[i + 1].getDeb() - unites[i].getDeb());
+		}
+		return retour;
+	}
+	
+	// calcule les écarts en nombre de mots au sein d'un corpus des unités dont le
+	// type est contenu dans le tableau "types"
+	// les écarts sont la différence les positions de début de deux unités consécutives respectant toutes deux
+	// un type d'unités contenu dans "types"
+	public static ArrayList<Integer> ecartUniteMot(String[] types, Vue vue) {
+		ArrayList<Integer> retour = new ArrayList<>();
+		Unite[] unites = getUniteesTrieesEtFiltrees(types, vue);
+		for (int i = 0; i < unites.length - 1; i++) {
+			String texte = vue.getCorpus().getTexte().substring(unites[i].getDeb(), unites[i + 1].getDeb());
+			int compte = 0;
+			for (int j = 0; j < texte.length(); j++) {
+				if (texte.charAt(j) == ' ' || texte.charAt(j) == '\n') {
+					compte = compte + 1;
+				}
+			}
+			retour.add(compte);
+		}
+		return retour;
+	}
+	
+	// détermine les longueurs en mots des unités contenu dans un corpus et dont le
+	// type est contenu dans le tableau "types"
+	public static ArrayList<Integer> longueurUniteMot(String[] types, Vue vue) {
+		ArrayList<Integer> retour = new ArrayList<>();
+		for (String type : types) {
+			Unite[] unites = vue.getUnites(type);
+			for (int i = 0; i < unites.length; i++) {
+				String texte = vue.getCorpus().getTexte().substring(unites[i].getDeb(), unites[i].getFin());
+				int compte = 0;
+				for (int j = 0; j < texte.length(); j++) {
+					if (texte.charAt(j) == ' ' || texte.charAt(j) == '\n') {
+						compte = compte + 1;
+					}
+				}
+				retour.add(compte);
+			}
+		}
+		return retour;
+	}
+	
+	// détermine les longueurs en nombre de caractères des unités contenu dans un corpus et dont le
+	// type est contenu dans le tableau "types"
+	public static ArrayList<Integer> longueurUniteCaractere(String[] types, Vue vue) {
+		ArrayList<Integer> retour = new ArrayList<>();
+		for (String type : types) {
+			Unite[] unites = vue.getUnites(type);
+			for (int i = 0; i < unites.length; i++) {
+				int compte = unites[i].getFin() - unites[i].getDeb();
+				retour.add(compte);
+			}
+		}
+		return retour;
+	}
+	
+	// pas optimisé comme un binary search car on a pas d'ordre défini sur les objets du tableau
+	// et donc le tableau n'est pas trié
+	public static boolean tableauRecherche(Object[] tab, Object elt) {
+		for (Object unit : tab) {
+			if (unit.equals(elt)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	// détermine la longueur des chaines en caractères
+	public static ArrayList<Integer> longueurChaineCaractere(String[] types, Vue vue) {
+		String[] typeschaine = vue.getTypesSchemasAVoir();
+		ArrayList<Integer> retour = new ArrayList<>();
+		for (String type : typeschaine) {
+			Schema[] chaines = vue.getSchemas(type);
+			for (Schema chaine : chaines) {
+				HashSet<Element> contenu = chaine.getContenu();
+				Integer compte = 0;
+				for (Element elt : contenu) {
+					if (elt.getClass() == Unite.class && tableauRecherche(types, elt.getType())) {
+						Unite tmp = (Unite) elt;
+						compte = compte + tmp.getFin() - tmp.getDeb();
+					}
+				}
+				retour.add(compte);
+			}
+		}
+		return retour;
+	}
+	
+	// détermine la longueur des chaines en mots en sommant la longueur des maillons dont le type est contenu
+	// dans "types"
+	public static ArrayList<Integer> longueurChaineMot(String[] types, Vue vue) {
+		String[] typeschaine = vue.getTypesSchemasAVoir();
+		ArrayList<Integer> retour = new ArrayList<>();
+		for (String type : typeschaine) {
+			Schema[] chaines = vue.getSchemas(type);
+			for (Schema chaine : chaines) {
+				HashSet<Element> contenu = chaine.getContenu();
+				Integer compte = 0;
+				for (Element elt : contenu) {
+					if (elt.getClass() == Unite.class && tableauRecherche(types, elt.getType())) {
+						Unite tmp = (Unite) elt;
+						String texte = vue.getCorpus().getTexte().substring(tmp.getDeb(), tmp.getFin());
+						for (int i = 0; i < texte.length(); i++) {
+							if (texte.charAt(i) == ' ' || texte.charAt(i) == '\n') {
+								compte = compte + 1;
+							}
+						}
+					}
+				}
+				retour.add(compte);
+			}
+		}
+		return retour;
+	}
+	
+	
+	// calcule le nombre de chainons(unités) dont le type est contenu dans "types" de chaque chaine
+	public static ArrayList<Integer> nombreDeChainons(String[] types, Vue vue) {
+		String[] typeschaines = vue.getTypesSchemasAVoir();
+		ArrayList<Integer> retour = new ArrayList<>();
+		for (String type : typeschaines) {
+			Schema[] chaines = vue.getSchemas(type);
+			for (Schema chaine : chaines) {
+				HashSet<Element> contenu = chaine.getContenu();
+				Integer compte = 0;
+				for (Element elt : contenu) {
+					if (elt.getClass() == Unite.class && tableauRecherche(types, elt.getType())) {
+						compte = compte + 1;
+					}
+				}
+				retour.add(compte);
+			}
+		}
+		return retour;
+	}
+	
+	
+	
+	// recherche le numero de paragraphe dans le corpus qui correspond à une position en caractère
+	public static int conversionPositionCaracterEtNoParagraphe(int poscaractere, Vue vue) {
+		Integer[] noparagraphe = vue.getCorpus().getFinParagraphes();
+		for (int i = 0; i < noparagraphe.length; i++) {
+			if (poscaractere > noparagraphe[i] || i == noparagraphe.length - 1) {
+				return i;
+			}
+			
+		}
+		return -1;
+	}
+	
+	
+	// @ensures : retourne la longueur d'une unité en caractère
+	public static int longueurUnite(Unite donnee) {
+		return (donnee.getFin() - donnee.getDeb());
+	}
+	
+	// @ensures : retourne la longueur d'une unite en mot
+	public static int nbMotUnite(Unite donnee, Vue vue) {
+		String chaine = (vue.getCorpus()).getTexteUnite(donnee);
+		return calculerPositionMot(chaine.length(), chaine, vue);
+	}
+	
+	// cherche le maximum d'un tableau pas forcément trié
+	public static Integer maxiTab(Integer[] donnees) {
+		Integer max = -1;
+		if (donnees.length > 0) {
+			max = donnees[0];
+			for (Integer nbr : donnees) {
+				if (nbr > max) {
+					max = nbr;
+				}
+			}
+		}
+		return max;
+	}
+	
+	// cherche le minimum d'un tableau pas forcément trié
+	public static Integer miniTab(Integer[] donnees) {
+		Integer min = -1;
+		if (donnees.length > 0) {
+			min = donnees[0];
+			for (Integer nbr : donnees) {
+				if (nbr < min) {
+					min = nbr;
+				}
+			}
+		}
+		return min;
+	}
+	
+	// retourne la somme des éléments d'un tableau
+	public static int somme(Integer[] donnees) {
+		int total = 0;
+		for (Integer nbr : donnees) {
+			total = total + nbr;
+		}
+		return total;
+	}
+	
+	
+	public static int nbMotsDansUneUnite(int deb, int fin, Vue vue) {
+		String texteunite = vue.getCorpus().getTexte().substring(deb, fin);
+		int compte = (deb < fin ? 1 : 0);
+		for (int i = 0; i < texteunite.length(); i++) {
+			if (texteunite.charAt(i) == ' ') {
+				compte = compte + 1;
+			}
+		}
+		return compte;
+	}
+	
+	// permet de trier un tableau de valeurs suivant leur fréquence
+	public static void triFusionMap(String tableau[], HashMap<String, Float> freq) {
+		int longueur = tableau.length;
+		if (longueur > 0) {
+			triFusionMap(tableau, 0, longueur - 1, freq);
+		}
+	}
+	
+	private static void triFusionMap(String tableau[], int deb, int fin, HashMap<String, Float> freq) {
+		if (deb != fin) {
+			int milieu = (fin + deb) / 2;
+			triFusionMap(tableau, deb, milieu, freq);
+			triFusionMap(tableau, milieu + 1, fin, freq);
+			fusionMap(tableau, deb, milieu, fin, freq);
+		}
+	}
+	
+	private static void fusionMap(String tableau[], int deb1, int fin1, int fin2, HashMap<String, Float> freq) {
+		int deb2 = fin1 + 1;
+		
+		// on recopie les éléments du début du tableau
+		String table1[] = new String[fin1 - deb1 + 1];
+		for (int i = deb1; i <= fin1; i++) {
+			table1[i - deb1] = tableau[i];
+		}
+		
+		int compt1 = deb1;
+		int compt2 = deb2;
+		
+		for (int i = deb1; i <= fin2; i++) {
+			if (compt1 == deb2) // c'est que tous les éléments du premier tableau ont été utilisés
+			{
+				break; // tous les éléments ont donc été classés
+			}
+			else if (compt2 == (fin2 + 1)) // c'est que tous les éléments du second tableau ont été utilisés
+			{
+				tableau[i] = table1[compt1 - deb1]; // on ajoute les éléments restants du premier tableau
+				compt1++;
+			}
+			else if (freq.get(table1[compt1 - deb1]) > freq.get(tableau[compt2])) {
+				tableau[i] = table1[compt1 - deb1]; // on ajoute un élément du premier tableau
+				compt1++;
+			}
+			else {
+				tableau[i] = tableau[compt2]; // on ajoute un élément du second tableau
+				compt2++;
+			}
+		}
+	}
+	
+	// on enlève les unités dont le numero de paragraphe appartient à Noparagraphe
+	public static Unite[] filtreparagraphe(Unite[] donnees, ArrayList<Integer> Noparagraphemasque, Vue vue) {
+		HashMap<Unite, Integer> noparagraphe = unitenumeroparagraphe(donnees, vue);
+		ArrayList<Unite> unitefiltrees = new ArrayList<>();
+		for (Unite unit : donnees) {
+			if (!(Noparagraphemasque.contains(noparagraphe.get(unit)))) {
+				unitefiltrees.add(unit);
+			}
+		}
+		Unite[] resultat = unitefiltrees.toArray(new Unite[0]);
+		return resultat;
+	}
+	
+	// renvoie un tableau contenant les fréquences de chaque valeur d'un champ dans la liste d'unités
+	public static HashMap<String, Float> calculerfrequencechamp(Unite[] donnees, String typeUnites, String Champcible, Vue vue) {
+		String[] valsdisponibles = vue.getValeursChamp(Unite.class, typeUnites, Champcible);
+		HashMap<String, Float> tableaufrequence = new HashMap<>(valsdisponibles.length + 1);
+		String valeurchamp;
+		// on initialise le tableau résultat
+		for (String valeur : valsdisponibles) {
+			tableaufrequence.put(valeur, 0.0f);
+		}
+		tableaufrequence.put("", 0.0f);
+		// on compte le nombre d'occurences
+		for (Unite unit : donnees) {
+			valeurchamp = vue.getValeurChamp(unit, Champcible);
+			tableaufrequence.put(valeurchamp, tableaufrequence.get(valeurchamp) + 1);
+		}
+		// on calcule les pourcentages
+		for (String valeur : valsdisponibles) {
+			tableaufrequence.put(valeur, tableaufrequence.get(valeur) * 10000.0f /
+					donnees.length / 100.0f);
+		}
+		tableaufrequence.put("", tableaufrequence.get("") * 10000.0f /
+				donnees.length / 100.0f);
+		
+		return tableaufrequence;
+	}
+	
+	// détermine la moyenne par rapport à la deuxième variable d'un HashMap
+	public static float Esperance(HashMap<Object, Integer> donnees) {
+		float moyenne = 0.0f;
+		for (Object i : donnees.keySet()) {
+			moyenne = moyenne + donnees.get(i);
+		}
+		moyenne = moyenne / donnees.size();
+		return moyenne;
+	}
+	
+	// détermine la moyenne des valeurs d'un tableau
+	public static float Esperance(Integer[] donnees) {
+		float moyenne = 0.0f;
+		for (Integer i : donnees) {
+			moyenne = moyenne + i;
+		}
+		moyenne = moyenne / donnees.length;
+		return moyenne;
+	}
+	
+	// détermine la variance par rapport à la deuxième variable d'un HashMap
+	public static float Variance(HashMap<Object, Integer> donnees) {
+		float moyenne = Esperance(donnees);
+		float variance = 0.0f;
+		if (donnees.size() > 1) {
+			for (Object i : donnees.keySet()) {
+				variance = variance + (donnees.get(i) - moyenne) * (donnees.get(i) - moyenne);
+			}
+			variance = variance / (donnees.size() - 1);
+		}
+		
+		return variance;
+	}
+	
+	// détermine la variance des valeurs d'un tableau
+	public static float Variance(Integer[] donnees) {
+		float moyenne = Esperance(donnees);
+		float variance = 0.0f;
+		if (donnees.length > 1) {
+			for (Integer i : donnees) {
+				variance = variance + (i - moyenne) * (i - moyenne);
+			}
+			variance = variance / (donnees.length - 1);
+		}
+		return variance;
+	}
+	
+	// permet de trier les unités d'un tableau
+	// la relation d'ordre entre les unités est la comparaison des positions de débuts des unités au sein du texte
+	public static void triFusionUnite(Unite tableau[]) {
+		int longueur = tableau.length;
+		if (longueur > 0) {
+			triFusionUnite(tableau, 0, longueur - 1);
+		}
+	}
+	
+	private static void triFusionUnite(Unite tableau[], int deb, int fin) {
+		if (deb != fin) {
+			int milieu = (fin + deb) / 2;
+			triFusionUnite(tableau, deb, milieu);
+			triFusionUnite(tableau, milieu + 1, fin);
+			fusionUnite(tableau, deb, milieu, fin);
+		}
+	}
+	
+	private static void fusionUnite(Unite tableau[], int deb1, int fin1, int fin2) {
+		int deb2 = fin1 + 1;
+		
+		// on recopie les éléments du début du tableau
+		Unite table1[] = new Unite[fin1 - deb1 + 1];
+		for (int i = deb1; i <= fin1; i++) {
+			table1[i - deb1] = tableau[i];
+		}
+		
+		int compt1 = deb1;
+		int compt2 = deb2;
+		
+		for (int i = deb1; i <= fin2; i++) {
+			if (compt1 == deb2) // c'est que tous les éléments du premier tableau ont été utilisés
+			{
+				break; // tous les éléments ont donc été classés
+			}
+			else if (compt2 == (fin2 + 1)) // c'est que tous les éléments du second tableau ont été utilisés
+			{
+				tableau[i] = table1[compt1 - deb1]; // on ajoute les éléments restants du premier tableau
+				compt1++;
+			}
+			else if (table1[compt1 - deb1].getDeb() < tableau[compt2].getDeb()) {
+				tableau[i] = table1[compt1 - deb1]; // on ajoute un élément du premier tableau
+				compt1++;
+			}
+			else {
+				tableau[i] = tableau[compt2]; // on ajoute un élément du second tableau
+				compt2++;
+			}
+		}
+	}
+	
+	// permet de trier les unités d'une arrayList
+	// la relation d'ordre entre les unités est la comparaison des positions de débuts des unités au sein du texte
+	public static void triFusionUnite(ArrayList<Unite> tableau) {
+		int longueur = tableau.size();
+		if (longueur > 0) {
+			triFusionUnite(tableau, 0, longueur - 1);
+		}
+	}
+	
+	private static void triFusionUnite(ArrayList<Unite> tableau, int deb, int fin) {
+		if (deb != fin) {
+			int milieu = (fin + deb) / 2;
+			triFusionUnite(tableau, deb, milieu);
+			triFusionUnite(tableau, milieu + 1, fin);
+			fusionUnite(tableau, deb, milieu, fin);
+		}
+	}
+	
+	private static void fusionUnite(ArrayList<Unite> tableau, int deb1, int fin1, int fin2) {
+		int deb2 = fin1 + 1;
+		
+		// on recopie les éléments du début du tableau
+		Unite table1[] = new Unite[fin1 - deb1 + 1];
+		for (int i = deb1; i <= fin1; i++) {
+			table1[i - deb1] = tableau.get(i);
+		}
+		
+		int compt1 = deb1;
+		int compt2 = deb2;
+		
+		for (int i = deb1; i <= fin2; i++) {
+			if (compt1 == deb2) // c'est que tous les éléments du premier tableau ont été utilisés
+			{
+				break; // tous les éléments ont donc été classés
+			}
+			else if (compt2 == (fin2 + 1)) // c'est que tous les éléments du second tableau ont été utilisés
+			{
+				tableau.add(i, table1[compt1 - deb1]); // on ajoute les éléments restants du premier tableau
+				tableau.remove(i + 1);
+				compt1++;
+			}
+			else if (table1[compt1 - deb1].getDeb() < tableau.get(compt2).getDeb()) {
+				tableau.add(i, table1[compt1 - deb1]); // on ajoute un élément du premier tableau
+				tableau.remove(i + 1);
+				compt1++;
+			}
+			else {
+				tableau.add(i, tableau.get(compt2)); // on ajoute un élément du second tableau
+				tableau.remove(i + 1);
+				compt2++;
+			}
+		}
+	}
+	
+	// permet de créer un ensemble de points à intervalle régulier entre deux bornes
+	public static int[] discretisation(int deb, int fin, int nbpoints) {
+		int[] subdivision = new int[nbpoints];
+		try {
+			int pas = (fin - deb) / (nbpoints - 1);
+			for (int i = 0; i < nbpoints; i++) {
+				subdivision[i] = deb + i * pas;
+			}
+		}
+		catch (ArithmeticException e) {
+			subdivision[0] = (deb + fin) / 2;
+		}
+		return subdivision;
+	}
+	
+	// @require : les paragraphes et les unités sont triés dans l'ordre
+	// @ensures : retourne une table associant les unités à leur numero de
+	// paragraphe
+	public static HashMap<Unite, Integer> unitenumeroparagraphe(Unite[] unites, Vue vue) {
+		HashMap<Unite, Integer> numeroparagraphe = new HashMap<>(unites.length);
+		int[] noparagraphe = (vue.getCorpus()).calculerNoParagraphe(unites);
+		for (int i = 0; i < unites.length; i++) {// pour toutes les unites
+			numeroparagraphe.put(unites[i], noparagraphe[i]);
+		}
+		return numeroparagraphe;
+	}
+	
+	// le nouveau type s'appellera "tout"
+	// attention les relations ne sont pas copiées pour vérifier pour maintenir le lien entre les unités
+	public static void fusionTypeUnite(Vue vue) {
+		// on initialise les propriétés du nouveau type
+		long deb = System.nanoTime();
+		HashSet<String> nomsChamps = new HashSet<>();
+		for (String champ : (vue.getTypesUnitesAVoir().length == 0 ? new String[0] : vue.getNomsChamps(Unite.class, vue.getTypesUnitesAVoir()[0]))) {
+			nomsChamps.add(champ);
+		}
+		// les propriétés du nouveau seront l'intersection des propriétés de tous les types
+		for (String type : vue.getTypesUnitesAVoir()) {
+			HashSet<String> nomsChampNonFiltres = (HashSet<String>) nomsChamps.clone();
+			nomsChamps = new HashSet<>();
+			for (String champ : vue.getNomsChamps(Unite.class, type)) {
+				// si le champ est partagé par tous les autres types d'unités déjà passé en revue
+				// alors on l'ajoute à l'intersection provisoire
+				if (nomsChampNonFiltres.contains(champ)) {
+					nomsChamps.add(champ);
+				}
+			}
+		}
+		// on parcours toutes les unités
+		for (String type : vue.getTypesUnitesAVoir()) {
+			for (Unite unit : vue.getUnites(type)) {
+				Unite cloneUnite = new Unite("tout", unit.getDeb(), unit.getFin());
+				for (String champ : nomsChamps) {
+					cloneUnite.putProp(champ, vue.getValeurChamp(unit, champ));
+				}
+				vue.getCorpus().addUniteConvertit(cloneUnite);
+				// on ajoute la nouvelle unité aux autre schemas
+				for (Schema schemasContenant : unit.getSchemas()) {
+					vue.getCorpus().ajouterElementSchemaSaisi(cloneUnite, schemasContenant);
+				}
+			}
+		}
+		long fin = System.nanoTime();
+		System.out.println((fin - deb) / 1000000);
+	}
+	
+	// crée un type de schéma et les schémas correspondant à partir des choix de l'utilisateur
+	/*
+	 * Deux éléments d'une même relation appartiennent au même Schéma et on crée un shéma
+	 * pour chaque valeur différente d'une propriété de la relation
+	 */
+	public static Schema[] conversion(String source, String nomType, String typeSource, String primaryKey, String[] otherKey,
+			Vue vue) {
+		ArrayList<Schema> retour = new ArrayList<>();
+		HashMap<String, Schema> triSchema = new HashMap<>();
+		long deb = System.nanoTime();
+		switch (source) {
+			case "Relation":
+				Relation[] donnees = vue.getRelations(typeSource);
+				// pour toutes les relations
+				for (Relation Rel : donnees) {
+					String valeur = vue.getValeurChamp(Rel, primaryKey);
+					// si aucun schema n'a la même valeur que la relation pour la clé primaire
+					if (!triSchema.containsKey(valeur)) {
+						triSchema.put(valeur, new Schema(nomType));
+						HashMap<String, String> propSchema = triSchema.get(valeur).getProps();
+						// le schema prend les mêmes propriétés que le schéma
+						for (String champ : Rel.getProps().keySet()) {
+							propSchema.put(champ, Rel.getProp(champ));
+						}
+					}
+					triSchema.get(valeur).ajouter(Rel.getElt1());
+					triSchema.get(valeur).ajouter(Rel.getElt2());
+				}
+				break;
+			case "typeUnite":
+				// pour tous les types d'unités on crée un schéma
+				String[] typesUnites = vue.getTypesUnitesAVoir();
+				for (String type : typesUnites) {
+					triSchema.put(type, new Schema(nomType));
+					HashMap<String, String> propSchema = triSchema.get(type).getProps();
+					propSchema.put("type", type);
+					for (Unite unit : vue.getUnites(type)) {
+						triSchema.get(type).ajouter(unit);
+					}
+				}
+				break;
+			case "attributUnite":
+				Unite[] UnitesAVoir = vue.getUnites(typeSource);
+				// pour toutes les unités
+				for (Unite unit : UnitesAVoir) {
+					String valeur = vue.getValeurChamp(unit, primaryKey);
+					// si aucun schéma n'a la même valeur que l'unité pour la clé primaire
+					if (!triSchema.containsKey(valeur)) {
+						triSchema.put(valeur, new Schema(nomType));
+						HashMap<String, String> propSchema = triSchema.get(valeur).getProps();
+						// le nouveau schéma prend les mêmes propriétés que l'unité
+						propSchema.put(primaryKey, unit.getProp(primaryKey));
+						for (String champ : otherKey) {
+							propSchema.put(champ, unit.getProp(champ));
+						}
+					}
+					triSchema.get(valeur).ajouter(unit);
+				}
+				break;
+			default:
+				break;
+			
+		}
+		for (String valeur : triSchema.keySet()) {
+			vue.getCorpus().addSchemaConvertit(triSchema.get(valeur));
+		}
+		long fin = System.nanoTime();
+		System.out.println((fin - deb) / 1000000);
+		
+		return retour.toArray(new Schema[0]);
+	}
+	
+	// calcule les donnees nécessaires pour l'affichage du graphique dont l'axe des abscisses est le numéro de
+	// paragraphe
+	public static HashMap<Integer, HashMap<String, Integer>> calculedonneecourbe(String[] typesdispo, String unitecomptage, Vue vue) {
+		HashMap<Integer, HashMap<String, Integer>> donnees = new HashMap();
+		String texte = vue.getCorpus().getTexte();
+		Integer[] noparagraphes = vue.getCorpus().getFinParagraphes();
+		int unitecourante = 0;
+		int paragraphecourant = 0;
+		int comptemot = 0;
+		int sommeUniteComptage = 0;
+		HashMap<Unite, Schema> chainesUnitesNonFiltrees = calculerChainesUnitesNonFiltrees(typesdispo, vue);
+		HashSet<Schema> chaineparagraphe = new HashSet();
+		Unite[] unites = ChaineUtil.getUniteesTrieesEtFiltrees(typesdispo, vue);
+		// initialisation
+		for (int i = 0; i < noparagraphes.length; i++) {
+			donnees.put(i, new HashMap());
+			donnees.get(i).put("Nombre de Chaines de coreference", 0);
+			donnees.get(i).put("Nombre de chainons", 0);
+			donnees.get(i).put("ratio nombre de chainons par nombre de " + unitecomptage, 0);
+			donnees.get(i).put("Densité référentielle", 0);
+		}
+		for (int i = 0; i < texte.length(); i++) {
+			if (i > noparagraphes[paragraphecourant] || i == texte.length() - 1) {
+				donnees.get(paragraphecourant).put("Nombre de Chaines de coreference", chaineparagraphe.size());
+				donnees.get(paragraphecourant).put("ratio nombre de chainons par nombre de " + unitecomptage,
+						Math.round(sommeUniteComptage * 100.0f / (unitecomptage.equals("Mots") ? comptemot
+								: (noparagraphes[paragraphecourant] - (paragraphecourant == 0 ? 0 : noparagraphes[paragraphecourant - 1])))));
+				donnees.get(paragraphecourant).put("Densité référentielle",
+						Math.round((100.0f * donnees.get(paragraphecourant).get("Nombre de chainons")) /
+								(unitecomptage == "Mots" ? comptemot
+										: (noparagraphes[paragraphecourant] -
+												(paragraphecourant == 0 ? 0 : noparagraphes[paragraphecourant - 1])))));
+				chaineparagraphe = new HashSet();
+				paragraphecourant = paragraphecourant + 1;
+				comptemot = 1;
+				sommeUniteComptage = 0;
+			}
+			// si on decouvre une unité
+			while (unitecourante < unites.length && unites[unitecourante].getDeb() == i) {
+				if (chainesUnitesNonFiltrees.containsKey(unites[unitecourante])) {
+					donnees.get(paragraphecourant).put("Nombre de chainons",
+							donnees.get(paragraphecourant).get("Nombre de chainons") + 1);
+					chaineparagraphe.add(chainesUnitesNonFiltrees.get(unites[unitecourante]));
+					sommeUniteComptage = sommeUniteComptage + (unitecomptage == "Mots" ? ChaineUtil.nbMotsDansUneUnite(unites[unitecourante].getDeb(), unites[unitecourante].getFin(), vue)
+							: unites[unitecourante].getFin() - unites[unitecourante].getDeb());
+				}
+				unitecourante = unitecourante + 1;
+			}
+			// si on change de mot
+			if (unitecomptage.equals("Mots") && texte.charAt(i) == ' ') {
+				comptemot = comptemot + 1;
+			}
+		}
+		
+		return donnees;
+	}
+	
+	
+	// struture qui n'est pas filtrées mais qui associe à une unité qui correspond au bon type d'unités
+	// contenu dans "typeUnités" la chaine qui la contient et qui est elle aussi du bon type de Schéma
+	private static HashMap<Unite, Schema> calculerChainesUnitesNonFiltrees(String[] typeUnites, Vue vue) throws UnsupportedOperationException {
+		HashMap<Unite, Schema> chainesUnitesNonFiltrees = new HashMap();
+		for (String typechaine : vue.getTypesSchemasAVoir()) {
+			Schema[] chaines = vue.getSchemas(typechaine);
+			for (Schema chaine : chaines) {
+				HashSet<Element> contenu = chaine.getContenu();
+				for (Element elt : contenu) {
+					if (elt.getClass() == Unite.class && ChaineUtil.tableauRecherche(typeUnites, elt.getType())) {
+						if (chainesUnitesNonFiltrees.containsKey(elt)) {
+							throw new UnsupportedOperationException("L'unité " + vue.getIdElement(elt)
+									+ " appartient à deux chaînes : " + vue.getIdElement(chaine) + " et "
+									+ vue.getIdElement(chainesUnitesNonFiltrees.get(elt)));
+						}
+						else
+							chainesUnitesNonFiltrees.put((Unite) elt, chaine);
+					}
+				}
+			}
+		}
+		return chainesUnitesNonFiltrees;
+	}
+	
+	// renvoie la valeur en un point d'un polynome interpolé à partir de deux tableau représentant les coordonnées de points
+	public static Integer interpolationLagrangienne(Integer[] abscisse, Integer[] ordonnee, int value) {
+		if (abscisse.length == ordonnee.length) {
+			Double retour = 0.0d;
+			for (int i = 0; i < abscisse.length; i++) {
+				Double produit = 1.0d;
+				for (int j = 0; j < abscisse.length; j++) {
+					if (i != j) {
+						produit = produit * (value - abscisse[j]) / (abscisse[i] - abscisse[j]);
+					}
+				}
+				retour = retour + produit * ordonnee[i];
+			}
+			return (Math.round(retour) < 0 ? 0 : (int) Math.round(retour));
+			
+		}
+		return -1;
+	}
+	
+	/* @require: abscisse and length have the same length */
+	public static ArrayList<Float[]> coef_spline_quad(Integer[] abscisse, Integer[] ordonnee) {
+		Float[] coef_abs = new Float[abscisse.length];
+		Float[] coef_ord = new Float[ordonnee.length];
+		ArrayList<Float[]> retour = new ArrayList<>();
+		coef_abs[0] = 0.0f;
+		for (int i = 1; i < abscisse.length; i++) {
+			coef_abs[i] = 1.0f * 2 * (ordonnee[i] - ordonnee[i - 1]) / (abscisse[i] - abscisse[i - 1]);
+			coef_ord[i] = ordonnee[i - 1] + coef_abs[i - 1] * (abscisse[i] - abscisse[i - 1]) / 2;
+			
+		}
+		retour.add(coef_abs);
+		retour.add(coef_ord);
+		return retour;
+		
+	}
+	
+	/* @require: abscisse and length have the same length superior to 2 */
+	public static Integer interpolation_spline_quad(Integer[] abscisse, Integer[] ordonnee, int value) {
+		float retour;
+		ArrayList<Float[]> coef = coef_spline_quad(abscisse, ordonnee);
+		retour = coef.get(1)[1];
+		for (int i = 1; i < abscisse.length; i++) {
+			if (value > abscisse[i - 1] && value < abscisse[i]) {
+				retour = 0 - coef.get(0)[i - 1] * (value - abscisse[i]) * (value - abscisse[i]) + coef.get(0)[i]
+						* (value - abscisse[i - 1]) * (value - abscisse[i - 1]) / 2 / (abscisse[i] - abscisse[i - 1])
+						+ coef.get(1)[i];
+			}
+		}
+		return Math.round(retour);
+	}
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ChaineUtil.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuCoref.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuCoref.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuCoref.java	(revision 3653)
@@ -0,0 +1,1193 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package visuAnalec.chaines;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import org.jfree.chart.ChartPanel;
+import visuAnalec.*;
+import visuAnalec.elements.*;
+import visuAnalec.fichiers.FichiersJava;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.GAction;
+import visuAnalec.util.GVisu.LegendeLabel;
+import visuAnalec.util.GVisu.LegendeModeleTable;
+import visuAnalec.util.GVisu.LegendeModeleTableTexte;
+import visuAnalec.util.GVisu.TypeComboBox;
+import visuAnalec.util.GVisu.Val0ComboBox;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Marc
+ */
+public class VisuCoref extends JFrame implements Vue.VueListener, ActionListener {
+	
+	private static final int[] seuilsValsNbElts = { 3, 10 };
+	
+	private static final Color[] couleursNbElts = { Color.WHITE, GVisu.getCouleurSansValeur(),
+			GVisu.getCouleur(0), GVisu.getCouleur(3), GVisu.getCouleur(1) };
+	
+	private static final String[] labelsNbElements = {
+			"pas de chaîne associée",
+			"chaîne d'un seul chaînon",
+			"chaîne de 2-" + Integer.toString(seuilsValsNbElts[0]) + " chaînons",
+			"chaîne de " + Integer.toString(seuilsValsNbElts[0] + 1) + "-"
+					+ Integer.toString(seuilsValsNbElts[1]) + "  chaînons",
+			"chaîne de plus de " + Integer.toString(seuilsValsNbElts[1]) + " chaînons"
+	};
+	
+	private final Vue vue;
+	
+	private final JMenuBar menuBar = new JMenuBar();
+	
+	private final ModeleChaines donneesChaines;
+	
+	private String typeChaines;
+	
+	private String typeUnites;
+	
+	private String[] valsAffichees;
+	
+	private HashSet<String> valsAffichees1cachees = new HashSet<>();
+	
+	private ArrayList<Integer> noparagraphecachees = new ArrayList<>();
+	
+	private String[] valsAffichees1;
+	
+	private Integer[] valsAffichees2;
+	
+	private final TypeComboBox saisieTypeChaines;
+	
+	private final TypeComboBox saisieTypeUnites;
+	
+	private Val0ComboBox saisieChampAffiche;
+	
+	private Val0ComboBox saisieChampChaine;
+	
+	private final Val0ComboBox saisieChampStatistique;
+	
+	private JTable legendeChampAffiche;
+	
+	private JTable legendeChampAfficheChaine;
+	
+	private JTable legendeChampAfficheParagraphe;
+	
+	private LegendeModeleTable legendeChampAfficheModele;
+	
+	private LegendeModeleTableTexte legendeChampAfficheChaineModele;
+	
+	private LegendeModeleTableTexte legendeChampAfficheParagrapheModele;
+	
+	private JPopupMenu popupChamp = new JPopupMenu();
+	
+	private JPopupMenu popupChampChaine = new JPopupMenu();
+	
+	private JPopupMenu popupChampParagraphe = new JPopupMenu();
+	
+	private final JCheckBox activehistogramme;
+	
+	private final Box listeGChaines;
+	
+	private JTable ResultatStat;
+	
+	private final HashSet<GChaines> suiteGChaines = new HashSet<>();
+	
+	private final String[] statpossibles = new String[] { "Répartition des références par paragraphe",
+			"Répartition des paragraphes par référence", "Répartition des paragraphe par valeur du champ",
+			"Répartition des valeurs du champ par paragraphe", "Répartition des valeurs de champ par référence",
+			"Répartition des références par valeur de champ", "Répartition par paragraphe et par réfences "
+					+ "des valeurs du champ", "Répartition par paragraphe et par valeur du champ des références",
+			"Répartition par référence et par valeur de champ des paragraphes" };
+	
+	
+	public VisuCoref(Container fenetre, Vue vue, PanneauEditeur pEditeur) {
+		super("Analyse d'une chaine de coréférence");
+		Point pos = new Point(fenetre.getX() + 20, fenetre.getY() + 20);
+		Dimension dim = new Dimension(fenetre.getWidth(), fenetre.getHeight());
+		setLocation(pos);
+		setSize(dim);
+		this.vue = vue;
+		vue.addEventListener(this);
+		saisieTypeChaines = new TypeComboBox(Schema.class);
+		saisieTypeChaines.setModele(vue.getTypesSchemasAVoir());
+		saisieTypeChaines.addActionListener(this);
+		saisieTypeUnites = new TypeComboBox(Unite.class);
+		saisieTypeUnites.setModele(vue.getTypesUnitesAVoir());
+		saisieTypeUnites.addActionListener(this);
+		saisieChampAffiche = new Val0ComboBox("Nombre de chaînons");
+		saisieChampAffiche.addActionListener(this);
+		saisieChampChaine = new Val0ComboBox("Rien");
+		saisieChampChaine.addActionListener(this);
+		saisieChampStatistique = new Val0ComboBox("Rien");
+		saisieChampStatistique.addActionListener(this);
+		Box commandes = Box.createVerticalBox();
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Chaînes : "));
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(saisieTypeChaines);
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Unites : "));
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(saisieTypeUnites);
+		commandes.add(Box.createVerticalGlue());
+		activehistogramme = new JCheckBox("Afficher les histogrammes de répartition");
+		commandes.add(activehistogramme);
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Champ à filtrer : "));
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(saisieChampAffiche);
+		commandes.add(Box.createVerticalGlue());
+		
+		legendeChampAffiche = new JTable();
+		legendeChampAffiche.addMouseListener(new MouseAdapter() {
+			
+			@Override
+			public void mousePressed(MouseEvent e) {// on gère les évènements de la souris
+				check(e);
+			}
+			
+			@Override
+			public void mouseReleased(MouseEvent e) {
+				check(e);
+			}
+			
+			public void check(MouseEvent e) {
+				if (e.isPopupTrigger()) {// if the event shows the menu
+					popupChampInit(legendeChampAffiche.rowAtPoint(e.getPoint()));
+					popupChamp.show(legendeChampAffiche, e.getX(), e.getY());
+				}
+			}
+		});
+		
+		commandes.add(legendeChampAffiche);
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Champ de la chaine à analyser : "));
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(saisieChampChaine);
+		commandes.add(Box.createVerticalGlue());
+		
+		legendeChampAfficheParagraphe = new JTable();
+		// legendeChampAfficheParagraphe.setCellRenderer(new LegendeCellRenderer());
+		legendeChampAfficheParagraphe.addMouseListener(new MouseAdapter() {
+			
+			@Override
+			public void mousePressed(MouseEvent e) {// on gère les évènements de la souris
+				check(e);
+			}
+			
+			@Override
+			public void mouseReleased(MouseEvent e) {
+				check(e);
+			}
+			
+			public void check(MouseEvent e) {
+				if (e.isPopupTrigger()) {// if the event shows the menu
+					popupChampInitParagraphe(legendeChampAfficheParagraphe.rowAtPoint(e.getPoint()));
+					popupChampParagraphe.show(legendeChampAfficheParagraphe, e.getX(), e.getY());
+				}
+			}
+		});
+		
+		
+		
+		legendeChampAfficheChaine = new JTable();
+		// legendeChampAfficheChaine.setCellRenderer(new LegendeCellRenderer());
+		legendeChampAfficheChaine.addMouseListener(new MouseAdapter() {
+			
+			@Override
+			public void mousePressed(MouseEvent e) {// on gère les évènements de la souris
+				check(e);
+			}
+			
+			@Override
+			public void mouseReleased(MouseEvent e) {
+				check(e);
+			}
+			
+			public void check(MouseEvent e) {
+				if (e.isPopupTrigger()) {// if the event shows the menu
+					popupChampInitChaine(legendeChampAfficheChaine.rowAtPoint(e.getPoint()));
+					popupChampChaine.show(legendeChampAfficheChaine, e.getX(), e.getY());
+				}
+			}
+		});
+		commandes.add(legendeChampAfficheChaine);
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Paragraphe à filtrer : "));
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(legendeChampAfficheParagraphe);
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Sélectionner une statistique : "));
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(saisieChampStatistique);
+		JScrollPane scrollLegende = new JScrollPane(commandes);
+		listeGChaines = Box.createVerticalBox();
+		JScrollPane scrollList = new JScrollPane(listeGChaines);
+		Box resultatstat = Box.createVerticalBox();
+		resultatstat.add(Box.createVerticalGlue());
+		resultatstat.add(new JLabel("Statistique : "));
+		resultatstat.add(Box.createVerticalGlue());
+		ResultatStat = new JTable(new ModeleStatChaine());
+		JScrollPane jsp = new JScrollPane(ResultatStat);
+		resultatstat.add(ResultatStat.getTableHeader());
+		resultatstat.add(jsp);
+		JScrollPane scrollstatresultat = new JScrollPane(resultatstat);
+		JSplitPane split1 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollList, scrollstatresultat);
+		JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollLegende, split1);
+		getContentPane().add(split);
+		setVisible(true);
+		split.setDividerLocation(1. / 3);
+		split1.setDividerLocation(1. / 2);
+		setJMenuBar(menuBar);
+		JMenu corpusMenu = new JMenu("Paramètres d'affichage");
+		menuBar.add(corpusMenu);
+		corpusMenu.add(new GAction("Reprendre un affichage") {
+			
+			@Override
+			public void executer() {
+				importerAffichage();
+			}
+		});
+		corpusMenu.add(new GAction("Sauver les paramètres d'affichage") {
+			
+			@Override
+			public void executer() {
+				exporterAffichage();
+			}
+		});
+		JMenu csvMenu = new JMenu("Exporter les données");
+		final VisuCoref visu = this;
+		final Vue vues = this.vue;
+		final PanneauEditeur pEditeurs = pEditeur;
+		menuBar.add(csvMenu);
+		csvMenu.add(new GAction("Exporter les données de filtrage") {
+			
+			@Override
+			public void executer() {
+				new ExportCSV(getContentPane(), vues, pEditeurs, visu);
+			}
+		});
+		csvMenu.add(new GAction("Exporter le tableau statistique") {
+			
+			@Override
+			public void executer() {
+				Object[][] donneesCSV = new Object[ResultatStat.getRowCount() + 1][ResultatStat.getColumnCount()];
+				for (int i = 0; i < ResultatStat.getRowCount(); i++) {
+					for (int j = 0; j < ResultatStat.getColumnCount(); j++) {
+						donneesCSV[i + 1][j] = ResultatStat.getValueAt(i, j);
+					}
+				}
+				for (int j = 0; j < ResultatStat.getColumnCount(); j++) {
+					donneesCSV[0][j] = ResultatStat.getColumnName(j);
+				}
+				
+				ExportCSV.exporterCSV(donneesCSV);
+			}
+		});
+		csvMenu.add(new GAction("Exporter les fréquences pour le champ des unités") {
+			
+			@Override
+			public void executer() {
+				Object[][] donneesCSV = new Object[legendeChampAffiche.getRowCount() + 1][2];
+				for (int i = 0; i < legendeChampAffiche.getRowCount(); i++) {
+					donneesCSV[i + 1][0] = legendeChampAffiche.getValueAt(i, 1);
+					donneesCSV[i + 1][1] = legendeChampAffiche.getValueAt(i, 2) == null ? "0"
+							: legendeChampAffiche.getValueAt(i, 2);
+				}
+				donneesCSV[0][1] = "frequence";
+				donneesCSV[0][0] = saisieChampAffiche.pasdeSelection() ? "Nombre de Chainons"
+						: saisieChampAffiche.getSelection();
+				ExportCSV.exporterCSV(donneesCSV);
+			}
+		});
+		csvMenu.add(new GAction("Exporter les fréquences pour le champ des chaines") {
+			
+			@Override
+			public void executer() {
+				if (!saisieChampChaine.pasdeSelection()) {
+					Object[][] donneesCSV = new Object[legendeChampAfficheChaine.getRowCount() + 1][2];
+					for (int i = 0; i < legendeChampAfficheChaine.getRowCount(); i++) {
+						donneesCSV[i + 1][0] = legendeChampAfficheChaine.getValueAt(i, 1);
+						donneesCSV[i + 1][1] = legendeChampAfficheChaine.getValueAt(i, 2) == null ? "0"
+								: legendeChampAfficheChaine.getValueAt(i, 2);
+					}
+					donneesCSV[0][1] = "frequence";
+					donneesCSV[0][0] = saisieChampChaine.getSelection();
+					ExportCSV.exporterCSV(donneesCSV);
+				}
+			}
+		});
+		JMenu typeMenu = new JMenu("Fusionner des types d'unités");
+		menuBar.add(typeMenu);
+		final Vue vueconv = vue;
+		typeMenu.add(new GAction("Fusionner tous les types") {
+			
+			@Override
+			public void executer() {
+				JOptionPane jop = new JOptionPane();
+				int option = jop.showConfirmDialog(null, "Voulez-créer un nouveau type rassemblant tous les autres ?"
+						+ System.getProperty("line.separator") + "Si oui, la fenêtre de visualisation des chaines se fermera pour mettre à jour les annotations.", "Création d'un type d'unités",
+						JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
+				
+				if (option == JOptionPane.OK_OPTION) {
+					ChaineUtil.fusionTypeUnite(vueconv);
+					fermerFenetre();
+				}
+			}
+		});
+		saisieTypeChaines.setAlignmentX(0);
+		saisieTypeUnites.setAlignmentX(0);
+		saisieChampAffiche.setAlignmentX(0);
+		saisieChampChaine.setAlignmentX(0);
+		saisieChampStatistique.setAlignmentX(0);
+		legendeChampAffiche.setAlignmentX(0);
+		legendeChampAfficheChaine.setAlignmentX(0);
+		legendeChampAfficheParagraphe.setAlignmentX(0);
+		
+		// Fermeture de la fenêtre
+		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+		addWindowListener(new WindowAdapter() {
+			
+			@Override
+			public void windowClosing(WindowEvent evt) {
+				fermerFenetre();
+			}
+		});
+		donneesChaines = new ModeleChaines(vue, new GChaines(this));
+		if (saisieTypeChaines.nbItems() == 1) {
+			saisieTypeChaines.setSelection(0);
+			if (saisieTypeUnites.nbItems() == 1) saisieTypeUnites.setSelection(0);
+			else saisieTypeUnites.effSelection();
+		}
+		else {
+			saisieTypeChaines.effSelection();
+			saisieTypeUnites.effSelection();
+		}
+	}
+	
+	private void fermerFenetre() {
+		vue.removeEventListener(this);
+		dispose();
+	}
+	
+	@Override
+	public void traiterEvent(Message evt) { // très grossier : à améliorer
+		switch (evt.getType()) {
+			case CLEAR_CORPUS:
+				fermerFenetre();
+				return;
+			case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+				throw new UnsupportedOperationException("Fenêtre chaines présente lors d'un message NEW_CORPUS ???");
+			case MODIF_TEXTE:
+				fermerFenetre();
+				return;
+			case MODIF_VUE:
+				fermerFenetre();
+				return;
+			case MODIF_STRUCTURE:
+				fermerFenetre();
+				return;
+			case MODIF_ELEMENT:
+				// ElementEvent evtE = (ElementEvent) evt;
+				// if (evtE.getModif() != TypeModifElement.BORNES_UNITE) fermerFenetre();
+				fermerFenetre();
+				return;
+			case CORPUS_SAVED:
+				fermerFenetre();
+				return;
+			default:
+				throw new UnsupportedOperationException("Cas " + evt.getType() + " oublié dans un switch");
+		}
+	}
+	
+	@Override
+	public void actionPerformed(ActionEvent evt) {
+		try {
+			if (evt.getSource().equals(saisieTypeChaines)
+					|| evt.getSource().equals(saisieTypeUnites)) {
+				if (saisieTypeChaines.pasdeSelection() || saisieTypeUnites.pasdeSelection()) {
+					initVide();
+					return;
+				}
+				try {
+					init();
+				}
+				catch (UnsupportedOperationException ex) {
+					GMessages.impossibiliteAction("Erreur de type : " + ex.getMessage());
+					initVide();
+					return;
+				}
+				return;
+			}
+			if (evt.getSource().equals(saisieChampAffiche)) {
+				if (!saisieTypeChaines.pasdeSelection() && !saisieTypeUnites.pasdeSelection()) {
+					if (saisieChampAffiche.pasdeSelection()) initCouleursNbElts();
+					else initCouleursChamp(saisieChampAffiche.getSelection());
+					afficherchaines();
+				}
+				return;
+			}
+			if (evt.getSource().equals(saisieChampChaine)) {
+				initChaineChamp();
+				afficherchaines();
+				return;
+			}
+			if (evt.getSource().equals(saisieChampStatistique)) {
+				afficherstat();
+				return;
+			}
+			throw new UnsupportedOperationException("Evénement non prévu : " + evt.paramString());
+		}
+		catch (Throwable ex) {
+			GMessages.erreurFatale(ex);
+		}
+	}
+	
+	private void initVide() {
+		donneesChaines.permettreaffichage(false);
+		typeChaines = null;
+		typeUnites = null;
+		donneesChaines.initVide();
+		saisieChampAffiche.setModeleVide();
+		saisieChampChaine.setModeleVide();
+		saisieChampStatistique.setModeleVide();
+		legendeChampAfficheModele = new LegendeModeleTable(new String[] { "icone", "nom du champ" }, new LegendeLabel[0], new HashMap());
+		legendeChampAffiche.setModel(legendeChampAfficheModele);
+		legendeChampAfficheChaineModele = new LegendeModeleTableTexte(new String[] { "Affiché", "nom du champ", "frequence" }, new LegendeLabel[0], new HashMap());
+		legendeChampAfficheChaine.setModel(legendeChampAfficheChaineModele);
+		legendeChampAfficheParagrapheModele = new LegendeModeleTableTexte(new String[] { "Affiché", "nom du champ", "frequence" }, new LegendeLabel[0], new HashMap());
+		legendeChampAfficheParagraphe.setModel(legendeChampAfficheParagrapheModele);
+	}
+	
+	private void init() throws UnsupportedOperationException {
+		donneesChaines.permettreaffichage(false);
+		typeChaines = saisieTypeChaines.getTypeSelection();
+		typeUnites = saisieTypeUnites.getTypeSelection();
+		donneesChaines.init(typeChaines, typeUnites, seuilsValsNbElts);
+		initParagraphechamp();
+		initCouleursNbElts();
+		afficherchaines();
+		saisieChampAffiche.removeActionListener(this);
+		saisieChampAffiche.setModele(vue.getNomsChamps(Unite.class, typeUnites));
+		saisieChampAffiche.addActionListener(this);
+		saisieChampChaine.removeActionListener(this);
+		saisieChampChaine.setModele(vue.getNomsChamps(Schema.class, typeChaines));
+		saisieChampChaine.addActionListener(this);
+		saisieChampStatistique.removeActionListener(this);
+		saisieChampStatistique.setModele(statpossibles);
+		saisieChampStatistique.addActionListener(this);
+		// histochaine.changeHistogramme(donneesChaines.dispositionunites(10),Color.BLUE,this,200);
+		// initstat();
+		
+	}
+	
+	private void initCouleursNbElts() {
+		if (!saisieChampChaine.pasdeSelection()) {
+			donneesChaines.setChampAfficheNbElts(couleursNbElts);
+		}
+		if (!donneesChaines.peutetreafficher()) {
+			HashMap<String, Float> freq = donneesChaines.calculerfrequencenbelt(ChaineUtil.filtreparagraphe(saisieChampChaine.pasdeSelection() ? donneesChaines.getUnites()
+					: donneesChaines.filtrechaine(donneesChaines.getUnites(), saisieChampChaine.getSelection(),
+							valsAffichees1cachees), noparagraphecachees, vue), typeUnites, labelsNbElements);
+			legendeChampAfficheModele = new LegendeModeleTable(new String[] { "icone", "nom du champ", "frequence" },
+					creerLegendesNbElements(), freq);
+			legendeChampAffiche.setModel(legendeChampAfficheModele);
+			legendeChampAffiche.getColumnModel().getColumn(0).setMaxWidth(50);
+			legendeChampAffiche.getColumnModel().getColumn(2).setMaxWidth(50);
+			legendeChampAffiche.setRowHeight(30);
+		}
+	}
+	
+	private LegendeLabel[] creerLegendesNbElements() {
+		LegendeLabel[] legendes = new LegendeLabel[couleursNbElts.length];
+		for (int i = 0; i < legendes.length; i++)
+			legendes[i] = new LegendeLabel(labelsNbElements[i],
+					donneesChaines.isMasqueeValNbElements(i) ? null : couleursNbElts[i]);
+		return legendes;
+	}
+	
+	private void initCouleursChamp(String champ) {
+		valsAffichees = vue.getValeursChamp(Unite.class, typeUnites, champ);
+		HashMap<String, Color> couleursValeursChamp = new HashMap<>();
+		for (int i = 0, nocolor = 0; i < valsAffichees.length; i++)
+			if (!donneesChaines.isMasqueeValChamp(champ, valsAffichees[i]))
+				couleursValeursChamp.put(valsAffichees[i], GVisu.getCouleur(nocolor++));
+		if (!donneesChaines.isMasqueeValNulleChamp(champ))
+			couleursValeursChamp.put("", GVisu.getCouleurSansValeur());
+		donneesChaines.setChampAffiche(champ, couleursValeursChamp);
+		if (!donneesChaines.peutetreafficher()) {
+			HashMap<String, Float> freq = ChaineUtil.calculerfrequencechamp(ChaineUtil.filtreparagraphe(saisieChampChaine.pasdeSelection() ? donneesChaines.getUnites()
+					: donneesChaines.filtrechaine(donneesChaines.getUnites(), saisieChampChaine.getSelection(),
+							valsAffichees1cachees), noparagraphecachees, vue), typeUnites, champ, vue);
+			ChaineUtil.triFusionMap(valsAffichees, freq);
+			legendeChampAfficheModele = new LegendeModeleTable(new String[] { "icone", "nom du champ", "frequence" },
+					creerLegendesChamp(valsAffichees, couleursValeursChamp), freq);
+			legendeChampAffiche.setModel(legendeChampAfficheModele);
+			legendeChampAffiche.getColumnModel().getColumn(0).setMaxWidth(50);
+			legendeChampAffiche.getColumnModel().getColumn(2).setMaxWidth(50);
+			legendeChampAffiche.setRowHeight(30);
+		}
+	}
+	
+	private LegendeLabel[] creerLegendesChamp(String[] valsAffichees,
+			HashMap<String, Color> couleursValeursChamp) {
+		LegendeLabel[] legendes = new LegendeLabel[valsAffichees.length + 1];
+		for (int i = 0; i < valsAffichees.length; i++)
+			legendes[i] = new LegendeLabel(valsAffichees[i],
+					couleursValeursChamp.get(valsAffichees[i]));
+		legendes[valsAffichees.length] = new LegendeLabel("<aucune valeur>",
+				couleursValeursChamp.get(""));
+		return legendes;
+	}
+	
+	// initialise la Jlist des paragraphes
+	private void initParagraphechamp() {
+		valsAffichees2 = donneesChaines.listenumeroparagraphe();
+		LegendeLabel[] legende = new LegendeLabel[valsAffichees2.length];
+		for (int i = 0; i < valsAffichees2.length; i++) {
+			int debutParagraphe = valsAffichees2[i] - 2 < 0 ? 0 : vue.getCorpus().getFinParagraphes()[valsAffichees2[i] - 2];
+			// on enlève 2 au paragraphe car quand on cherche le début d'un paragraphe on cherche la fin du précédent
+			// et de plus les paragraphes commencent à 1 quand les index de tableau commencent à 1
+			int longueur = debutParagraphe < vue.getCorpus().getTexte().length() - 20 ? 20 : vue.getCorpus().getTexte().length() - debutParagraphe;
+			if (noparagraphecachees.contains(valsAffichees2[i])) {
+				legende[i] = new LegendeLabel("Paragraphe" + valsAffichees2[i].toString() + "  \"" +
+						vue.getCorpus().getTexte().substring(debutParagraphe, debutParagraphe + longueur) + "\"", "Non");
+			}
+			else {
+				legende[i] = new LegendeLabel("Paragraphe" + valsAffichees2[i].toString() + "  \"" +
+						vue.getCorpus().getTexte().substring(debutParagraphe, debutParagraphe + longueur) + "\"", "Oui");
+			}
+		}
+		if (!donneesChaines.peutetreafficher()) {
+			legendeChampAfficheParagrapheModele = new LegendeModeleTableTexte(new String[] { "Affiché", "Paragraphe" }, legende, null);
+			legendeChampAfficheParagraphe.setModel(legendeChampAfficheParagrapheModele);
+			legendeChampAfficheParagraphe.getColumnModel().getColumn(0).setMaxWidth(50);
+		}
+	}
+	
+	// initialise la legende des valeurs de la Chaine
+	private void initChaineChamp() {
+		if (!donneesChaines.peutetreafficher()) {
+			valsAffichees1 = vue.getValeursChamp(Schema.class, typeChaines, saisieChampChaine.getSelection());
+			LegendeLabel[] legende = new LegendeLabel[valsAffichees1.length];
+			HashMap<String, Float> freq;
+			freq = donneesChaines.calculerfrequencechaine(ChaineUtil.filtreparagraphe(donneesChaines.getUnites(), noparagraphecachees, vue), typeChaines, saisieChampChaine.getSelection(),
+					valsAffichees1cachees);
+			ChaineUtil.triFusionMap(valsAffichees1, freq);
+			for (int i = 0; i < valsAffichees1.length; i++) {
+				if (valsAffichees1cachees.contains(valsAffichees1[i])) {
+					legende[i] = new LegendeLabel(valsAffichees1[i].toString(), "Non");
+				}
+				else {
+					legende[i] = new LegendeLabel(valsAffichees1[i].toString(), "Oui");
+				}
+			}
+			legendeChampAfficheChaineModele = new LegendeModeleTableTexte(new String[] { "Affiché", "Paragraphe", "frequence" }, legende, freq);
+			legendeChampAfficheChaine.setModel(legendeChampAfficheChaineModele);
+			legendeChampAfficheChaine.getColumnModel().getColumn(0).setMaxWidth(50);
+			legendeChampAfficheChaine.getColumnModel().getColumn(2).setMaxWidth(50);
+		}
+	}
+	
+	
+	private void popupChampInit(final int index) {
+		final boolean masquee;
+		String[] vals = valsAffichees;
+		Val0ComboBox zonedesaisie = saisieChampAffiche;
+		JPopupMenu popup = popupChamp;
+		popup.removeAll();
+		if (zonedesaisie.pasdeSelection()) {
+			masquee = donneesChaines.isMasqueeValNbElements(index);
+			popup.add(new GAction(masquee ? "Montrer cette valeur" : "Masquer cette valeur") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValNbElements(masquee, index, false);
+				}
+			});
+			popup.add(new GAction(masquee ? "Montrer toutes les valeurs" : "Ne montrer que cette valeur") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValNbElements(masquee, index, true);
+				}
+			});
+		}
+		else if (index == vals.length) {
+			masquee = donneesChaines.isMasqueeValNulleChamp(zonedesaisie.getSelection());
+			popup.add(new GAction(masquee ? "Montrer cette valeur" : "Masquer cette valeur") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValNulleChamp(masquee, false);
+				}
+			});
+			popup.add(new GAction(masquee ? "Montrer toutes les valeurs" : "Ne montrer que cette valeur") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValNulleChamp(masquee, true);
+				}
+			});
+		}
+		else {
+			masquee = donneesChaines.isMasqueeValChamp(zonedesaisie.getSelection(),
+					vals[index]);
+			popup.add(new GAction(masquee ? "Montrer cette valeur" : "Masquer cette valeur") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValChamp(masquee, index, false);
+				}
+			});
+			popup.add(new GAction(masquee ? "Montrer toutes les valeurs" : "Ne montrer que cette valeur") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValChamp(masquee, index, true);
+				}
+			});
+		}
+		
+	}
+	
+	private void modifierStatutValChamp(boolean masquee, int index, boolean tous) {
+		String[] vals;
+		Val0ComboBox zonedesaisie;
+		vals = valsAffichees;
+		zonedesaisie = saisieChampAffiche;
+		if (!tous) donneesChaines.masquerValChamp(!masquee,
+				zonedesaisie.getSelection(), vals[index]);
+		else if (masquee) donneesChaines.demasquerToutesValsChamp(
+				zonedesaisie.getSelection());
+		else donneesChaines.masquerAutresValsChamp(typeUnites,
+				zonedesaisie.getSelection(), vals[index]);
+		if (!saisieChampChaine.pasdeSelection()) {
+			if (saisieChampAffiche.pasdeSelection()) {
+				initCouleursNbElts();
+			}
+			else {
+				initCouleursChamp(saisieChampAffiche.getSelection());
+			}
+		}
+		afficherchaines();
+	}
+	
+	private void modifierStatutValNulleChamp(boolean masquee, boolean tous) {
+		Val0ComboBox zonedesaisie;
+		zonedesaisie = saisieChampAffiche;
+		if (!tous) donneesChaines.masquerValNulleChamp(!masquee, zonedesaisie.getSelection());
+		else if (masquee) donneesChaines.demasquerToutesValsChamp(
+				zonedesaisie.getSelection());
+		else donneesChaines.masquerValsNonNullesChamp(typeUnites,
+				zonedesaisie.getSelection());
+		if (!saisieChampChaine.pasdeSelection()) {
+			if (saisieChampAffiche.pasdeSelection()) {
+				initCouleursNbElts();
+			}
+			else {
+				initCouleursChamp(saisieChampAffiche.getSelection());
+			}
+		}
+		afficherchaines();
+	}
+	
+	private void modifierStatutValNbElements(boolean masquee, int index, boolean tous) {
+		Val0ComboBox zonedesaisie;
+		zonedesaisie = saisieChampAffiche;
+		if (!tous) donneesChaines.masquerValNbElements(!masquee, index);
+		else if (masquee) donneesChaines.demasquerToutesValsNbElts(
+				zonedesaisie.getSelection());
+		else donneesChaines.masquerAutresValsNbElts(
+				zonedesaisie.getSelection(), index);
+		if (!saisieChampChaine.pasdeSelection()) {
+			if (saisieChampAffiche.pasdeSelection()) {
+				initCouleursNbElts();
+			}
+			else {
+				initCouleursChamp(saisieChampAffiche.getSelection());
+			}
+		}
+		afficherchaines();
+	}
+	
+	public void afficherchaines() {
+		donneesChaines.permettreaffichage(true);
+		this.suiteGChaines.clear();
+		listeGChaines.removeAll();
+		if (!saisieChampChaine.pasdeSelection() && !saisieTypeChaines.pasdeSelection()
+				&& !saisieTypeUnites.pasdeSelection()) {
+			for (String val : valsAffichees1) { // pour toutes les valeurs de la propriété de la chaine
+				if (!valsAffichees1cachees.contains(val)) {
+					listeGChaines.add(Box.createVerticalGlue());
+					GChaines graphique = new GChaines(this);
+					donneesChaines.setGChaine(graphique);
+					donneesChaines.modifMasqueValsChampChaine(saisieTypeChaines.getSelection(), saisieTypeUnites.getSelection(), noparagraphecachees, saisieChampChaine.getSelection(),
+							val);
+					if (!saisieChampAffiche.pasdeSelection()) {
+						initCouleursChamp(saisieChampAffiche.getSelection());
+					}
+					else {
+						initCouleursNbElts();
+					}
+					listeGChaines.add(new JLabel(val + " :"));
+					listeGChaines.add(graphique);
+					suiteGChaines.add(graphique);
+					if (activehistogramme.isSelected()) {
+						ChartPanel histochaine = Histogramme.histogrammeFactory();
+						Histogramme.updatePanel(histochaine, "Répartion des unités", donneesChaines, 10, Color.blue, 200,
+								"position de l'unité", "Fréquence d'unités", vue);
+						histochaine.setMaximumSize(new Dimension(550, 300));
+						listeGChaines.add(histochaine);
+					}
+				}
+			}
+		}
+		donneesChaines.permettreaffichage(false);
+		GChaines graphique = new GChaines(this);
+		donneesChaines.setGChaine(graphique);
+		donneesChaines.modifMasqueVals(saisieTypeChaines.getSelection(), saisieTypeUnites.getSelection());
+		if (!saisieChampChaine.pasdeSelection()) {
+			if (saisieChampAffiche.pasdeSelection()) {
+				initCouleursNbElts();
+			}
+			else {
+				initCouleursChamp(saisieChampAffiche.getSelection());
+			}
+			initChaineChamp();
+			initParagraphechamp();
+		}
+		afficherstat();
+		listeGChaines.revalidate();
+		listeGChaines.repaint();
+	}
+	
+	private void popupChampInitChaine(final int index) {
+		final boolean masquee;
+		Val0ComboBox zonedesaisie = saisieChampChaine;
+		JPopupMenu popup = popupChampChaine;
+		popup.removeAll();
+		if (zonedesaisie.pasdeSelection()) {
+		}
+		else {
+			masquee = valsAffichees1cachees.contains(valsAffichees1[index]);
+			popup.add(new GAction(masquee ? "Montrer cette valeur de la chaine" : "Masquer cette valeur de la chaine") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValChampChaine(masquee, index, false);
+				}
+			});
+			popup.add(new GAction(masquee ? "Montrer toutes les valeurs de la chaine" : "Ne montrer que cette valeur de la chaine") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValChampChaine(masquee, index, true);
+				}
+			});
+		}
+		
+	}
+	
+	private void modifierStatutValChampChaine(boolean masquee, int index, boolean tous) {
+		if (!tous) {
+			if (masquee) {
+				valsAffichees1cachees.remove(valsAffichees1[index]);
+			}
+			else {
+				valsAffichees1cachees.add(valsAffichees1[index]);
+			}
+		}
+		else if (masquee) {
+			valsAffichees1cachees.clear();
+		}
+		else {
+			valsAffichees1cachees.clear();
+			for (String valeur : valsAffichees1) {
+				if (!valeur.equals(valsAffichees1[index])) {
+					valsAffichees1cachees.add(valeur);
+				}
+			}
+			
+		}
+		initChaineChamp();
+		if (!saisieChampChaine.pasdeSelection()) {
+			afficherchaines();
+		}
+	}
+	
+	private void popupChampInitParagraphe(final int index) {
+		final boolean masquee;
+		Val0ComboBox zonedesaisie = saisieChampChaine;
+		JPopupMenu popup = popupChampParagraphe;
+		popup.removeAll();
+		if (zonedesaisie.pasdeSelection()) {
+		}
+		else {
+			masquee = noparagraphecachees.contains(valsAffichees2[index]);
+			popup.add(new GAction(masquee ? "Montrer ce paragraphe" : "Masquer ce paragraphe") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValChampParagraphe(masquee, index, false);
+				}
+			});
+			popup.add(new GAction(masquee ? "Montrer tous les paragraphes" : "Ne montrer que ce paragraphe") {
+				
+				@Override
+				public void executer() {
+					modifierStatutValChampParagraphe(masquee, index, true);
+				}
+			});
+		}
+		
+	}
+	
+	private void modifierStatutValChampParagraphe(boolean masquee, int index, boolean tous) {
+		if (!tous) { // on masque ou demasque un paragraphe
+			if (masquee) {
+				noparagraphecachees.remove(valsAffichees2[index]);
+			}
+			else {
+				noparagraphecachees.add(valsAffichees2[index]);
+			}
+		}
+		else if (masquee) { // on demasque tous les paragraphes
+			noparagraphecachees.clear();
+		}
+		else { // on masque tous les autres paragraphes
+			noparagraphecachees.clear();
+			for (Integer numero : valsAffichees2) {
+				if (numero.intValue() != valsAffichees2[index]) {
+					noparagraphecachees.add(numero);
+				}
+			}
+		}
+		initParagraphechamp();
+		if (!saisieChampChaine.pasdeSelection()) {
+			afficherchaines();
+		}
+	}
+	
+	public void afficherstat() {
+		if (!saisieChampStatistique.pasdeSelection() && !saisieChampChaine.pasdeSelection()
+				&& !saisieTypeChaines.pasdeSelection() && !saisieTypeUnites.pasdeSelection()) {
+			ModeleStatChaine Modelestat = (ModeleStatChaine) ResultatStat.getModel();
+			String typeChampColonne;
+			String[] typeChampLigne;
+			switch (saisieChampStatistique.getSelection()) {
+				case "Répartition des références par paragraphe":
+					
+					typeChampColonne = "Chaine";
+					typeChampLigne = new String[1];
+					typeChampLigne[0] = "Paragraphe";
+					Modelestat = ModeleStatChaine.calculateStatCoref(saisieChampChaine.getSelection(), saisieChampAffiche.getSelection(),
+							valsAffichees1cachees, typeChampColonne, typeChampLigne, vue,
+							donneesChaines, noparagraphecachees, typeChaines, typeUnites, labelsNbElements);
+					break;
+				case "Répartition des paragraphes par référence":
+					
+					typeChampColonne = "Paragraphe";
+					typeChampLigne = new String[1];
+					typeChampLigne[0] = "Chaine";
+					Modelestat = ModeleStatChaine.calculateStatCoref(saisieChampChaine.getSelection(), saisieChampAffiche.getSelection(),
+							valsAffichees1cachees, typeChampColonne, typeChampLigne, vue,
+							donneesChaines, noparagraphecachees, typeChaines, typeUnites, labelsNbElements);
+					break;
+				case "Répartition des paragraphe par valeur du champ":
+					
+					typeChampColonne = "Paragraphe";
+					typeChampLigne = new String[1];
+					typeChampLigne[0] = "Unite";
+					Modelestat = ModeleStatChaine.calculateStatCoref(saisieChampChaine.getSelection(), saisieChampAffiche.getSelection(),
+							valsAffichees1cachees, typeChampColonne, typeChampLigne, vue,
+							donneesChaines, noparagraphecachees, typeChaines, typeUnites, labelsNbElements);
+					break;
+				case "Répartition des valeurs du champ par paragraphe":
+					
+					typeChampColonne = "Unite";
+					typeChampLigne = new String[1];
+					typeChampLigne[0] = "Paragraphe";
+					Modelestat = ModeleStatChaine.calculateStatCoref(saisieChampChaine.getSelection(), saisieChampAffiche.getSelection(),
+							valsAffichees1cachees, typeChampColonne, typeChampLigne, vue,
+							donneesChaines, noparagraphecachees, typeChaines, typeUnites, labelsNbElements);
+					break;
+				case "Répartition des valeurs de champ par référence":
+					
+					typeChampColonne = "Unite";
+					typeChampLigne = new String[1];
+					typeChampLigne[0] = "Chaine";
+					Modelestat = ModeleStatChaine.calculateStatCoref(saisieChampChaine.getSelection(), saisieChampAffiche.getSelection(),
+							valsAffichees1cachees, typeChampColonne, typeChampLigne, vue,
+							donneesChaines, noparagraphecachees, typeChaines, typeUnites, labelsNbElements);
+					break;
+				case "Répartition des références par valeur de champ":
+					
+					typeChampColonne = "Chaine";
+					typeChampLigne = new String[1];
+					typeChampLigne[0] = "Unite";
+					Modelestat = ModeleStatChaine.calculateStatCoref(saisieChampChaine.getSelection(), saisieChampAffiche.getSelection(),
+							valsAffichees1cachees, typeChampColonne, typeChampLigne, vue,
+							donneesChaines, noparagraphecachees, typeChaines, typeUnites, labelsNbElements);
+					break;
+				case "Répartition par paragraphe et par réfences des valeurs du champ":
+					
+					typeChampColonne = "Unite";
+					typeChampLigne = new String[2];
+					typeChampLigne[0] = "Chaine";
+					typeChampLigne[1] = "Paragraphe";
+					Modelestat = ModeleStatChaine.calculateStatCoref(saisieChampChaine.getSelection(), saisieChampAffiche.getSelection(),
+							valsAffichees1cachees, typeChampColonne, typeChampLigne, vue,
+							donneesChaines, noparagraphecachees, typeChaines, typeUnites, labelsNbElements);
+					break;
+				case "Répartition par paragraphe et par valeur du champ des références":
+					
+					typeChampColonne = "Chaine";
+					typeChampLigne = new String[2];
+					typeChampLigne[0] = "Unite";
+					typeChampLigne[1] = "Paragraphe";
+					Modelestat = ModeleStatChaine.calculateStatCoref(saisieChampChaine.getSelection(), saisieChampAffiche.getSelection(),
+							valsAffichees1cachees, typeChampColonne, typeChampLigne, vue,
+							donneesChaines, noparagraphecachees, typeChaines, typeUnites, labelsNbElements);
+					break;
+				case "Répartition par référence et par valeur de champ des paragraphes":
+					
+					typeChampColonne = "Paragraphe";
+					typeChampLigne = new String[2];
+					typeChampLigne[0] = "Chaine";
+					typeChampLigne[1] = "Unite";
+					Modelestat = ModeleStatChaine.calculateStatCoref(saisieChampChaine.getSelection(), saisieChampAffiche.getSelection(),
+							valsAffichees1cachees, typeChampColonne, typeChampLigne, vue,
+							donneesChaines, noparagraphecachees, typeChaines, typeUnites, labelsNbElements);
+					break;
+				default:
+					break;
+				
+			}
+			
+			ResultatStat.setModel(Modelestat);
+			ResultatStat.setAutoCreateRowSorter(true);
+			
+			for (int i = 0; i < ResultatStat.getColumnCount(); i++) {// on ajuste les tailles des cases du tableau
+				ResultatStat.getColumnModel().getColumn(i).setMinWidth(50);
+			}
+			ResultatStat.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+			
+		}
+	}
+	
+	public JTable getLegende() {
+		return this.legendeChampAffiche;
+	}
+	
+	public String getSelection(int taillepolice, int x, int y, String police) {
+		String retour = "";
+		if (saisieTypeChaines.pasdeSelection()) {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Type de Schéma : aucun" + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		else {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Type de Schéma : " + saisieTypeChaines.getSelection() + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		if (saisieTypeUnites.pasdeSelection()) {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 2 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Type d'Unités : aucun" + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		else {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 2 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Type d'Unités : " + saisieTypeUnites.getSelection() + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		if (saisieChampAffiche.pasdeSelection()) {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 4 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Champ 1 : nombre de Chainons" + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		else {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 4 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Champ 1 : " + saisieChampAffiche.getSelection() + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		if (saisieChampChaine.pasdeSelection()) {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 6 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Champ de la Chaine : aucun" + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		else {
+			retour = retour + "<text x=\"" + x + "\" y=\"" + (y + 6 * taillepolice) + "\""
+					+ " style=\" fill:black; stroke:black ;font-size:" + taillepolice + "px " + police + "\">" + "Champ de la Chaine : " + saisieChampChaine.getSelection() + ";" +
+					"</text>" + System.getProperty("line.separator") + System.getProperty("line.separator");
+		}
+		return retour;
+	}
+	
+	public void importerAffichage() {
+		HashMap<String, Object> Choix = FichiersJava.ouvrirChaineVue();
+		if (Choix != null && Choix.containsKey("choixCommande2") &&
+				Fichiers.getNomFichierCourant(Fichiers.TypeFichier.DOC_ANALEC).equals(Choix.get("nomFichier"))) {
+			HashMap<String, String> choixCommande = (HashMap<String, String>) Choix.get("choixCommande2");
+			
+			saisieTypeChaines.removeActionListener(this);
+			saisieTypeUnites.removeActionListener(this);
+			saisieTypeChaines.setSelectedItem(choixCommande.get("saisieTypeChaines"));
+			saisieTypeUnites.setSelectedItem(choixCommande.get("saisieTypeUnites"));
+			saisieTypeChaines.addActionListener(this);
+			saisieTypeUnites.addActionListener(this);
+			init();
+			
+			saisieChampChaine.removeActionListener(this);
+			saisieChampAffiche.removeActionListener(this);
+			saisieChampStatistique.removeActionListener(this);
+			donneesChaines.setValsMasqueesChamp((HashMap<String, HashSet<String>>) Choix.get("valmasquees"));
+			donneesChaines.setValsNbMasqueesChamp((boolean[]) Choix.get("valNbmasquees"));
+			donneesChaines.setValsNulleMasqueesChamp((HashSet<String>) Choix.get("valNullemasquees"));
+			this.valsAffichees1cachees = (HashSet<String>) Choix.get("valsAffichees1cachees");
+			this.noparagraphecachees = (ArrayList<Integer>) Choix.get("noparagraphecachees");
+			activehistogramme.setSelected(choixCommande.get("activehistogramme").equals("vrai"));
+			if (choixCommande.get("saisieChampAffiche") != null) {
+				saisieChampAffiche.setSelectedItem(choixCommande.get("saisieChampAffiche"));
+			}
+			else {
+				saisieChampAffiche.effSelection();
+			}
+			if (choixCommande.get("saisieChampChaine") != null) {
+				saisieChampChaine.setSelectedItem(choixCommande.get("saisieChampChaine"));
+			}
+			else {
+				saisieChampChaine.effSelection();
+			}
+			if (choixCommande.get("saisieChampStatistique") != null) {
+				saisieChampStatistique.setSelectedItem(choixCommande.get("saisieChampStatistique"));
+			}
+			else {
+				saisieChampStatistique.effSelection();
+			}
+			
+			saisieChampChaine.addActionListener(this);
+			saisieChampAffiche.addActionListener(this);
+			saisieChampStatistique.addActionListener(this);
+			
+			
+			if (saisieChampAffiche.pasdeSelection()) {
+				initCouleursNbElts();
+			}
+			else {
+				initCouleursChamp(saisieChampAffiche.getSelection());
+			}
+			initChaineChamp();
+			initParagraphechamp();
+			afficherchaines();
+			afficherstat();
+		}
+		else {
+			JOptionPane.showMessageDialog(null, "le fichier des paramètres d'affichage n'est pas destiné à cette fenêtre"
+					+ System.getProperty("line.separator") +
+					"ou à ce corpus", "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+		}
+		
+	}
+	
+	public void exporterAffichage() {
+		
+		HashMap<String, Object> Choix = new HashMap();
+		HashMap<String, String> choixCommande = new HashMap();
+		
+		choixCommande.put("saisieTypeChaines", saisieTypeChaines.pasdeSelection() ? null : saisieTypeChaines.getSelection());
+		choixCommande.put("saisieTypeUnites", saisieTypeUnites.pasdeSelection() ? null : saisieTypeUnites.getSelection());
+		choixCommande.put("saisieChampAffiche", saisieChampAffiche.pasdeSelection() ? null : saisieChampAffiche.getSelection());
+		choixCommande.put("saisieChampChaine", saisieChampChaine.pasdeSelection() ? null : saisieChampChaine.getSelection());
+		choixCommande.put("saisieChampStatistique", saisieChampStatistique.pasdeSelection() ? null : saisieChampStatistique.getSelection());
+		choixCommande.put("activehistogramme", activehistogramme.isSelected() ? "vrai" : "faux");
+		Choix.put("valmasquees", donneesChaines.getValsMasqueesChamp());
+		Choix.put("valNbmasquees", donneesChaines.getValsNbMasqueesChamp());
+		Choix.put("valNullemasquees", donneesChaines.getValsNulleMasqueesChamp());
+		Choix.put("valsAffichees1cachees", valsAffichees1cachees);
+		Choix.put("noparagraphecachees", noparagraphecachees);
+		Choix.put("choixCommande2", choixCommande);
+		Choix.put("nomFichier", Fichiers.getNomFichierCourant(Fichiers.TypeFichier.DOC_ANALEC));
+		FichiersJava.enregistrerChaineSous(Choix);
+	}
+	
+	public HashSet<GChaines> getSuiteGChaines() {
+		return this.suiteGChaines;
+	}
+	
+	public ModeleChaines getDonneesChaines() {
+		return this.donneesChaines;
+	}
+	
+	public Object[][] donneesCSV(boolean[] champ) {
+		ArrayList<Object[]> donnees = new ArrayList<>();
+		int nbchamp = 0;
+		for (boolean tmp : champ) {
+			if (tmp) {
+				nbchamp = nbchamp + 1;
+			}
+		}
+		// on crée les colonnes
+		if (champ.length == 3) {
+			Object[] titre = new Object[nbchamp + 1];
+			titre[0] = "unité";
+			int compteurTitre = 1;
+			for (int i = 0; i < champ.length; i++) {
+				if (champ[i]) {
+					switch (i) {
+						case 0:
+							titre[compteurTitre] = this.saisieChampAffiche.pasdeSelection() ? "Nombre de Chainons"
+									: this.saisieChampAffiche.getSelection();
+							break;
+						case 1:
+							titre[compteurTitre] = this.saisieChampChaine.pasdeSelection() ? ""
+									: this.saisieChampChaine.getSelection();
+							break;
+						case 2:
+							titre[compteurTitre] = "Numéro de paragraphe";
+							break;
+					}
+					compteurTitre = compteurTitre + 1;
+				}
+			}
+			donnees.add(titre);
+			for (GChaines chaine : this.suiteGChaines) {
+				for (int j = 0; j < chaine.chainons.length; j++) {
+					ModeleChaines.Chainon unit = chaine.chainons[j];
+					Object[] row = new Object[nbchamp + 1];
+					row[0] = unit.texte;
+					int compteur = 1;
+					for (int i = 0; i < champ.length; i++) {
+						if (champ[i]) {
+							switch (i) {
+								case 0:
+									row[compteur] = this.saisieChampAffiche.pasdeSelection() ? labelsNbElements[donneesChaines.calculerValNbElements(unit.nbEltsChaine)]
+											: vue.getValeurChamp(unit.unite, this.saisieChampAffiche.getSelection());
+									break;
+								case 1:
+									row[compteur] = this.saisieChampChaine.pasdeSelection() ? ""
+											: vue.getValeurChamp(unit.chaine, this.saisieChampChaine.getSelection());
+									break;
+								case 2:
+									row[compteur] = chaine.noSegments[j];
+									break;
+							}
+							compteur = compteur + 1;
+						}
+					}
+					donnees.add(row);
+				}
+			}
+		}
+		return donnees.toArray(new Object[donnees.size()][nbchamp + 1]);
+	}
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuCoref.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuStatGenerale.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuStatGenerale.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuStatGenerale.java	(revision 3653)
@@ -0,0 +1,766 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package visuAnalec.chaines;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import org.jfree.chart.ChartPanel;
+import visuAnalec.*;
+import visuAnalec.elements.*;
+import visuAnalec.fichiers.FichiersJava;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GMessages.GAction;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.util.GVisu.Val0ComboBox;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Marc
+ */
+public class VisuStatGenerale extends JFrame implements Vue.VueListener, ActionListener {
+	
+	private Vue vue;
+	
+	private ModeleChaines donneesChaines;
+	
+	private String[] typesChainesAffiches;
+	
+	private HashSet<String> typesChainesMasques = new HashSet();
+	
+	private Val0ComboBox saisieUniteComptage;
+	
+	private JList legendeTypeUnite;
+	
+	private Val0ComboBox saisieAxeOrdonnee;
+	
+	private Val0ComboBox saisieAxeAbscisse;
+	
+	private Val0ComboBox saisieModeAffichage;
+	
+	private JPopupMenu popupChamp = new JPopupMenu();
+	
+	private PanneauEditeur panneauEditeur;
+	
+	private Box listeStat = Box.createVerticalBox();
+	
+	private ChartPanel graphique;
+	
+	private JMenuBar menuBar = new JMenuBar();
+	
+	private String[] StatPossiblesAbscisses = new String[] { "Nombre de chainons", "Numéro de paragraphe" };
+	
+	private String[] StatPossiblesOrdonnees;
+	
+	private String[] ModesPossibles = new String[] { "Activer l'interpolation", "Désactiver l'affichage des valeurs nulles" };
+	
+	private Object[][] donneesGenerales = new Object[0][0];
+	
+	public VisuStatGenerale(Container fenetre, final Vue vue, PanneauEditeur pEditeur) {
+		super("Analyse générale du texte");
+		Point pos = new Point(fenetre.getX() + 20, fenetre.getY() + 20);
+		Dimension dim = new Dimension(fenetre.getWidth(), fenetre.getHeight());
+		setLocation(pos);
+		setSize(dim);
+		this.vue = vue;
+		vue.addEventListener(this);
+		typesChainesMasques = new HashSet();
+		this.panneauEditeur = pEditeur;
+		saisieUniteComptage = new Val0ComboBox("Caractère");
+		saisieUniteComptage.addActionListener(this);
+		saisieAxeOrdonnee = new Val0ComboBox("Rien");
+		saisieAxeOrdonnee.addActionListener(this);
+		saisieAxeAbscisse = new Val0ComboBox("Rien");
+		saisieAxeAbscisse.addActionListener(this);
+		saisieModeAffichage = new Val0ComboBox("Normal");
+		saisieModeAffichage.addActionListener(this);
+		Box commandes = Box.createVerticalBox();
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Statistiques : "));
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Selectionner une unité de comptage : "));
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(saisieUniteComptage);
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Type unité : "));
+		commandes.add(Box.createVerticalGlue());
+		
+		legendeTypeUnite = new JList();
+		legendeTypeUnite.addMouseListener(new MouseAdapter() {
+			
+			@Override
+			public void mousePressed(MouseEvent e) {// on gère les évènements de la souris
+				check(e);
+			}
+			
+			@Override
+			public void mouseReleased(MouseEvent e) {
+				check(e);
+			}
+			
+			public void check(MouseEvent e) {
+				if (e.isPopupTrigger()) {// if the event shows the menu
+					popupChampInit(legendeTypeUnite.locationToIndex(e.getPoint()));
+					popupChamp.show(legendeTypeUnite, e.getX(), e.getY());
+				}
+			}
+		});
+		commandes.add(legendeTypeUnite);
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Ordonnée : "));
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(saisieAxeOrdonnee);
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Abscisse : "));
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(saisieAxeAbscisse);
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(new JLabel("Mode d'Affichage : "));
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(saisieModeAffichage);
+		commandes.add(Box.createVerticalGlue());
+		commandes.add(listeStat);
+		saisieUniteComptage.setAlignmentX(0);
+		legendeTypeUnite.setAlignmentX(0);
+		saisieAxeOrdonnee.setAlignmentX(0);
+		saisieAxeAbscisse.setAlignmentX(0);
+		saisieModeAffichage.setAlignmentX(0);
+		
+		JScrollPane scrollcommandes = new JScrollPane(commandes);
+		graphique = Courbe.courbeFactory();
+		JScrollPane scrollcourbe = new JScrollPane(graphique);
+		JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollcommandes, scrollcourbe);
+		split.setDividerLocation(1. / 2);
+		setJMenuBar(menuBar);
+		JMenu corpusMenu = new JMenu("Paramètres d'affichage");
+		menuBar.add(corpusMenu);
+		;
+		corpusMenu.add(new GAction("Reprendre un affichage") {
+			
+			@Override
+			public void executer() {
+				importerAffichage();
+			}
+		});
+		corpusMenu.add(new GAction("Sauver les paramètres d'affichage") {
+			
+			@Override
+			public void executer() {
+				exporterAffichage();
+			}
+		});
+		JMenu csvMenu = new JMenu("Exporter les données");
+		menuBar.add(csvMenu);
+		;
+		csvMenu.add(new GAction("Exporter les données de filtrage") {
+			
+			@Override
+			public void executer() {
+				ArrayList<Object[]> donnees = new ArrayList<>();
+				donnees.add(new Object[] { "Unité", "type d'unité" });
+				for (String typeUnit : vue.getTypesUnitesAVoir()) {
+					if (!typesChainesMasques.contains(typeUnit)) {
+						for (Unite unit : vue.getUnites(typeUnit)) {
+							donnees.add(new Object[] { vue.getTexteUnite(unit), unit.getType() });
+						}
+					}
+				}
+				ExportCSV.exporterCSV(donnees.toArray(new Object[donnees.size()][2]));
+			}
+		});
+		csvMenu.add(new GAction("Exporter les statiques générales") {
+			
+			@Override
+			public void executer() {
+				ExportCSV.exporterCSV(donneesGenerales);
+			}
+		});
+		getContentPane().add(split);
+		setVisible(true);
+		// Fermeture de la fenêtre
+		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+		addWindowListener(new WindowAdapter() {
+			
+			@Override
+			public void windowClosing(WindowEvent evt) {
+				fermerFenetre();
+			}
+		});
+		donneesChaines = new ModeleChaines(vue, new GChaines(this));
+		donneesChaines.permettreaffichage(false);
+		saisieUniteComptage.setModele(new String[] { "Mots", "Caractère" });
+		saisieAxeAbscisse.setModele(StatPossiblesAbscisses);
+		saisieModeAffichage.setModele(ModesPossibles);
+	}
+	
+	private void fermerFenetre() {
+		vue.removeEventListener(this);
+		dispose();
+	}
+	
+	@Override
+	public void traiterEvent(Message evt) { // très grossier : à améliorer
+		switch (evt.getType()) {
+			case CLEAR_CORPUS:
+				fermerFenetre();
+				return;
+			case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+				throw new UnsupportedOperationException("Fenêtre chaines présente lors d'un message NEW_CORPUS ???");
+			case MODIF_TEXTE:
+				fermerFenetre();
+				return;
+			case MODIF_VUE:
+				fermerFenetre();
+				return;
+			case MODIF_STRUCTURE:
+				fermerFenetre();
+				return;
+			case MODIF_ELEMENT:
+				// ElementEvent evtE = (ElementEvent) evt;
+				// if (evtE.getModif() != TypeModifElement.BORNES_UNITE) fermerFenetre();
+				fermerFenetre();
+				return;
+			case CORPUS_SAVED:
+				fermerFenetre();
+				return;
+			default:
+				throw new UnsupportedOperationException("Cas " + evt.getType() + " oublié dans un switch");
+		}
+	}
+	
+	@Override
+	public void actionPerformed(ActionEvent evt) {
+		try {
+			if (evt.getSource().equals(saisieUniteComptage)) {
+				if (vue.getTypesUnitesAVoir() == null || saisieUniteComptage.pasdeSelection()) {
+					initVide();
+				}
+				else {
+					init();
+				}
+				return;
+			}
+			if (evt.getSource().equals(saisieAxeOrdonnee)) {
+				if (!saisieAxeAbscisse.pasdeSelection() && !saisieAxeOrdonnee.pasdeSelection()) {
+					affichercourbe();
+				}
+				return;
+			}
+			if (evt.getSource().equals(saisieAxeAbscisse)) {
+				if (!saisieUniteComptage.pasdeSelection()) {
+					initChampOrdonnee();
+				}
+				return;
+			}
+			if (evt.getSource().equals(saisieModeAffichage)) {
+				if (!saisieAxeAbscisse.pasdeSelection() && !saisieAxeOrdonnee.pasdeSelection()) {
+					affichercourbe();
+				}
+				return;
+			}
+			throw new UnsupportedOperationException("Evénement non prévu : " + evt.paramString());
+		}
+		catch (Throwable ex) {
+			GMessages.erreurFatale(ex);
+		}
+	}
+	
+	private void initTypeUnite() {
+		String[] legende = new String[typesChainesAffiches.length];
+		for (int i = 0; i < typesChainesAffiches.length; i++) {
+			if (typesChainesMasques.contains(typesChainesAffiches[i])) {
+				legende[i] = "" + typesChainesAffiches[i].toString() + "     Non";
+			}
+			else {
+				legende[i] = "" + typesChainesAffiches[i].toString() + "     Oui";
+			}
+		}
+		legendeTypeUnite.setListData(legende);
+	}
+	
+	private void popupChampInit(final int index) {
+		final boolean masquee;
+		masquee = typesChainesMasques.contains(typesChainesAffiches[index]);
+		popupChamp.removeAll();
+		popupChamp.add(new GAction(masquee ? "Montrer ce type d'unité" : "Masquer ce type d'unité") {
+			
+			@Override
+			public void executer() {
+				modifierStatutValChampType(masquee, index, false);
+			}
+		});
+		popupChamp.add(new GAction(masquee ? "Montrer tous les types" : "Ne montrer que ce type d'unité") {
+			
+			@Override
+			public void executer() {
+				modifierStatutValChampType(masquee, index, true);
+			}
+		});
+		
+	}
+	
+	private void modifierStatutValChampType(boolean masquee, int index, boolean tous) {
+		if (!tous) {
+			if (masquee) {
+				typesChainesMasques.remove(typesChainesAffiches[index]);
+			}
+			else {
+				typesChainesMasques.add(typesChainesAffiches[index]);
+			}
+		}
+		else if (masquee) {
+			typesChainesMasques.clear();
+		}
+		else {
+			typesChainesMasques.clear();
+			for (String valeur : typesChainesAffiches) {
+				if (!valeur.equals(typesChainesAffiches[index])) {
+					typesChainesMasques.add(valeur);
+				}
+			}
+			
+		}
+		afficherCalculs();
+		if (!saisieAxeAbscisse.pasdeSelection() && !saisieAxeOrdonnee.pasdeSelection()) {
+			affichercourbe();
+		}
+	}
+	
+	private void initVide() {
+		listeStat.removeAll();
+		saisieAxeOrdonnee.setModeleVide();
+		legendeTypeUnite.setListData(new String[0]);
+	}
+	
+	private String[] getTypesAutorises() {
+		String[] retour;
+		if (typesChainesAffiches.length - typesChainesMasques.size() > 0) {
+			retour = new String[typesChainesAffiches.length - typesChainesMasques.size()];
+			int compte = 0;
+			for (String type : typesChainesAffiches) {
+				if (!typesChainesMasques.contains(type)) {
+					retour[compte] = type;
+					compte = compte + 1;
+				}
+			}
+		}
+		else {
+			retour = new String[typesChainesAffiches.length];
+			int compte = 0;
+			for (String type : typesChainesAffiches) {
+				retour[compte] = type;
+				compte = compte + 1;
+			}
+		}
+		return retour;
+	}
+	
+	private void init() {
+		typesChainesAffiches = vue.getTypesUnitesAVoir();
+		saisieAxeAbscisse.setModele(StatPossiblesAbscisses);
+		initChampOrdonnee();
+		afficherCalculs();
+		
+	}
+	
+	private void afficherCalculs() {
+		initTypeUnite();
+		String unite = saisieUniteComptage.getSelection();
+		listeStat.removeAll();
+		this.donneesGenerales = new Object[20][2];
+		int donnee;
+		float donneef;
+		String[] typesDispo = getTypesAutorises();
+		listeStat.add(Box.createVerticalGlue());
+		donnee = ChaineUtil.nbCaractere(vue);
+		listeStat.add(new JLabel("Nombre de Caractères : " + donnee));
+		this.donneesGenerales[0][0] = "Nombre de Caractères";
+		this.donneesGenerales[0][1] = donnee;
+		listeStat.add(Box.createVerticalGlue());
+		donnee = ChaineUtil.nbMot(vue);
+		listeStat.add(new JLabel("Nombre de Mots : " + donnee));
+		this.donneesGenerales[1][0] = "Nombre de Mots";
+		this.donneesGenerales[1][1] = donnee;
+		listeStat.add(Box.createVerticalGlue());
+		donnee = ChaineUtil.nbParagraphe(vue);
+		listeStat.add(new JLabel("Nombre de Paragraphes : " + donnee));
+		this.donneesGenerales[2][0] = "Nombre de Paragraphes";
+		this.donneesGenerales[2][1] = donnee;
+		listeStat.add(Box.createVerticalGlue());
+		donnee = ChaineUtil.getUniteesTrieesEtFiltrees(typesDispo, vue).length;
+		listeStat.add(new JLabel("Nombre d'unités : " + donnee));
+		this.donneesGenerales[3][0] = "Nombre d'unités";
+		this.donneesGenerales[3][1] = donnee;
+		listeStat.add(Box.createVerticalGlue());
+		donnee = ChaineUtil.nombreDeReference(typesDispo, vue);
+		listeStat.add(new JLabel("Nombre de Références : " + donnee));
+		this.donneesGenerales[4][0] = "Nombre de Références";
+		this.donneesGenerales[4][1] = donnee;
+		listeStat.add(Box.createVerticalGlue());
+		donnee = ChaineUtil.nbChaines(vue);
+		listeStat.add(new JLabel("Nombre de Chaines : " + donnee));
+		this.donneesGenerales[5][0] = "Nombre de Chaines";
+		this.donneesGenerales[5][1] = donnee;
+		listeStat.add(Box.createVerticalGlue());
+		Integer[] tmp = ChaineUtil.nombreDeChainons(typesDispo, vue).toArray(new Integer[0]);
+		donneef = ChaineUtil.Esperance(tmp);
+		listeStat.add(new JLabel("Nombre moyen de Chainons par Chaine : " + donneef));
+		this.donneesGenerales[6][0] = "Nombre moyen de Chainons par Chaine";
+		this.donneesGenerales[6][1] = donneef;
+		listeStat.add(Box.createVerticalGlue());
+		donneef = ChaineUtil.Variance(tmp);
+		listeStat.add(new JLabel("Variance du Nombre de Chainons par Chaine : " + donneef));
+		this.donneesGenerales[7][0] = "Variance du Nombre de Chainons par Chaine";
+		this.donneesGenerales[7][1] = donneef;
+		listeStat.add(Box.createVerticalGlue());
+		donneef = ChaineUtil.densiteReferentielle("Paragraphe", typesDispo, vue);
+		listeStat.add(new JLabel("Densité référentielle par paragraphe : " + donneef));
+		this.donneesGenerales[8][0] = "Densité référentielle par paragraphe";
+		this.donneesGenerales[8][1] = donneef;
+		listeStat.add(Box.createVerticalGlue());
+		switch (unite) {
+			case "Mots":
+				donneef = ChaineUtil.densiteReferentielle("Mot", typesDispo, vue);
+				listeStat.add(new JLabel("Densité référentielle par nombre de mots : " + donneef));
+				this.donneesGenerales[9][0] = "Densité référentielle par nombre de mots";
+				this.donneesGenerales[9][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				tmp = ChaineUtil.positionUnite(typesDispo, vue).toArray(new Integer[0]);
+				// ici la position moyenne est calculé en caractère puis convertit en mots pour plus de précisions
+				donneef = ChaineUtil.calculerPositionMotCorpus(Math.round(ChaineUtil.Esperance(tmp)), vue);
+				listeStat.add(new JLabel("Position moyenne des unités : " + donneef));
+				this.donneesGenerales[10][0] = "Position moyenne des unités";
+				this.donneesGenerales[10][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				tmp = ChaineUtil.positionUniteEnMot(typesDispo, vue).toArray(new Integer[0]);
+				donneef = ChaineUtil.Variance(tmp);
+				listeStat.add(new JLabel("Variance des positions des unités : " + donneef));
+				this.donneesGenerales[11][0] = "Variance des positions des unités";
+				this.donneesGenerales[11][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				tmp = ChaineUtil.ecartUniteMot(typesDispo, vue).toArray(new Integer[0]);
+				donneef = ChaineUtil.Esperance(tmp);
+				listeStat.add(new JLabel("Ecart moyen entre les unités : " + donneef));
+				this.donneesGenerales[12][0] = "Ecart moyen entre les unités";
+				this.donneesGenerales[12][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				donneef = ChaineUtil.Variance(tmp);
+				listeStat.add(new JLabel("Variance des écarts des unités : " + donneef));
+				this.donneesGenerales[13][0] = "Variance des écarts des unités";
+				this.donneesGenerales[13][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				tmp = ChaineUtil.longueurUniteMot(typesDispo, vue).toArray(new Integer[0]);
+				donnee = ChaineUtil.somme(tmp);
+				listeStat.add(new JLabel("Longueur totale des unités : " + donnee));
+				this.donneesGenerales[14][0] = "Nombre de Mots";
+				this.donneesGenerales[14][1] = donnee;
+				listeStat.add(Box.createVerticalGlue());
+				donneef = ChaineUtil.Esperance(tmp);
+				listeStat.add(new JLabel("Longueur moyenne des unités : " + donneef));
+				this.donneesGenerales[15][0] = "Longueur moyenne des unités";
+				this.donneesGenerales[15][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				donneef = ChaineUtil.Variance(tmp);
+				listeStat.add(new JLabel("Variance des longueurs des unités : " + donneef));
+				this.donneesGenerales[16][0] = "Variance des longueurs des unités";
+				this.donneesGenerales[16][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				tmp = ChaineUtil.longueurChaineMot(typesDispo, vue).toArray(new Integer[0]);
+				donnee = ChaineUtil.somme(tmp);
+				listeStat.add(new JLabel("Longueur totale des chaines de coréférences : " + donnee));
+				this.donneesGenerales[17][0] = "Longueur totale des chaines de coréférences";
+				this.donneesGenerales[17][1] = donnee;
+				listeStat.add(Box.createVerticalGlue());
+				donneef = ChaineUtil.Esperance(tmp);
+				listeStat.add(new JLabel("Longueur moyenne des chaines de coréférences : " + donneef));
+				this.donneesGenerales[18][0] = "Nombre de Mots";
+				this.donneesGenerales[18][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				donneef = ChaineUtil.Variance(tmp);
+				listeStat.add(new JLabel("Variance des longueurs des chaines de coréférences : " + donneef));
+				this.donneesGenerales[19][0] = "Variance des longueurs des chaines de coréférences";
+				this.donneesGenerales[19][1] = donneef;
+				
+				
+				break;
+			case "Caractère":
+				donneef = ChaineUtil.densiteReferentielle("Caractère", typesDispo, vue);
+				listeStat.add(new JLabel("Densité référentielle par nombre de caractères : " + donneef));
+				this.donneesGenerales[9][0] = "Densité référentielle par nombre de caractères";
+				this.donneesGenerales[9][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				tmp = ChaineUtil.positionUnite(typesDispo, vue).toArray(new Integer[0]);
+				donneef = ChaineUtil.Esperance(tmp);
+				listeStat.add(new JLabel("Position moyenne des unités : " + donneef));
+				this.donneesGenerales[10][0] = "Position moyenne des unités";
+				this.donneesGenerales[10][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				donneef = ChaineUtil.Variance(tmp);
+				listeStat.add(new JLabel("Variance des positions des unités : " + donneef));
+				this.donneesGenerales[11][0] = "Variance des positions des unités";
+				this.donneesGenerales[11][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				tmp = ChaineUtil.ecartUniteCaractere(typesDispo, vue).toArray(new Integer[0]);
+				donneef = ChaineUtil.Esperance(tmp);
+				listeStat.add(new JLabel("Ecart moyen entre les unités : " + donneef));
+				this.donneesGenerales[12][0] = "Ecart moyen entre les unités";
+				this.donneesGenerales[12][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				donneef = ChaineUtil.Variance(tmp);
+				listeStat.add(new JLabel("Variance des écarts des unités : " + donneef));
+				this.donneesGenerales[13][0] = "Variance des écarts des unités";
+				this.donneesGenerales[13][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				tmp = ChaineUtil.longueurUniteCaractere(typesDispo, vue).toArray(new Integer[0]);
+				donnee = ChaineUtil.somme(tmp);
+				listeStat.add(new JLabel("Longueur totale des unités : " + donnee));
+				this.donneesGenerales[14][0] = "Longueur totale des unités";
+				this.donneesGenerales[14][1] = donnee;
+				listeStat.add(Box.createVerticalGlue());
+				donneef = ChaineUtil.Esperance(tmp);
+				listeStat.add(new JLabel("Longueur moyenne des unités : " + donneef));
+				this.donneesGenerales[15][0] = "Longueur moyenne des unités";
+				this.donneesGenerales[15][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				donneef = ChaineUtil.Variance(tmp);
+				listeStat.add(new JLabel("Variance des longueurs des unités : " + donneef));
+				this.donneesGenerales[16][0] = "Variance des longueurs des unités";
+				this.donneesGenerales[16][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				tmp = ChaineUtil.longueurChaineCaractere(typesDispo, vue).toArray(new Integer[0]);
+				donnee = ChaineUtil.somme(tmp);
+				listeStat.add(new JLabel("Longueur totale des chaines de coréférences : " + donnee));
+				this.donneesGenerales[17][0] = "Longueur totale des chaines de coréférences";
+				this.donneesGenerales[17][1] = donnee;
+				listeStat.add(Box.createVerticalGlue());
+				donneef = ChaineUtil.Esperance(tmp);
+				listeStat.add(new JLabel("Longueur moyenne des chaines de coréférences : " + donneef));
+				this.donneesGenerales[18][0] = "Longueur moyenne des chaines de coréférences";
+				this.donneesGenerales[18][1] = donneef;
+				listeStat.add(Box.createVerticalGlue());
+				donneef = ChaineUtil.Variance(tmp);
+				listeStat.add(new JLabel("Variance des longueurs des chaines de coréférences : " + donneef));
+				this.donneesGenerales[19][0] = "Variance des longueurs des chaines de coréférences";
+				this.donneesGenerales[19][1] = donneef;
+				break;
+			default:
+				break;
+		}
+	}
+	
+	private void initChampOrdonnee() {
+		if (!saisieAxeAbscisse.pasdeSelection()) {
+			switch (saisieAxeAbscisse.getSelection()) {
+				case "Nombre de chainons":
+					StatPossiblesOrdonnees = new String[] { "Nombre de Chaines de coreference" };
+					break;
+				case "Numéro de paragraphe":
+					StatPossiblesOrdonnees = new String[] { "Nombre de chainons", "Nombre de Chaines de coreference",
+							"ratio nombre de chainons par nombre de " + saisieUniteComptage.getSelection(), "Densité référentielle" };
+					break;
+				default:
+					StatPossiblesOrdonnees = new String[] {};
+					break;
+			}
+		}
+		else {
+			StatPossiblesOrdonnees = new String[] {};
+		}
+		saisieAxeOrdonnee.setModele(StatPossiblesOrdonnees);
+	}
+	
+	private void affichercourbe() {
+		switch (saisieAxeAbscisse.getSelection()) {
+			case "Nombre de chainons":
+				switch (saisieAxeOrdonnee.getSelection()) {
+					case "Nombre de Chaines de coreference":
+						HashMap donnee = ChaineUtil.calculerdonneecourbechainons(getTypesAutorises(), vue);
+						afficherNbChainesEnFonctionNbChainons(donnee);
+						break;
+				}
+				;
+				break;
+			case "Numéro de paragraphe":
+				HashMap donnee = ChaineUtil.calculedonneecourbe(getTypesAutorises(), saisieUniteComptage.getSelection(), vue);
+				switch (saisieAxeOrdonnee.getSelection()) {
+					case "Nombre de Chaines de coreference":
+						afficherEnFonctionParagraphe(donnee);
+						break;
+					case "Nombre de chainons":
+						afficherEnFonctionParagraphe(donnee);
+						break;
+					case "ratio nombre de chainons par nombre de " + "Mots":
+						afficherEnFonctionParagraphe(donnee);
+						break;
+					case "ratio nombre de chainons par nombre de " + "Caractère":
+						afficherEnFonctionParagraphe(donnee);
+						break;
+					case "Densité référentielle":
+						afficherEnFonctionParagraphe(donnee);
+						break;
+				}
+				;
+				break;
+			default:
+				break;
+		}
+	}
+	
+	
+	private void afficherEnFonctionParagraphe(HashMap<Integer, HashMap<String, Integer>> donnees) {
+		ArrayList<Integer> classement = new ArrayList<>();
+		ArrayList<Integer> ordonnee = new ArrayList<>();
+		for (Integer nopa : donnees.keySet()) {
+			classement.add(nopa, nopa);
+			ordonnee.add(nopa, donnees.get(nopa).get(saisieAxeOrdonnee.getSelection()));
+			
+		}
+		if (!saisieModeAffichage.pasdeSelection() && saisieModeAffichage.getSelection() == "Désactiver l'affichage des valeurs nulles") {
+			for (int nopa = 0; nopa < ordonnee.size(); nopa++) {
+				if (nopa != 0 && nopa < ordonnee.size() - 1 && ordonnee.get(nopa) == 0) {
+					classement.remove(nopa);
+					ordonnee.remove(nopa);
+					nopa = nopa - 1;
+				}
+			}
+			
+		}
+		
+		if (!saisieModeAffichage.pasdeSelection() && saisieModeAffichage.getSelection() == "Activer l'interpolation") {
+			ArrayList<Integer> valeurlagrange = new ArrayList<>();
+			for (int i = 0; i < classement.size(); i++) {
+				valeurlagrange.add(i, ChaineUtil.interpolationLagrangienne(classement.toArray(new Integer[0]),
+						ordonnee.toArray(new Integer[0]), i));
+			}
+			ordonnee = valeurlagrange;
+		}
+		Courbe.updatePanel(graphique, "Représentation de " + saisieAxeOrdonnee.getSelection() + " en fonction du numéro pararaphe",
+				classement.toArray(new Integer[0]), ordonnee.toArray(new Integer[0]),
+				Color.blue, -1, "numéro pararaphe", saisieAxeOrdonnee.getSelection());
+	}
+	
+	
+	
+	private void afficherNbChainesEnFonctionNbChainons(HashMap<Integer, Integer> donnees) {
+		int max = 0;// on cherche l'abscisse maximum
+		for (Integer elt : donnees.keySet()) {
+			if (elt > max) {
+				max = elt;
+			}
+		}
+		ArrayList<Integer> abscisse;
+		ArrayList<Integer> ordonnee;
+		
+		if (saisieModeAffichage.pasdeSelection() || saisieModeAffichage.getSelection() != "Activer l'interpolation") {
+			abscisse = new ArrayList<>();
+			ordonnee = new ArrayList<>();
+			for (int i = 0; i < max + 1; i++) {
+				abscisse.add(i, i);
+				if (donnees.containsKey(i)) {
+					ordonnee.add(i, donnees.get(i));
+				}
+				else {
+					ordonnee.add(i, 0);
+				}
+			}
+			if (!saisieModeAffichage.pasdeSelection() && saisieModeAffichage.getSelection().equals("Désactiver l'affichage des valeurs nulles")) {
+				for (int nopa = 0; nopa < ordonnee.size(); nopa++) {
+					if (nopa != 0 && nopa < ordonnee.size() - 1 && ordonnee.get(nopa) == 0) {
+						abscisse.remove(nopa);
+						ordonnee.remove(nopa);
+						nopa = nopa - 1;
+					}
+				}
+				
+			}
+		}
+		else {
+			Integer[] abscisses = new Integer[donnees.size()];
+			Integer[] ordonnees = new Integer[donnees.size()];
+			int compteur = 0;
+			for (int i = 0; i < max + 1; i++) {
+				
+				if (donnees.containsKey(i)) {
+					abscisses[compteur] = i;
+					ordonnees[compteur] = donnees.get(i);
+					compteur = compteur + 1;
+				}
+			}
+			abscisse = new ArrayList<>();
+			ordonnee = new ArrayList<>();
+			for (int i = 0; i < max + 1; i++) {
+				abscisse.add(i, i);
+				ordonnee.add(i, ChaineUtil.interpolationLagrangienne(abscisses, ordonnees, i));
+			}
+		}
+		Courbe.updatePanel(graphique, "Représentation de " + "nombre de chaines" + " en fonction du nombre de chainons",
+				abscisse.toArray(new Integer[0]), ordonnee.toArray(new Integer[0]),
+				Color.blue, -1, "numéro pararaphe", saisieAxeOrdonnee.getSelection());
+	}
+	
+	private void importerAffichage() {
+		HashMap<String, Object> Choix = FichiersJava.ouvrirChaineVue();
+		if (Choix != null && Choix.containsKey("choixCommande3") &&
+				Fichiers.getNomFichierCourant(Fichiers.TypeFichier.DOC_ANALEC).equals(Choix.get("nomFichier"))) {
+			HashMap<String, String> choixCommande = (HashMap<String, String>) Choix.get("choixCommande3");
+			saisieUniteComptage.removeActionListener(this);
+			saisieUniteComptage.setSelectedItem(choixCommande.get("saisieUniteComptage"));
+			saisieUniteComptage.addActionListener(this);
+			if (vue.getTypesUnitesAVoir() == null || saisieUniteComptage.pasdeSelection()) {
+				initVide();
+			}
+			else {
+				init();
+			}
+			this.typesChainesMasques = (HashSet<String>) Choix.get("typesChainesMasques");
+			saisieAxeOrdonnee.removeActionListener(this);
+			saisieAxeAbscisse.removeActionListener(this);
+			saisieModeAffichage.removeActionListener(this);
+			
+			
+			saisieAxeAbscisse.setSelectedItem(choixCommande.get("saisieAxeAbscisse"));
+			initChampOrdonnee();
+			saisieAxeOrdonnee.setSelectedItem(choixCommande.get("saisieAxeOrdonnee"));
+			saisieModeAffichage.setSelectedItem(choixCommande.get("saisieModeAffichage"));
+			saisieAxeOrdonnee.addActionListener(this);
+			saisieAxeAbscisse.addActionListener(this);
+			saisieModeAffichage.addActionListener(this);
+			affichercourbe();
+		}
+		else {
+			JOptionPane.showMessageDialog(null, "le fichier des paramètres d'affichage n'est pas destiné à cette fenêtre"
+					+ System.getProperty("line.separator") +
+					"ou à ce corpus", "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+		}
+		
+		
+	}
+	
+	private void exporterAffichage() {
+		
+		HashMap<String, Object> Choix = new HashMap();
+		HashMap<String, String> choixCommande = new HashMap();
+		
+		choixCommande.put("saisieUniteComptage", saisieUniteComptage.pasdeSelection() ? null : saisieUniteComptage.getSelection());
+		choixCommande.put("saisieAxeOrdonnee", saisieAxeOrdonnee.pasdeSelection() ? null : saisieAxeOrdonnee.getSelection());
+		choixCommande.put("saisieAxeAbscisse", saisieAxeAbscisse.pasdeSelection() ? null : saisieAxeAbscisse.getSelection());
+		choixCommande.put("saisieModeAffichage", saisieModeAffichage.pasdeSelection() ? null : saisieModeAffichage.getSelection());
+		Choix.put("typesChainesMasques", typesChainesMasques);
+		Choix.put("choixCommande3", choixCommande);
+		Choix.put("nomFichier", Fichiers.getNomFichierCourant(Fichiers.TypeFichier.DOC_ANALEC));
+		FichiersJava.enregistrerChaineSous(Choix);
+	}
+	
+	/* renvoie un tableau contenant les statistiques générales du texte */
+	public Object[][] donneesCSV() {
+		return this.donneesGenerales;
+	}
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuStatGenerale.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ModeleStatChaine.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ModeleStatChaine.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ModeleStatChaine.java	(revision 3653)
@@ -0,0 +1,232 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package visuAnalec.chaines;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import javax.swing.table.*;
+import visuAnalec.elements.Schema;
+import visuAnalec.elements.Unite;
+import visuAnalec.vue.Vue;
+
+/**
+ *
+ * @author Marc
+ */
+public class ModeleStatChaine extends AbstractTableModel {
+	
+	private Object[][] donnees;
+	
+	private String[] entetes = new String[] { "Trigramme", "Nombre d'occurences", "Fréquence", "Position moyenne" };
+	
+	@Override
+	public int getColumnCount() {
+		return entetes.length;
+	}
+	
+	@Override
+	public String getColumnName(int columnIndex) {
+		return entetes[columnIndex];
+	}
+	
+	public ModeleStatChaine(Object[][] donnees, String[] titres) {
+		this.donnees = donnees;
+		this.entetes = titres;
+	}
+	
+	public ModeleStatChaine() {
+		this.donnees = new Object[0][0];
+		this.entetes = new String[0];
+	}
+	
+	@Override
+	public int getRowCount() {
+		return donnees.length;
+	}
+	
+	@Override
+	public Object getValueAt(int rowIndex, int columnIndex) {
+		return donnees[rowIndex][columnIndex];
+	}
+	
+	@Override
+	public Class getColumnClass(int columnIndex) {
+		switch (columnIndex) {
+			case 0:
+				return String.class;
+			default:
+				return Float.class;
+		}
+	}
+	
+	public HashMap<Object, HashMap<Object, Float>> conversionNbOccurencesToFrequence(
+			HashMap<Object, HashMap<Object, Float>> donnees) {
+		float sommepartielle;
+		for (Object val : donnees.keySet()) {
+			sommepartielle = 0.0f;
+			for (Object val1 : donnees.get(val).keySet()) {
+				sommepartielle = sommepartielle + (donnees.get(val)).get(val1);
+			}
+			for (Object val1 : donnees.get(val).keySet()) {
+				(donnees.get(val)).put(val1, (sommepartielle != 0.0f ? (donnees.get(val)).get(val1) * 10000.0f / sommepartielle / 100.0f : 0.0f));
+			}
+		}
+		return donnees;
+	}
+	
+	public void getTableau(HashMap<Object, HashMap<Object, Float>> donnees, int nbcolonnes, String observation) {
+		Object[][] resultat = new Object[donnees.size()][nbcolonnes + 2];
+		String[] titre = new String[nbcolonnes + 2];
+		int i = 0;
+		HashMap<Object, Integer> idcolonnes = new HashMap();
+		donnees = conversionNbOccurencesToFrequence(donnees);
+		titre[0] = observation;
+		// on choisit les colonnes des valeurs
+		// grossier
+		for (Object val : donnees.keySet()) {
+			i = 0;
+			for (Object val1 : donnees.get(val).keySet()) {
+				titre[i + 1] = val1.toString();
+				idcolonnes.put(val1, i + 1);
+				i = i + 1;
+			}
+		}
+		i = 0;
+		for (Object val : donnees.keySet()) {
+			// on écrit l'objet surlequel porte l'observation
+			resultat[i][0] = val;
+			for (Object val1 : donnees.get(val).keySet()) {
+				resultat[i][idcolonnes.get(val1)] = (donnees.get(val)).get(val1);
+			}
+			i = i + 1;
+		}
+		this.entetes = titre;
+		this.donnees = resultat;
+		
+	}
+	
+	// @require : typeChampLigne n'a aucune case nulle, typeUnite et typeChaine sont non-null
+	// typeChampColonne est défini
+	// génère un modèle pour un tableau en comptant le nombre d'occurrence de la valeur du champ en tête de
+	// colonne par par valeur du ou des champs en tête de ligne
+	public static ModeleStatChaine calculateStatCoref(String nomChampChaine,
+			String nomChampUnite, Collection<String> valeurChaineCachees,
+			String typeChampColonne, String[] typeChampLigne, Vue vue, ModeleChaines donneesChaine,
+			ArrayList paragrapheCaches, String typeChaine, String typeUnite, String[] valNbElements) {
+		HashMap<Object, HashMap<Object, Float>> retour = new HashMap<>();
+		Unite[] listeUnites = donneesChaine.getUnites();
+		int[] noparag = (vue.getCorpus()).calculerNoParagraphe(listeUnites);
+		
+		// on créé une ligne par défaut
+		HashMap<String, Float> defaultLine = new HashMap<>();
+		switch (typeChampColonne) {
+			case "Chaine":
+				// un champ de la chaine ne peut pas être nul
+				for (String val : vue.getValeursChamp(Schema.class, typeChaine, nomChampChaine)) {
+					defaultLine.put(val, 0.0f);
+				}
+				defaultLine.put("Aucune valeur", 0.0f);
+				break;
+			case "Unite":
+				for (String val : (nomChampUnite == null ? valNbElements
+						: vue.getValeursChamp(Unite.class, typeUnite, nomChampUnite))) {
+					defaultLine.put(val, 0.0f);
+				}
+				defaultLine.put("Aucune valeur", 0.0f);
+				break;
+			default:
+				for (int val : noparag) {
+					defaultLine.put("  Paragraphe " + val, 0.0f);
+				}
+				break;
+		}
+		
+		
+		int numeroUnite = 0;
+		for (Unite unit : listeUnites) {
+			Schema chaine = donneesChaine.getchainesUnitesNonFiltrees().get(unit);
+			
+			// on filtre les unités
+			String propUnite = (nomChampUnite == null ? valNbElements[donneesChaine.calculerValNbElements(
+					donneesChaine.getChainonUnites().get(unit).nbEltsChaine)]
+					: vue.getValeurChamp(unit, nomChampUnite));
+			
+			String propChaine = chaine == null ? null : (vue.getValeurChamp(chaine, nomChampChaine));
+			
+			if (!paragrapheCaches.contains(noparag[numeroUnite]) && chaine != null &&
+					!(nomChampUnite == null ? donneesChaine.isMasqueeValNbElements(donneesChaine.calculerValNbElements(donneesChaine.getChainonUnites().get(unit).nbEltsChaine))
+							: donneesChaine.isMasqueeValChamp(nomChampUnite, propUnite)) &&
+					!valeurChaineCachees.contains(propChaine)) {
+				
+				// on calcule la clé de la ligne sous forme de chaine de caractère
+				String key1 = new String();
+				for (int i = 0; i < typeChampLigne.length; i++) {
+					switch (typeChampLigne[i]) {
+						case "Chaine":
+							key1 = key1 + "  " + (propChaine == null || propChaine.equals("")
+									? "Aucune valeur"
+									: propChaine);
+							break;
+						case "Unite":
+							key1 = key1 + "  " + (propUnite == null || propUnite.equals("") ? "Aucune valeur" : propUnite);
+							break;
+						default:
+							key1 = key1 + "  Paragraphe " + noparag[numeroUnite];
+							break;
+					}
+				}
+				// on cherche la clé de la colonne et on initialise les valeurs
+				String key2 = new String();
+				switch (typeChampColonne) {
+					case "Chaine":
+						key2 = key2 + (propChaine == null || propChaine.equals("")
+								? "Aucune valeur"
+								: propChaine);
+						break;
+					case "Unite":
+						key2 = key2 + (propUnite == null || propUnite.equals("")
+								? "Aucune valeur"
+								: propUnite);
+						break;
+					default:
+						key2 = key2 + "  Paragraphe " + noparag[numeroUnite];
+						break;
+				}
+				// on ajoute l'unité dans la table correspondante
+				HashMap<Object, Float> ligne = (retour.containsKey(key1) ? retour.get(key1) : (HashMap<Object, Float>) defaultLine.clone());
+				ligne.put(key2, ligne.get(key2) + 1);
+				retour.put(key1, ligne);
+			}
+			numeroUnite++;
+		}
+		
+		String titreLigne = new String();
+		for (String type : typeChampLigne) {
+			switch (type) {
+				case "Chaine":
+					titreLigne = titreLigne + "  Valeur Champ Chaine";
+					break;
+				case "Unite":
+					titreLigne = titreLigne + "  Valeur Champ Unite";
+					break;
+				default:
+					titreLigne = titreLigne + "  Numero Paragraphe";
+					break;
+			}
+		}
+		ModeleStatChaine modele = new ModeleStatChaine();
+		modele.getTableau(retour, defaultLine.size(), titreLigne);
+		return modele;
+	}
+	
+	
+	
+	
+	
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ModeleStatChaine.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/NgrammesPanel.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/NgrammesPanel.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/NgrammesPanel.java	(revision 3653)
@@ -0,0 +1,526 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package visuAnalec.chaines;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.HashMap;
+import java.util.HashSet;
+import javax.swing.Box;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableModel;
+import visuAnalec.Message;
+import visuAnalec.elements.Schema;
+import visuAnalec.elements.Unite;
+import visuAnalec.util.GMessages;
+import visuAnalec.util.GVisu;
+import visuAnalec.vue.Vue;
+
+/**
+ *
+ * @author marc
+ * panneau affichage des statistiques des n-grams
+ */
+public class NgrammesPanel extends JPanel implements Vue.VueListener, ActionListener {
+
+private JList legendechampstatistique;
+private JPopupMenu popupChampstat = new JPopupMenu();
+private JPopupMenu popupChamptrigramme = new JPopupMenu();
+private JCheckBox digrammeXX = new JCheckBox();
+private JCheckBox trigrammeXOX = new JCheckBox();
+private JCheckBox trigrammeXOY = new JCheckBox();
+private JCheckBox trigrammeXXX = new JCheckBox();
+private JCheckBox trigrammeXYZ = new JCheckBox();
+private final GVisu.Val0ComboBox typeChamp;
+private final GVisu.Val0ComboBox champstatistique;
+private final GVisu.Val0ComboBox saisiechampchaine;
+private final JCheckBox activeparagraphe;
+private final JCheckBox activeglissant;
+private final JCheckBox activesingleton;
+private final Box commandesstat;
+private String[] valsAfficheesstat;
+private NgrammesModel ngrammesModel;
+private HashSet valsAfficheesautrestat=new HashSet();
+private Vue vue;
+private String typeChaines;
+private String typeUnites;
+private JTable resultatstatistique;
+private ModeleChaines donneesChaines;
+private final String[] statpossibles = new String[]{"Digramme","Trigramme"};
+
+public NgrammesPanel(Vue vue){    
+    this.vue=vue;
+    vue.addEventListener(this);
+    
+    legendechampstatistique = new JList();
+    legendechampstatistique.addMouseListener(new MouseAdapter() {
+      @Override
+      public void mousePressed(MouseEvent e) {//on gère les évènements de la souris
+        check(e);
+      }
+      @Override
+      public void mouseReleased(MouseEvent e) {
+        check(e);
+      }
+      public void check(MouseEvent e) {
+        if (e.isPopupTrigger()) {//if the event shows the menu
+          popupChampInitStat(legendechampstatistique.locationToIndex(e.getPoint()));
+          popupChampstat.show(legendechampstatistique, e.getX(), e.getY());
+        }
+      }
+    });
+    typeChamp = new GVisu.Val0ComboBox("Rien");
+    typeChamp.addActionListener(this);
+    champstatistique = new GVisu.Val0ComboBox("Rien");
+    champstatistique.addActionListener(this);  
+    saisiechampchaine = new GVisu.Val0ComboBox("Rien");
+    saisiechampchaine.addActionListener(this);  
+    activeparagraphe = new JCheckBox("activer les paragraphes (chiffre 0)");
+    activeglissant = new JCheckBox("activer le mode glissant");
+    activesingleton = new JCheckBox("activer l'affichage des singletons");
+    commandesstat = Box.createVerticalBox();
+    commandesstat.add(Box.createVerticalGlue());
+    commandesstat.add(activeparagraphe);
+    commandesstat.add(Box.createVerticalGlue());
+    commandesstat.add(activeglissant);
+    commandesstat.add(Box.createVerticalGlue());
+    commandesstat.add(activesingleton);    
+    commandesstat.add(Box.createVerticalGlue());
+    commandesstat.add(new JLabel("Choisisser une statistique : "));
+    commandesstat.add(champstatistique);
+    commandesstat.add(Box.createVerticalGlue());
+    commandesstat.add(new JLabel("Choisisser un type de champ: "));
+    commandesstat.add(typeChamp);    
+    commandesstat.add(Box.createVerticalGlue());
+    commandesstat.add(new JLabel("Choisisser un champ de la chaine : "));
+    commandesstat.add(saisiechampchaine);
+    commandesstat.add(Box.createVerticalGlue());
+    commandesstat.add(legendechampstatistique);  
+    commandesstat.add(Box.createVerticalGlue());
+    digrammeXX = new JCheckBox("Compter les digrammes de type XX");
+    commandesstat.add(digrammeXX); 
+    commandesstat.add(Box.createVerticalGlue());
+    trigrammeXOX = new JCheckBox("Compter les digrammes de type X0X");
+    commandesstat.add(trigrammeXOX);     
+    commandesstat.add(Box.createVerticalGlue());
+    trigrammeXOY = new JCheckBox("Compter les digrammes de type X0Y");
+    commandesstat.add(trigrammeXOY); 
+    commandesstat.add(Box.createVerticalGlue());
+    trigrammeXYZ = new JCheckBox("Compter les digrammes de type XYZ");
+    commandesstat.add(trigrammeXYZ); 
+    commandesstat.add(Box.createVerticalGlue());
+    trigrammeXXX = new JCheckBox("Compter les digrammes de type XXX");
+    commandesstat.add(trigrammeXXX); 
+    JScrollPane scrollstat = new JScrollPane(commandesstat);
+    this.donneesChaines = null;
+        
+    Box resultatstat = Box.createVerticalBox();
+    resultatstat.add(Box.createVerticalGlue());
+    resultatstat.add(new JLabel("Statistique : "));
+    resultatstat.add(Box.createVerticalGlue());
+    
+    DefaultTableModel initModel = new DefaultTableModel(new Object[0][0],
+    new String[]{"Ngramme","Nombre d'occurences","Fréquence","Position moyenne"}){
+               Class[] types = new Class [] {
+                java.lang.String.class, java.lang.Integer.class,java.lang.Float.class,java.lang.Float.class
+            };
+
+            public Class getColumnClass(int columnIndex) {
+                return types [columnIndex];
+            }
+
+            };
+    
+    resultatstatistique = new JTable(initModel);
+    resultatstatistique.addMouseListener(new MouseAdapter() {
+      @Override
+      public void mousePressed(MouseEvent e) {//on gère les évènements de la souris
+        check(e);
+      }
+      @Override
+      public void mouseReleased(MouseEvent e) {
+        check(e);
+      }
+      public void check(MouseEvent e) {
+        if (e.isPopupTrigger()) {//if the event shows the menu
+          popupChampInitTrigramme(resultatstatistique.rowAtPoint(e.getPoint()));
+          popupChamptrigramme.show(resultatstatistique, e.getX(), e.getY());
+        }
+      }
+    });
+    JScrollPane jsp =new JScrollPane(resultatstatistique);
+    resultatstat.add(resultatstatistique.getTableHeader());
+    resultatstat.add(jsp);
+    typeChamp.setAlignmentX(0);
+    champstatistique.setAlignmentX(0);
+    saisiechampchaine.setAlignmentX(0);
+    legendechampstatistique.setAlignmentX(0); 
+    JScrollPane scrollstatresultat = new JScrollPane(resultatstat);
+    JSplitPane split1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,  scrollstat,scrollstatresultat);
+    add(split1);
+    split1.setDividerLocation(1./4);
+    
+}
+
+public void setDonneesChaines(ModeleChaines donneesChaines){
+    this.donneesChaines=donneesChaines;
+}
+
+public void setVue(Vue vue){
+    this.vue= vue;
+}
+
+public void setTypeChaines(String typeChaines){
+    this.typeChaines=typeChaines;
+}
+
+public void setTypeUnites(String typeUnites){
+    this.typeUnites=typeUnites;
+}
+
+public void update(){
+    if(this.donneesChaines!=null && this.vue!=null && this.typeChaines!=null && this.typeUnites!=null){
+        initstat();
+    }
+    else{
+        init();
+    }
+}
+
+public void importerAffichage(HashMap choix){
+        typeChamp.removeActionListener(this);
+        saisiechampchaine.removeActionListener(this);
+        champstatistique.removeActionListener(this);
+        activeparagraphe.setSelected(choix.get("activeparagraphe").equals("vrai"));
+        activeglissant.setSelected(choix.get("activeglissant").equals("vrai"));
+        activesingleton.setSelected(choix.get("activesingleton").equals("vrai"));
+        digrammeXX.setSelected(choix.get("digrammeXX").equals("vrai"));
+        trigrammeXOX.setSelected(choix.get("trigrammeXOX").equals("vrai"));
+        trigrammeXOY.setSelected(choix.get("trigrammeXOY").equals("vrai"));
+        trigrammeXXX.setSelected(choix.get("trigrammeXXX").equals("vrai"));
+        trigrammeXYZ.setSelected(choix.get("trigrammeXYZ").equals("vrai"));
+        if(choix.get("typeChamp")!=null){
+          typeChamp.setSelectedItem(choix.get("typeChamp"));
+          if(!typeChamp.pasdeSelection()){
+            switch(typeChamp.getSelection()){
+                case "Chaine" :
+                    saisiechampchaine.removeActionListener(this);
+                    saisiechampchaine.setModele(vue.getNomsChamps(Schema.class, typeChaines));
+                    saisiechampchaine.addActionListener(this);                       
+                    break;
+                case "Unité" :
+                    saisiechampchaine.removeActionListener(this);
+                    saisiechampchaine.setModele(vue.getNomsChamps(Unite.class, typeUnites));
+                    saisiechampchaine.addActionListener(this);                        
+                    break;
+                default :
+                    saisiechampchaine.removeActionListener(this);
+                    saisiechampchaine.setModeleVide();
+                    saisiechampchaine.addActionListener(this);                      
+                    break;
+            }
+          }
+          else{
+                saisiechampchaine.removeActionListener(this);
+                saisiechampchaine.setModeleVide();
+                saisiechampchaine.addActionListener(this);                 
+          }
+        }
+        else{
+          typeChamp.effSelection();
+        }
+        
+        if(choix.get("saisiechampchaine")!=null){
+          saisiechampchaine.setSelectedItem(choix.get("saisiechampchaine"));
+        }
+        else{
+          saisiechampchaine.effSelection();
+        }
+        if(choix.get("champstatistique")!=null){
+        champstatistique.setSelectedItem(choix.get("champstatistique"));
+        }
+        else{
+          champstatistique.effSelection();
+        }
+        typeChamp.addActionListener(this);
+        saisiechampchaine.addActionListener(this);
+        champstatistique.addActionListener(this);
+        this.valsAfficheesautrestat = (HashSet) choix.get("valsAfficheesautrestat");
+        this.valsAfficheesstat = (String[]) choix.get("valsAfficheesstat");
+    
+}
+
+public HashMap exporterAffichage(){
+    HashMap choix = new HashMap();
+      choix.put("activeparagraphe",activeparagraphe.isSelected() ? "vrai" : "faux");
+      choix.put("activeglissant",activeglissant.isSelected() ? "vrai" : "faux");
+      choix.put("activesingleton",activesingleton.isSelected() ? "vrai" : "faux");
+      choix.put("digrammeXX",digrammeXX.isSelected() ? "vrai" : "faux");
+      choix.put("trigrammeXOX",trigrammeXOX.isSelected() ? "vrai" : "faux");
+      choix.put("trigrammeXOY",trigrammeXOY.isSelected() ? "vrai" : "faux");
+      choix.put("trigrammeXXX",trigrammeXXX.isSelected() ? "vrai" : "faux");
+      choix.put("trigrammeXYZ",trigrammeXYZ.isSelected() ? "vrai" : "faux");
+      choix.put("typeChamp",typeChamp.pasdeSelection() ? null : typeChamp.getSelection());
+      choix.put("saisiechampchaine",saisiechampchaine.pasdeSelection() ? null : saisiechampchaine.getSelection());
+      choix.put("champstatistique",champstatistique.pasdeSelection() ? null : champstatistique.getSelection());
+      choix.put("valsAfficheesautrestat",valsAfficheesautrestat);
+      choix.put("valsAfficheesstat",valsAfficheesstat);
+    return choix;
+    
+}
+
+private void popupChampInitStat(final int index) {
+    popupChampstat.removeAll();
+    if (saisiechampchaine.pasdeSelection()) {
+    } else if (index>=valsAfficheesstat.length - valsAfficheesautrestat.size()) {
+      popupChampstat.add(new GMessages.GAction("Afficher toutes les autres valeurs") {
+        @Override
+        public void executer() {
+          eclaterautres();
+        }
+      });
+    } else {
+      popupChampstat.add(new GMessages.GAction("Ajouter à la valeur autre") {
+        @Override
+        public void executer() {
+          ajouteraautres(legendechampstatistique.getModel().getElementAt(index));
+        }
+      });
+    }
+  }
+
+private void popupChampInitTrigramme(final int index) {
+    popupChamptrigramme.removeAll();
+    if (!champstatistique.pasdeSelection() && !saisiechampchaine.pasdeSelection()) {
+        String valeur = resultatstatistique.getValueAt(index, 0).toString();
+        if(!valeur.equals("x0x") && !valeur.equals("xx") &&!valeur.equals("x0y") &&!valeur.equals("xyz") &&
+                !valeur.equals("xxx")){
+            String[] affichage;
+            switch(champstatistique.getSelection()){
+                case "Digramme" :
+                    affichage = ngrammesModel.infoSuivant(valeur);
+                    break;
+                case "Trigramme" :
+                    affichage = ngrammesModel.infoSuivant(valeur);
+                    break;
+                default :
+                    affichage = new String[0];
+                    break;
+            }
+            for(int i = 0; i < affichage.length;i++){
+                popupChamptrigramme.add(new JLabel(affichage[i]));
+            }
+        }
+    } 
+  }
+//permet d'ajouter à la catégorie "autre" la valeur d'un champ
+  private void ajouteraautres (Object valeur){
+
+        this.valsAfficheesautrestat.add(valeur.toString().substring(4));
+
+    initstat();
+  }
+  private void eclaterautres(){
+    this.valsAfficheesautrestat.clear();
+    initstat();
+  }
+  
+  public HashMap<String,Character> LegendeStat(String[] valsAfficheesstat,HashSet valsAfficheesautre){
+      HashMap<String,Character> retour = new HashMap<String,Character>();
+      int compte = 0;
+      for(String unit : valsAfficheesstat){
+          if(!valsAfficheesautre.contains(unit) ){
+          compte = compte + 1;
+          retour.put(unit,GVisu.intToChar(compte));
+          }
+      }
+      retour.put("autre", GVisu.intToChar(compte+1));
+      retour.put("singleton", GVisu.intToChar(compte+2));
+     return retour;
+  }
+  
+
+  public void AfficherLegendeStat(HashMap<String,Character> donnee){
+  String[] legendes = new String[donnee.size()];
+  for(String unit : donnee.keySet()){
+    legendes[GVisu.CharToInt(donnee.get(unit)) - 1]= "" + donnee.get(unit) +"   "+ unit;
+  }
+  legendechampstatistique.setListData(legendes);
+  }
+  
+  public void initstat(){
+      if(!champstatistique.pasdeSelection() && !saisiechampchaine.pasdeSelection() && !typeChamp.pasdeSelection()){
+            switch(typeChamp.getSelection()){
+                case "Chaine" :
+                    this.valsAfficheesstat = vue.getValeursChamp(Schema.class,typeChaines,
+                            saisiechampchaine.getSelection());              
+                    break;
+                case "Unité" :
+                    this.valsAfficheesstat = vue.getValeursChamp(Unite.class,typeUnites,
+                            saisiechampchaine.getSelection());                      
+                    break;
+            }
+        HashMap<String,Character> legende = LegendeStat(this.valsAfficheesstat,this.valsAfficheesautrestat);
+        AfficherLegendeStat(legende);
+        this.ngrammesModel=new NgrammesModel();
+        int nbLettre;
+        if( "Trigramme".equals(champstatistique.getSelection())){
+            nbLettre = 3;
+        }
+        else if("Digramme".equals(champstatistique.getSelection())){
+            nbLettre = 2;
+        }
+        else{
+            nbLettre = 1;
+        }
+        //on calcule le modèle des ngrammes
+        this.ngrammesModel.ngrammeUpdate(nbLettre, legende,saisiechampchaine.getSelection(),vue,
+                activeglissant.isSelected(), donneesChaines,activesingleton.isSelected(), 
+                typeChamp.getSelection(),activeparagraphe.isSelected());
+        boolean[] ligneSup;
+        if( "Trigramme".equals(champstatistique.getSelection())){
+            ligneSup = new boolean[4];
+            ligneSup[0]=trigrammeXOX.isSelected();
+            ligneSup[1]=trigrammeXOY.isSelected();
+            ligneSup[2]=trigrammeXYZ.isSelected();
+            ligneSup[3]=trigrammeXXX.isSelected();
+        }
+        else if("Digramme".equals(champstatistique.getSelection())){
+            ligneSup = new boolean[1];
+            ligneSup[0]=digrammeXX.isSelected();
+        }
+        else{
+            ligneSup = new boolean[0];
+        }
+        ((DefaultTableModel) resultatstatistique.getModel()).setDataVector(
+                this.ngrammesModel.gettableau(ligneSup),new String[]{champstatistique.getSelection()
+                        ,"Nombre d'occurences","Fréquence","Position moyenne"});
+        resultatstatistique.setAutoCreateRowSorter(true);
+          
+      }
+  }
+  
+  @Override
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource().equals(saisiechampchaine)) {
+        this.valsAfficheesautrestat.clear();
+        initstat();
+        return;
+      }
+      if (evt.getSource().equals(champstatistique)) {
+          this.valsAfficheesautrestat.clear();
+          initstat();
+        return;
+      }
+      if (evt.getSource().equals(typeChamp)) {
+          if(!typeChamp.pasdeSelection()){
+            switch(typeChamp.getSelection()){
+                case "Chaine" :
+                    saisiechampchaine.removeActionListener(this);
+                    saisiechampchaine.setModele(vue.getNomsChamps(Schema.class, typeChaines));
+                    saisiechampchaine.addActionListener(this);                       
+                    break;
+                case "Unité" :
+                    saisiechampchaine.removeActionListener(this);
+                    saisiechampchaine.setModele(vue.getNomsChamps(Unite.class, typeUnites));
+                    saisiechampchaine.addActionListener(this);                        
+                    break;
+                default :
+                    saisiechampchaine.removeActionListener(this);
+                    saisiechampchaine.setModeleVide();
+                    saisiechampchaine.addActionListener(this);                      
+                    break;
+            }
+          }
+          else{
+                saisiechampchaine.removeActionListener(this);
+                saisiechampchaine.setModeleVide();
+                saisiechampchaine.addActionListener(this);                 
+          }
+        return;
+      } 
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+
+  @Override
+  public void traiterEvent(Message evt) { // très grossier : à améliorer
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        return;
+      case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+        throw new UnsupportedOperationException("Fenêtre chaines présente lors d'un message NEW_CORPUS ???");
+      case MODIF_TEXTE:
+        return;
+      case MODIF_VUE:
+        return;
+      case MODIF_STRUCTURE:
+        return;
+      case MODIF_ELEMENT:
+//        ElementEvent evtE = (ElementEvent) evt;
+//        if (evtE.getModif() != TypeModifElement.BORNES_UNITE) fermerFenetre();
+        return;
+      case CORPUS_SAVED:
+          return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+  }
+  
+  public void init(){
+      
+    typeChamp.removeActionListener(this);
+    typeChamp.setModele(new String[]{"Chaine","Unité"});
+    typeChamp.setSelectedIndex(0);
+    typeChamp.addActionListener(this);      
+    saisiechampchaine.removeActionListener(this);
+    //saisiechampchaine.setModele(vue.getNomsChamps(Schema.class, typeChaines));
+    saisiechampchaine.setModeleVide();
+    saisiechampchaine.addActionListener(this);    
+    champstatistique.removeActionListener(this);
+    champstatistique.setModele(statpossibles);
+    champstatistique.addActionListener(this);    
+    if(vue!=null && donneesChaines!=null){
+        initstat();
+    }
+      
+  }
+  
+  public void initVide(){
+    saisiechampchaine.setModeleVide();
+    champstatistique.setModeleVide();
+    typeChamp.setModeleVide();
+      
+  }
+  
+  public Object[][] donneesCSV(){
+        Object[][] donneesCSV = new Object[resultatstatistique.getRowCount()+1][resultatstatistique.getColumnCount()];
+        for(int i = 0 ; i < resultatstatistique.getRowCount();i++){
+             for(int j = 0 ; j < resultatstatistique.getColumnCount();j++){
+                donneesCSV[i+1][j]=resultatstatistique.getValueAt(i, j);
+             }
+        }
+        for(int j = 0 ; j < resultatstatistique.getColumnCount();j++){
+                donneesCSV[0][j]=resultatstatistique.getColumnName(j);
+        }
+        return donneesCSV;
+  }
+
+
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/NgrammesPanel.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/NgrammesModel.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/NgrammesModel.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/NgrammesModel.java	(revision 3653)
@@ -0,0 +1,379 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package visuAnalec.chaines;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import visuAnalec.elements.Schema;
+import visuAnalec.elements.Unite;
+import visuAnalec.vue.Vue;
+
+/**
+ *
+ * @author marc
+ */
+public class NgrammesModel {
+	
+	public class ngramme {
+		
+		private HashSet<Unite[]> unites;
+		
+		private ArrayList<String> suivant;
+		
+		private float frequence;
+		
+		private float posmoyenne;
+		
+		public HashSet<Unite[]> getUnites() {
+			return unites;
+		}
+		
+		public int getnboccurences() {
+			return unites.size();
+		}
+		
+		public float getfrequence() {
+			return frequence;
+		}
+		
+		public float getposmoyenne() {
+			return posmoyenne;
+		}
+		
+		public void setposmoyenne() {
+			float somme = 0.0f;
+			for (Unite[] unit : unites) {
+				somme = somme + unit[0].getDeb();
+			}
+			this.posmoyenne = somme / unites.size();
+		}
+		
+		public void setfrequence(HashMap<String, ngramme> total) {
+			int somme = 0;
+			for (String code : total.keySet()) {
+				somme = somme + total.get(code).getnboccurences();
+			}
+			this.frequence = this.unites.size() * 10000.0f / somme / 100.0f;
+		}
+		
+		public void addUnites(Unite[] donnees) {
+			this.unites.add(donnees);
+		}
+		
+		public void addSuivant(String suivant) {
+			this.suivant.add(suivant);
+		}
+		
+		public ngramme() {
+			this.unites = new HashSet<>();
+			this.frequence = 0.0f;
+			this.posmoyenne = 0.0f;
+			this.suivant = new ArrayList<>();
+		}
+		
+		public ngramme(HashSet<Unite[]> unites, ArrayList<String> suivant) {
+			this.frequence = 0.0f;
+			this.unites = unites;
+			this.suivant = suivant;
+			setposmoyenne();
+		}
+	}
+	
+	private HashMap<String, ngramme> collection;
+	
+	public NgrammesModel() {
+		this.collection = new HashMap();
+	}
+	
+	public NgrammesModel(HashMap<String, ngramme> collection) {
+		this.collection = collection;
+	}
+	
+	public void setallfrequence() {
+		for (String code : this.collection.keySet()) {
+			this.collection.get(code).setfrequence(this.collection);
+		}
+	}
+	
+	public void setallposmoyenne() {
+		for (String code : this.collection.keySet()) {
+			this.collection.get(code).setposmoyenne();
+		}
+	}
+	
+	
+	// @require : les unités doivent être classées par ordre d'apparition
+	public void ngrammeUpdate(int nbLettre, HashMap<String, Character> legende, String champ, Vue vue, boolean glissant, ModeleChaines donnees, boolean singleton, String typeChamp,
+			boolean activeParagraphe) {
+		
+		ArrayList<Character> suiteLettre = new ArrayList<>();
+		String ngrammeCourant;
+		Unite[] unites = donnees.getUnites();
+		HashMap<String, ngramme> collection = new HashMap<>();
+		HashMap<Unite, Integer> noparagraphe = ChaineUtil.unitenumeroparagraphe(unites, vue);
+		int pas;
+		// on définit le pas de boucle en fonction du choix de l'utilisateur (glissant ou pas glissant)
+		if (glissant) {
+			pas = 1;
+		}
+		else {
+			pas = nbLettre;
+		}
+		// on crée la chaîne de lettres
+		for (int i = 0; i < unites.length; i++) {
+			Schema chaine;
+			if (singleton || donnees.getSchemacontenantunite((donnees.getUnites())[i]) != null) {
+				switch (typeChamp) {
+					case "Chaine":
+						chaine = donnees.getSchemacontenantunite(unites[i]);
+						suiteLettre.add(chaine == null ? legende.get("singleton")
+								: (legende.get(vue.getValeurChamp(
+										chaine, champ))) == null ? legende.get("autre") : legende.get(vue.getValeurChamp(chaine, champ)));
+						break;
+					default:
+						suiteLettre.add(legende.get(vue.getValeurChamp(
+								unites[i], champ)) == null ? legende.get("autre") : legende.get(vue.getValeurChamp(unites[i], champ)));
+						break;
+				}
+				if (activeParagraphe && i < (unites.length - 1) && noparagraphe.get(unites[i]) < noparagraphe.get(unites[i + 1])) {
+					suiteLettre.add('0');
+				}
+			}
+		}
+		// on retient le numéro d'unité qui va être lue
+		int numeroUnite = 0;
+		// on parcours la chaîne pour créer les ngrammes
+		for (int i = 0; i < suiteLettre.size() - (nbLettre - 1); i = i + pas) {
+			ArrayList<Unite> ajout = new ArrayList<>();
+			ngrammeCourant = "";
+			int nbUnite = 0;
+			// on crée le code constitué de nbLettre lettres
+			for (int j = 0; j < nbLettre; j++) {
+				ngrammeCourant = ngrammeCourant + suiteLettre.get(j + i);
+				// si ce n'est pas un saut de paragraphe alors on incrémente le numéro de l'unité qui va être lue
+				if (!suiteLettre.get(j + i).equals('0')) {
+					ajout.add(unites[numeroUnite + nbUnite]);
+					nbUnite++;
+				}
+			}
+			// on crée le ngramme obtenu
+			if (!collection.containsKey(ngrammeCourant)) {
+				collection.put(ngrammeCourant, new ngramme());
+			}
+			(collection.get(ngrammeCourant)).addUnites(
+					ajout.toArray(new Unite[0]));
+			// on recherche l'éventuel suivant
+			if (i < suiteLettre.size() - nbLettre) {
+				(collection.get(ngrammeCourant)).addSuivant(suiteLettre.get(i + nbLettre).toString());
+			}
+			// si la première lettre correspond à une unité et non un suat de paragraphe on incrémente numeroUnite
+			if (!suiteLettre.get(i).equals('0')) {
+				numeroUnite++;
+			}
+		}
+		this.collection = collection;
+		setallfrequence();
+		setallposmoyenne();
+	}
+	
+	
+	public HashMap<String, ngramme> getCollection() {
+		return this.collection;
+	}
+	
+	public Object[][] gettableau(boolean[] ligneSup) {
+		Object[][] donnees;
+		int nbRowSup = 0;
+		for (int i = 0; i < ligneSup.length; i++) {
+			if (ligneSup[i]) {
+				nbRowSup++;
+			}
+		}
+		donnees = new Object[collection.size() + nbRowSup][4];
+		
+		int compte = 0;
+		for (String unit : collection.keySet()) {
+			donnees[compte][0] = unit;
+			donnees[compte][1] = collection.get(unit).getnboccurences();
+			donnees[compte][2] = collection.get(unit).getfrequence();
+			donnees[compte][3] = collection.get(unit).getposmoyenne();
+			compte++;
+		}
+		if (collection.size() > 0) {
+			// on ajoute les éventuelles lignes supplémentaires
+			switch (this.collection.keySet().iterator().next().length()) {
+				// si on a des digrammes
+				case 2:
+					if (ligneSup[0]) {
+						donnees[compte] = calculXX();
+						compte++;
+					}
+					break;
+				// si on a des trigrammes
+				case 3:
+					if (ligneSup[0]) {
+						donnees[compte] = calculXOX();
+						compte++;
+					}
+					if (ligneSup[1]) {
+						donnees[compte] = calculXOY();
+						compte++;
+					}
+					if (ligneSup[2]) {
+						donnees[compte] = calculXYZ();
+						compte++;
+					}
+					if (ligneSup[3]) {
+						donnees[compte] = calculXXX();
+						compte++;
+					}
+					break;
+				default:
+					break;
+			}
+		}
+		return donnees;
+		
+	}
+	
+	// @require : le ngrammes contient des digrammes
+	public Object[] calculXX() {
+		Object[] retour = new Object[4];
+		Float frequencecumulee = 0.0f;
+		Float positionmoyenne = 0.0f;
+		Integer Nboccurences = 0;
+		for (String doubletcourant : this.collection.keySet()) {
+			if (doubletcourant.charAt(0) == doubletcourant.charAt(1)) {
+				frequencecumulee = frequencecumulee + this.collection.get(doubletcourant).getfrequence();
+				positionmoyenne = positionmoyenne + this.collection.get(doubletcourant).getnboccurences()
+						* this.collection.get(doubletcourant).getposmoyenne();
+				Nboccurences = Nboccurences + this.collection.get(doubletcourant).getnboccurences();
+			}
+		}
+		positionmoyenne = Math.round(100 * positionmoyenne / Nboccurences) / 100.0f;
+		retour[0] = "xx";
+		retour[1] = Nboccurences;
+		retour[2] = frequencecumulee;
+		retour[3] = positionmoyenne;
+		return retour;
+	}
+	
+	public String[] infoSuivant(String code) {
+		HashMap<String, Integer> totaux = new HashMap();
+		// on recense les lettres suivants le ngramme identifié par "code"
+		for (String next : this.collection.get(code).suivant) {
+			if (totaux.containsKey(next)) {
+				totaux.put(next, totaux.get(next) + 1);
+			}
+			else {
+				totaux.put(next, 1);
+			}
+		}
+		String[] retour = new String[totaux.size()];
+		int i = 0;
+		// on calcule des statistiques
+		for (String next : totaux.keySet()) {
+			retour[i] = code + next + "   Nombre d'occurences : " + totaux.get(next).toString() +
+					"   Fréquence : " + (Math.round(100.0f * totaux.get(next) / this.collection.get(code).suivant.size()) / 100.0f);
+			i = i + 1;
+		}
+		return retour;
+	}
+	
+	// @require : le ngrammes contient des digrammes
+	public Object[] calculXOX() {
+		Object[] retour = new Object[4];
+		Float frequencecumulee = 0.0f;
+		Float positionmoyenne = 0.0f;
+		Integer Nboccurences = 0;
+		for (String tripletcourant : this.collection.keySet()) {
+			if (tripletcourant.charAt(0) == tripletcourant.charAt(2) && tripletcourant.charAt(1) == '0') {
+				frequencecumulee = frequencecumulee + this.collection.get(tripletcourant).getfrequence();
+				positionmoyenne = positionmoyenne + this.collection.get(tripletcourant).getnboccurences()
+						* this.collection.get(tripletcourant).getposmoyenne();
+				Nboccurences = Nboccurences + this.collection.get(tripletcourant).getnboccurences();
+			}
+		}
+		positionmoyenne = Math.round(100 * positionmoyenne / Nboccurences) / 100.0f;
+		retour[0] = "x0x";
+		retour[1] = Nboccurences;
+		retour[2] = frequencecumulee;
+		retour[3] = positionmoyenne;
+		return retour;
+	}
+	
+	// @require : le ngrammes contient des digrammes
+	// on recherche les triplets séparés par des paragraphe au extrémités différentes
+	public Object[] calculXOY() {
+		Object[] retour = new Object[4];
+		Float frequencecumulee = 0.0f;
+		Float positionmoyenne = 0.0f;
+		Integer Nboccurences = 0;
+		for (String tripletcourant : this.collection.keySet()) {
+			if (tripletcourant.charAt(1) == '0' && tripletcourant.charAt(0) != tripletcourant.charAt(2)) {
+				frequencecumulee = frequencecumulee + this.collection.get(tripletcourant).getfrequence();
+				positionmoyenne = positionmoyenne + this.collection.get(tripletcourant).getnboccurences()
+						* this.collection.get(tripletcourant).getposmoyenne();
+				Nboccurences = Nboccurences + this.collection.get(tripletcourant).getnboccurences();
+			}
+		}
+		positionmoyenne = Math.round(100 * positionmoyenne / Nboccurences) / 100.0f;
+		retour[0] = "x0y";
+		retour[1] = Nboccurences;
+		retour[2] = frequencecumulee;
+		retour[3] = positionmoyenne;
+		return retour;
+	}
+	
+	// @require : le ngrammes contient des digrammes
+	public Object[] calculXYZ() {
+		Object[] retour = new Object[4];
+		Float frequencecumulee = 0.0f;
+		Float positionmoyenne = 0.0f;
+		Integer Nboccurences = 0;
+		for (String tripletcourant : this.collection.keySet()) {
+			if (tripletcourant.charAt(1) != tripletcourant.charAt(2) && tripletcourant.charAt(0) != tripletcourant.charAt(1) &&
+					tripletcourant.charAt(0) != tripletcourant.charAt(2) && tripletcourant.charAt(1) != '0') {
+				frequencecumulee = frequencecumulee + this.collection.get(tripletcourant).getfrequence();
+				positionmoyenne = positionmoyenne + this.collection.get(tripletcourant).getnboccurences()
+						* this.collection.get(tripletcourant).getposmoyenne();
+				Nboccurences = Nboccurences + this.collection.get(tripletcourant).getnboccurences();
+			}
+		}
+		positionmoyenne = Math.round(100 * positionmoyenne / Nboccurences) / 100.0f;
+		retour[0] = "xyz";
+		retour[1] = Nboccurences;
+		retour[2] = frequencecumulee;
+		retour[3] = positionmoyenne;
+		return retour;
+	}
+	
+	// @require : le ngrammes contient des digrammes
+	public Object[] calculXXX() {
+		Object[] retour = new Object[4];
+		Float frequencecumulee = 0.0f;
+		Float positionmoyenne = 0.0f;
+		Integer Nboccurences = 0;
+		for (String tripletcourant : this.collection.keySet()) {
+			if (tripletcourant.charAt(1) == tripletcourant.charAt(2) && tripletcourant.charAt(0) == tripletcourant.charAt(1)) {
+				frequencecumulee = frequencecumulee + this.collection.get(tripletcourant).getfrequence();
+				positionmoyenne = positionmoyenne + this.collection.get(tripletcourant).getnboccurences()
+						* this.collection.get(tripletcourant).getposmoyenne();
+				Nboccurences = Nboccurences + this.collection.get(tripletcourant).getnboccurences();
+			}
+		}
+		positionmoyenne = Math.round(100 * positionmoyenne / Nboccurences) / 100.0f;
+		retour[0] = "xxx";
+		retour[1] = Nboccurences;
+		retour[2] = frequencecumulee;
+		retour[3] = positionmoyenne;
+		return retour;
+	}
+	
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/NgrammesModel.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuConversion.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuConversion.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuConversion.java	(revision 3653)
@@ -0,0 +1,348 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package visuAnalec.chaines;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.vue.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author marc
+ */
+public class VisuConversion extends JFrame implements VueListener, ActionListener {
+	
+	private Box PanneauCommande = Box.createVerticalBox();
+	
+	private Box PanneauCommandeSource = Box.createVerticalBox();
+	
+	private Vue vue;
+	
+	private PanneauEditeur panneauEditeur;
+	
+	private JList choixModeConversion = new JList();
+	
+	private JButton lancerConversion = new JButton("Convertir");
+	
+	private JTextField nomSchema = new JTextField("Chaine de coréférence");
+	
+	private Val0ComboBox typeSource = new Val0ComboBox("Rien");
+	
+	private Val0ComboBox primaryKey = new Val0ComboBox("Rien");
+	
+	private String[] otherKey = new String[0];
+	
+	private Val0ComboBox addOtherKey = new Val0ComboBox("Rien");
+	
+	private Val0ComboBox removeOtherKey = new Val0ComboBox("Rien");
+	
+	private String[] sourcesPossibles = new String[] { "Type de Relation", "Type d'unité", "Propriété d'unité" };
+	
+	private String[] typesSourceDisponibles = new String[0];
+	
+	private ArrayList<String> primaryKeyDisponibles = new ArrayList<>();
+	
+	private ArrayList<String> otherKeyDisponibles = new ArrayList<>();
+	
+	private ArrayList<String> otherKeyAjoutees = new ArrayList<>();
+	
+	public VisuConversion(Container fenetre, Vue vue, PanneauEditeur pEditeur) {
+		super("Conversion de données en schéma");
+		Point pos = new Point(fenetre.getX() + 20, fenetre.getY() + 20);
+		Dimension dim = new Dimension(700, 500);
+		setLocation(pos);
+		setSize(dim);
+		this.vue = vue;
+		vue.addEventListener(this);
+		this.panneauEditeur = pEditeur;
+		choixModeConversion.addMouseListener(new MouseAdapter() {
+			
+			@Override
+			public void mousePressed(MouseEvent e) {// on gère les évènements de la souris
+				check(e);
+			}
+			
+			@Override
+			public void mouseReleased(MouseEvent e) {
+				// check(e);
+			}
+			
+			public void check(MouseEvent e) {
+				if (!e.isPopupTrigger()) {// si on a un clique gauche sur la liste
+					listAction(choixModeConversion.getSelectedIndex());
+				}
+			}
+		});
+		lancerConversion.addActionListener(this);
+		PanneauCommandeSource.add(Box.createVerticalStrut(20));
+		PanneauCommandeSource.add(new JLabel("Choix de la source de donnée :"));
+		PanneauCommandeSource.add(Box.createVerticalStrut(20));
+		PanneauCommandeSource.add(choixModeConversion);
+		PanneauCommandeSource.add(Box.createVerticalStrut(20));
+		PanneauCommandeSource.add(lancerConversion);
+		JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, PanneauCommandeSource, PanneauCommande);
+		getContentPane().add(split);
+		split.setDividerLocation(1. / 3);
+		setVisible(true);
+		typeSource.setAlignmentX(0);
+		primaryKey.setAlignmentX(0);
+		addOtherKey.setAlignmentX(0);
+		removeOtherKey.setAlignmentX(0);
+		choixModeConversion.setAlignmentX(0);
+		// Fermeture de la fenêtre
+		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+		addWindowListener(new WindowAdapter() {
+			
+			@Override
+			public void windowClosing(WindowEvent evt) {
+				fermerFenetre();
+			}
+		});
+		initVide();
+	}
+	
+	public void initVide() {
+		PanneauCommande.removeAll();
+		choixModeConversion.setListData(sourcesPossibles);
+	}
+	
+	@Override
+	public void actionPerformed(ActionEvent evt) {
+		try {
+			if (choixModeConversion.isSelectionEmpty()) {
+				initVide();
+				return;
+			}
+			else {
+				switch (choixModeConversion.getSelectedIndex()) {
+					case 0:
+						if (evt.getSource().equals(typeSource)) {
+							primaryKeyDisponibles = vue.getListeChamps(Relation.class, typeSource.getSelection());
+							primaryKey.removeActionListener(this);
+							primaryKey.setModele(primaryKeyDisponibles.toArray(new String[0]));
+							primaryKey.addActionListener(this);
+							return;
+						}
+						if (evt.getSource().equals(primaryKey)) {
+							return;
+						}
+						if (evt.getSource().equals(lancerConversion)) {
+							if (!typeSource.pasdeSelection() && !primaryKey.pasdeSelection()) {
+								ChaineUtil.conversion("Relation", nomSchema.getText(), typeSource.getSelection(),
+										primaryKey.getSelection(), null, vue);
+								fermerFenetre();
+							}
+							return;
+						}
+						break;
+					case 1:
+						if (evt.getSource().equals(lancerConversion)) {
+							ChaineUtil.conversion("typeUnite", nomSchema.getText(), null, null, new String[0], vue);
+							fermerFenetre();
+							return;
+						}
+						break;
+					case 2:
+						if (evt.getSource().equals(typeSource)) {
+							if (!typeSource.pasdeSelection()) {
+								primaryKeyDisponibles = vue.getListeChamps(Unite.class, typeSource.getSelection());
+								primaryKey.removeActionListener(this);
+								primaryKey.setModele(primaryKeyDisponibles.toArray(new String[0]));
+								primaryKey.addActionListener(this);
+								otherKeyDisponibles = vue.getListeChamps(Unite.class, typeSource.getSelection());
+								addOtherKey.removeActionListener(this);
+								addOtherKey.setModele(otherKeyDisponibles.toArray(new String[0]));
+								addOtherKey.addActionListener(this);
+								otherKeyAjoutees = new ArrayList<>();
+								removeOtherKey.removeActionListener(this);
+								removeOtherKey.setModele(otherKeyAjoutees.toArray(new String[0]));
+								removeOtherKey.addActionListener(this);
+							}
+							return;
+						}
+						if (evt.getSource().equals(primaryKey)) {
+							if (!typeSource.pasdeSelection() && !primaryKey.pasdeSelection()) {
+								otherKeyDisponibles = vue.getListeChamps(Unite.class, typeSource.getSelection());
+								otherKeyDisponibles.remove(primaryKey.getSelection());
+								for (String key : otherKeyAjoutees) {
+									otherKeyDisponibles.remove(key);
+								}
+								otherKeyAjoutees.remove(primaryKey.getSelection());
+								addOtherKey.removeActionListener(this);
+								removeOtherKey.removeActionListener(this);
+								addOtherKey.setModele(otherKeyDisponibles.toArray(new String[0]));
+								removeOtherKey.setModele(otherKeyAjoutees.toArray(new String[0]));
+								addOtherKey.addActionListener(this);
+								removeOtherKey.addActionListener(this);
+							}
+							return;
+						}
+						if (evt.getSource().equals(lancerConversion)) {
+							if (!typeSource.pasdeSelection() && !primaryKey.pasdeSelection()) {
+								ChaineUtil.conversion("attributUnite", nomSchema.getText(), typeSource.getSelection(),
+										primaryKey.getSelection(), otherKeyAjoutees.toArray(new String[0]), vue);
+								fermerFenetre();
+							}
+							return;
+						}
+						if (evt.getSource().equals(addOtherKey)) {
+							if (!typeSource.pasdeSelection() && !addOtherKey.pasdeSelection()) {
+								otherKeyDisponibles.remove(addOtherKey.getSelection());
+								otherKeyAjoutees.add(addOtherKey.getSelection());
+								addOtherKey.removeActionListener(this);
+								removeOtherKey.removeActionListener(this);
+								addOtherKey.setModele(otherKeyDisponibles.toArray(new String[0]));
+								removeOtherKey.setModele(otherKeyAjoutees.toArray(new String[0]));
+								addOtherKey.addActionListener(this);
+								removeOtherKey.addActionListener(this);
+							}
+							return;
+						}
+						if (evt.getSource().equals(removeOtherKey)) {
+							if (!typeSource.pasdeSelection() && !removeOtherKey.pasdeSelection()) {
+								otherKeyDisponibles.add(removeOtherKey.getSelection());
+								otherKeyAjoutees.remove(removeOtherKey.getSelection());
+								addOtherKey.removeActionListener(this);
+								removeOtherKey.removeActionListener(this);
+								addOtherKey.setModele(otherKeyDisponibles.toArray(new String[0]));
+								removeOtherKey.setModele(otherKeyAjoutees.toArray(new String[0]));
+								addOtherKey.addActionListener(this);
+								removeOtherKey.addActionListener(this);
+							}
+							return;
+						}
+						break;
+					default:
+						initVide();
+						break;
+					
+				}
+				
+			}
+			throw new UnsupportedOperationException("Evénement non prévu : " + evt.paramString());
+		}
+		catch (Throwable ex) {
+			GMessages.erreurFatale(ex);
+		}
+	}
+	
+	private void fermerFenetre() {
+		vue.removeEventListener(this);
+		dispose();
+	}
+	
+	@Override
+	public void traiterEvent(Message evt) { // très grossier : à améliorer
+		switch (evt.getType()) {
+			case CLEAR_CORPUS:
+				fermerFenetre();
+				return;
+			case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+				throw new UnsupportedOperationException("Fenêtre chaines présente lors d'un message NEW_CORPUS ???");
+			case MODIF_TEXTE:
+				fermerFenetre();
+				return;
+			case MODIF_VUE:
+				fermerFenetre();
+				return;
+			case MODIF_STRUCTURE:
+				fermerFenetre();
+				return;
+			case MODIF_ELEMENT:
+				// ElementEvent evtE = (ElementEvent) evt;
+				// if (evtE.getModif() != TypeModifElement.BORNES_UNITE) fermerFenetre();
+				fermerFenetre();
+				return;
+			case CORPUS_SAVED:
+				fermerFenetre();
+				return;
+			default:
+				throw new UnsupportedOperationException("Cas " + evt.getType() + " oublié dans un switch");
+		}
+	}
+	
+	public void listAction(int Index) {
+		if (!choixModeConversion.isSelectionEmpty()) {
+			PanneauCommande.removeAll();
+			PanneauCommande.add(Box.createVerticalStrut(20));
+			PanneauCommande.add(new JLabel("Saisisez un nom pour votre nouveau type de schéma :"));
+			nomSchema.setMaximumSize(new Dimension(500, 50));
+			PanneauCommande.add(Box.createVerticalStrut(20));
+			PanneauCommande.add(nomSchema);
+			switch (Index) {
+				case 0:
+					PanneauCommande.add(Box.createVerticalStrut(20));
+					PanneauCommande.add(new JLabel("Sélectionner un type de relation :"));
+					PanneauCommande.add(Box.createVerticalStrut(20));
+					PanneauCommande.add(typeSource);
+					PanneauCommande.add(Box.createVerticalStrut(20));
+					PanneauCommande.add(new JLabel("Sélectionner une propriété caractérisant chaque chaine :"));
+					PanneauCommande.add(Box.createVerticalStrut(20));
+					PanneauCommande.add(primaryKey);
+					this.typesSourceDisponibles = vue.getTypesRelationsAVoir();
+					typeSource.removeActionListener(this);
+					typeSource.setModele(typesSourceDisponibles);
+					typeSource.addActionListener(this);
+					this.primaryKeyDisponibles = new ArrayList<>();
+					primaryKey.removeActionListener(this);
+					this.primaryKey.setModele(this.primaryKeyDisponibles.toArray(new String[0]));
+					primaryKey.addActionListener(this);
+					break;
+				case 1:
+					break;
+				case 2:
+					PanneauCommande.add(Box.createVerticalStrut(20));
+					PanneauCommande.add(new JLabel("Sélectionner un type d'unité :"));
+					PanneauCommande.add(Box.createVerticalStrut(20));
+					PanneauCommande.add(typeSource);
+					PanneauCommande.add(Box.createVerticalStrut(20));
+					PanneauCommande.add(new JLabel("Sélectionner une propriété caractérisant chaque chaine :"));
+					PanneauCommande.add(Box.createVerticalStrut(20));
+					PanneauCommande.add(primaryKey);
+					PanneauCommande.add(Box.createVerticalStrut(20));
+					PanneauCommande.add(new JLabel("Sélectionner une propriété des unités à ajouter aux schémas :"));
+					PanneauCommande.add(Box.createVerticalStrut(20));
+					PanneauCommande.add(addOtherKey);
+					PanneauCommande.add(Box.createVerticalStrut(20));
+					PanneauCommande.add(new JLabel("Sélectionner une propriété des unités à enlever aux schemas :"));
+					PanneauCommande.add(Box.createVerticalStrut(20));
+					PanneauCommande.add(removeOtherKey);
+					this.typesSourceDisponibles = vue.getTypesUnitesAVoir();
+					typeSource.removeActionListener(this);
+					typeSource.setModele(typesSourceDisponibles);
+					typeSource.addActionListener(this);
+					primaryKey.removeActionListener(this);
+					this.primaryKeyDisponibles = new ArrayList<>();
+					this.primaryKey.setModele(this.primaryKeyDisponibles.toArray(new String[0]));
+					primaryKey.addActionListener(this);
+					this.otherKeyDisponibles = new ArrayList<>();
+					addOtherKey.removeActionListener(this);
+					this.addOtherKey.setModele(this.otherKeyDisponibles.toArray(new String[0]));
+					addOtherKey.addActionListener(this);
+					this.otherKeyAjoutees = new ArrayList<>();
+					removeOtherKey.removeActionListener(this);
+					this.removeOtherKey.setModele(this.otherKeyAjoutees.toArray(new String[0]));
+					removeOtherKey.addActionListener(this);
+					break;
+				default:
+					PanneauCommande.removeAll();
+					break;
+			}
+			revalidate();
+			repaint();
+		}
+	}
+	
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/VisuConversion.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ExportCSV.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ExportCSV.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ExportCSV.java	(revision 3653)
@@ -0,0 +1,223 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package visuAnalec.chaines;
+
+import com.itextpdf.awt.DefaultFontMapper;
+import com.itextpdf.text.Document;
+import com.itextpdf.text.pdf.PdfContentByte;
+import com.itextpdf.text.pdf.PdfTemplate;
+import com.itextpdf.text.pdf.PdfWriter;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.Rectangle2D;
+import java.io.File;
+import java.io.FileOutputStream;
+import javax.swing.*;
+import org.jfree.chart.ChartPanel;
+import visuAnalec.*;
+import visuAnalec.fichiers.FichiersTexte;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.GAction;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Marc
+ */
+public class ExportCSV extends JFrame implements Vue.VueListener, ActionListener{
+    private Vue vue;
+    private PanneauEditeur panneauEditeur;
+    private JCheckBox activeChamp1;
+    private JCheckBox activeChamp2;
+    private JCheckBox activeChamp3;
+    private JCheckBox activeChamp4;
+    private JCheckBox activeChamp5;
+    private JCheckBox activeChampChaine;
+    private JCheckBox activeChampUnite;
+    private JCheckBox activeChampParagraphe;
+    private JButton exporter;
+    
+    
+    public ExportCSV(Container fenetre, Vue vue, PanneauEditeur pEditeur, VisuCoref visucoref){
+        super("Analyse générale du texte");
+        Point pos = new Point(fenetre.getX()+20, fenetre.getY()+20);
+        Dimension dim = new Dimension(300, 500);
+        setLocation(pos);
+        setSize(dim);
+        this.panneauEditeur = pEditeur;
+        final VisuCoref visucorefs = visucoref;
+        final VisuChaines visuchaine = null;
+        this.vue = vue;
+        vue.addEventListener(this);
+        Box commandes = Box.createVerticalBox();
+        commandes.add(this.activeChampChaine = new JCheckBox("Afficher le Champ de la Chaine"));
+        commandes.add(Box.createVerticalStrut(20));
+        commandes.add(this.activeChampUnite = new JCheckBox("Afficher le Champ ds Unités"));
+        commandes.add(Box.createVerticalStrut(20));
+        commandes.add(this.activeChampParagraphe = new JCheckBox("Afficher le numéro des paragraphes"));
+        commandes.add(Box.createVerticalStrut(20));
+        commandes.add(this.exporter=new JButton("Exporter"));
+        exporter.setAction(new GAction("exporter") {
+            public void executer() {
+              exporterCSV(visucorefs.donneesCSV(new boolean[]{activeChampUnite.isSelected(),activeChampChaine.isSelected(),
+              activeChampParagraphe.isSelected()}));
+              fermerFenetre();
+            }
+          });
+        exporter.setSize(100, 40);
+        exporter.setVisible(true);
+        getContentPane().add(commandes);
+        setVisible(true);
+        // Fermeture de la fenêtre
+        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+        addWindowListener(new WindowAdapter() {
+        @Override
+        public void windowClosing(WindowEvent evt) {
+         fermerFenetre();
+        }
+        });
+    }
+    
+    public ExportCSV(Container fenetre, Vue vue, PanneauEditeur pEditeur, VisuChaines visuchaine){
+        super("Analyse générale du texte");
+        Point pos = new Point(fenetre.getX()+20, fenetre.getY()+20);
+        Dimension dim = new Dimension(300, 500);
+        setLocation(pos);
+        setSize(dim);
+        this.panneauEditeur = pEditeur;
+        final VisuCoref visucoref = null;
+        final VisuChaines visuchaines = visuchaine;
+        this.vue = vue;
+        vue.addEventListener(this);
+        Box commandes = Box.createVerticalBox();
+        commandes.add(this.activeChamp1 = new JCheckBox("Afficher le Champ1"));
+        commandes.add(Box.createVerticalStrut(20));
+        commandes.add(this.activeChamp2 = new JCheckBox("Afficher le Champ2"));
+        commandes.add(Box.createVerticalStrut(20));
+        commandes.add(this.activeChamp3 = new JCheckBox("Afficher le Champ3"));
+        commandes.add(Box.createVerticalStrut(20));
+        commandes.add(this.activeChamp4 = new JCheckBox("Afficher le Champ4"));
+        commandes.add(Box.createVerticalStrut(20));
+        commandes.add(this.activeChamp5 = new JCheckBox("Afficher le Champ5"));
+        commandes.add(Box.createVerticalStrut(20));
+        commandes.add(this.exporter=new JButton("Exporter"));
+        exporter.setAction(new GAction("exporter") {
+            public void executer() {
+              exporterCSV(visuchaines.donneesCSV(new boolean[]{activeChamp1.isSelected(),activeChamp2.isSelected(),
+              activeChamp3.isSelected(),activeChamp4.isSelected(),activeChamp5.isSelected()}));
+              fermerFenetre();
+            }
+          });
+        exporter.setSize(100, 40);
+        exporter.setVisible(true);
+        getContentPane().add(commandes);
+        setVisible(true);
+        // Fermeture de la fenêtre
+        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+        addWindowListener(new WindowAdapter() {
+        @Override
+        public void windowClosing(WindowEvent evt) {
+         fermerFenetre();
+        }
+        });
+    }    
+    
+       private void fermerFenetre() {
+        vue.removeEventListener(this);
+        dispose();
+        }
+    
+    public void traiterEvent(Message evt) { // très grossier : à améliorer
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        fermerFenetre();
+        return;
+      case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+        throw new UnsupportedOperationException("Fenêtre chaines présente lors d'un message NEW_CORPUS ???");
+      case MODIF_TEXTE:
+        fermerFenetre();
+        return;
+      case MODIF_VUE:
+        fermerFenetre();
+        return;
+      case MODIF_STRUCTURE:
+        fermerFenetre();
+        return;
+      case MODIF_ELEMENT:
+//        ElementEvent evtE = (ElementEvent) evt;
+//        if (evtE.getModif() != TypeModifElement.BORNES_UNITE) fermerFenetre();
+        fermerFenetre();
+        return;
+      case CORPUS_SAVED:
+          fermerFenetre();
+          return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+  }
+    
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  
+  public static void exporterCSV(Object[][] donnees){
+      JOptionPane jop = new JOptionPane();
+      String delimiteur = jop.showInputDialog(null, "Veuillez saisir un délimiteur d'un caractère maximum"
+              , "Saisie délimiteur pour export en UTF-8", JOptionPane.QUESTION_MESSAGE);
+      if(delimiteur!=null && !delimiteur.isEmpty() && delimiteur.length()==1){
+          String texte = "";
+          for(Object[] ligne : donnees){
+              for(Object cellule : ligne){
+                  texte = texte + (cellule==null ? "" : cellule.toString().replaceAll(delimiteur, "")) + delimiteur;
+              }
+              texte = texte + System.getProperty("line.separator");
+          }
+          FichiersTexte.exporterCSV(texte);
+      }
+  }
+  /*ajouté probablement dans la mauvaise classe, la package fichier semble plus adapté pour recevoir les classes*/
+  /*ici on laisse l'utilisateur choisir un dossier où enregistrer*/
+  public static void writeChartToPDF(ChartPanel chart,int width,int height) {
+    String fileName="";
+    
+    File fichierGraphique;
+    if ((fichierGraphique = Fichiers.choisirFichier(Fichiers.Commande.ENREGISTRER,
+            "Nom du fichier ?", Fichiers.TypeFichier.PDF)) == null) return;
+    
+    fileName = fichierGraphique.getAbsolutePath();
+            
+    
+    PdfWriter writer = null;
+ 
+    Document document = new Document();
+ 
+    try {
+        writer = PdfWriter.getInstance(document,  new FileOutputStream(
+                fileName));
+        document.open();
+        PdfContentByte contentByte = writer.getDirectContent();
+        PdfTemplate template = contentByte.createTemplate(width, height);
+        Graphics2D graphics2d = template.createGraphics(width, height,
+                new DefaultFontMapper());
+        Rectangle2D rectangle2d = new Rectangle2D.Double(0, 0, width,
+                height);
+ 
+        chart.getChart().draw(graphics2d, rectangle2d);
+         
+        graphics2d.dispose();
+        contentByte.addTemplate(template, 0, 0);
+ 
+    } catch (Exception e) {
+        e.printStackTrace();
+    }
+    document.close();
+}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/chaines/ExportCSV.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/VisuMain.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/VisuMain.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/VisuMain.java	(revision 3653)
@@ -0,0 +1,515 @@
+package visuAnalec;
+
+/**
+ *
+ * @author bernard
+ */
+import javax.swing.*;
+import java.awt.event.*;
+import java.awt.*;
+import java.io.*;
+import visuAnalec.Message.*;
+import visuAnalec.chaines.*;
+import visuAnalec.donnees.*;
+import visuAnalec.fichiers.*;
+import visuAnalec.statistiques.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.vue.*;
+import visuAnalec.vue.Vue.*;
+
+@SuppressWarnings("serial")
+public class VisuMain extends JFrame implements VueListener {
+  private Corpus corpus;
+  private Vue vue;
+  private PanneauEditeur panneauEditeur;
+  private String nomCorpus = "";
+  private String nomVue = "";
+  private static String[] args;
+  VisuMain() {
+    super();
+    corpus = new Corpus();
+    vue = new Vue(corpus);
+    panneauEditeur = new PanneauEditeur(vue);
+    vue.addEventListener(this);
+    // Cadre global de la fenêtre
+    setContentPane(panneauEditeur);
+    // Menus
+    JMenuBar menuBar = new JMenuBar();
+    setJMenuBar(menuBar);
+
+    // Menu corpus
+    JMenu corpusMenu = new JMenu("Documents");
+    corpusMenu.setMnemonic(KeyEvent.VK_D);
+    menuBar.add(corpusMenu);
+    corpusMenu.add(new GAction("Ouvrir...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersJava.ouvrirCorpusVue(corpus, vue, "");
+        //       System.out.println(corpus.getStructure());
+      }
+    });
+    JMenuItem item;
+    corpusMenu.add(item = new JMenuItem(new GAction("Enregistrer") {
+      public void executer() {
+        if (corpus.isVide()) return;
+        if (!nomCorpus.isEmpty()) {
+          File fichier = Fichiers.getFichierCourant(Fichiers.TypeFichier.DOC_ANALEC);
+          if (FichiersJava.enregistrerCorpus(corpus, fichier)) setTitre();
+        } else if (FichiersJava.enregistrerCorpusSous(corpus)) {
+          nomCorpus = Fichiers.getNomFichierCourant(Fichiers.TypeFichier.DOC_ANALEC);
+          setTitre();
+        }
+      }
+    }));
+    corpusMenu.add(new GAction("Enregistrer sous...") {
+      public void executer() {
+        if (FichiersJava.enregistrerCorpusSous(corpus)) {
+          nomCorpus = Fichiers.getNomFichierCourant(Fichiers.TypeFichier.DOC_ANALEC);
+          setTitre();
+        }
+      }
+    });
+    corpusMenu.add(new GAction("Fermer") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+      }
+    });
+    corpusMenu.insertSeparator(corpusMenu.getMenuComponentCount());
+    corpusMenu.add(new GAction("Fusionner des annotations") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        FichiersJava.fusionnerAnnot(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Concaténer deux documents") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        FichiersJava.concatenerDocuments(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Concaténer un corpus") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersJava.concatenerCorpus(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Extraire un type d'un corpus") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        String type = JOptionPane.showInputDialog("Nom du type d'unité à extraire");
+        if (type==null) return;
+        corpus.fermer();
+        FichiersJava.extraireTypeCorpus(type, corpus);
+      }
+    });
+    corpusMenu.insertSeparator(corpusMenu.getMenuComponentCount());
+    corpusMenu.add(new GAction("Importer du texte brut...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        int rep = 0;
+        if (!corpus.getStructure().isVide()) {
+          rep = JOptionPane.showOptionDialog(null, "Utiliser la structure actuelle pour le nouveau document ?",
+                  "Structure déjà présente", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+                  null, new Object[]{"Oui", "Non", "Annuler"}, "Oui");
+          if (rep==2) return;
+        }
+        if (rep==0) corpus.fermerConserverStructure();
+        else corpus.fermer();
+        FichiersTexte.importerTexte(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Importer des données Excel...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersTableur.importerExcel(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Importer des données Syntex...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersSyntex.importerSyntex(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Importer des données Glozz...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersGlozz.importerGlozz(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Exporter des données Glozz...") {
+      public void executer() {
+        FichiersGlozz.exporterGlozz(corpus);
+      }
+    });
+    corpusMenu.add(new GAction("Convertir un corpus Glozz...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersGlozz.convertirCorpusGlozz(corpus);
+      }
+    });
+   corpusMenu.add(new GAction("Exporter un corpus TEI...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersTEI.exporterCorpusTEI(corpus);
+      }
+    });
+   corpusMenu.add(new GAction("Convertir un corpus TEI...") {
+      public void executer() {
+        if (!sauvegarde()) return;
+        corpus.fermer();
+        FichiersTEI.convertirCorpusTEI(corpus);
+     }
+    });
+    corpusMenu.insertSeparator(corpusMenu.getMenuComponentCount());
+    corpusMenu.add(new GAction("Quitter") {
+      public void executer() {
+        fermerFenetre();
+      }
+    });
+
+    // Menu structure
+    JMenu structureMenu = new JMenu("Structure");
+    structureMenu.setMnemonic(KeyEvent.VK_S);
+    menuBar.add(structureMenu);
+    structureMenu.add(new GAction("Gestion de la structure...") {
+      public void executer() {
+        VisuStructure visuStructure = VisuStructure.newVisuStructure(getContentPane(), corpus);
+        visuStructure.setExtendedState(NORMAL);
+        visuStructure.setVisible(true);
+        visuStructure.agencer();
+      }
+    });
+    structureMenu.add(new GAction("Ouvrir...") {
+      public void executer() {
+        if (!fusionStructure()) return;
+        FichiersJava.ouvrirStructure(corpus);
+      }
+    });
+    structureMenu.add(item = new JMenuItem(new GAction("Enregistrer...") {
+      public void executer() {
+        FichiersJava.enregistrerStructure(corpus);
+        setTitre();
+      }
+    }));
+    structureMenu.add(new GAction("Importer un modèle Glozz...") {
+      public void executer() {
+        if (!fusionStructure()) return;
+        FichiersGlozz.importerModeleGlozz(corpus);
+        //       System.out.println(corpus.getStructure());
+      }
+    });
+    structureMenu.add(new GAction("Exporter un modèle Glozz...") {
+      public void executer() {
+        FichiersGlozz.exporterModeleGlozz(corpus.getStructure());
+      }
+    });
+
+    // Menu vue
+    JMenu vueMenu = new JMenu("Vue");
+    menuBar.add(vueMenu);
+    vueMenu.add(new GAction("Gestion de la vue...") {
+      public void executer() {
+        VisuVue.newVisuVue(getContentPane(), vue);
+      }
+    });
+    vueMenu.add(new GAction("Ouvrir (.ecv)...") {
+      public void executer() {
+        FichiersJava.ouvrirVue(vue);
+      }
+    });
+    vueMenu.add(new GAction("Enregistrer (.ecv)...") {
+      public void executer() {
+        if (FichiersJava.enregistrerVue(vue)) {
+          nomVue = Fichiers.getNomFichierCourant(Fichiers.TypeFichier.VUE);
+          setTitre();
+        }
+      }
+    });
+    vueMenu.add(new GAction("Rétablir la vue par défaut") {
+      public void executer() {
+        nomVue = "";
+        vue.retablirVueParDefaut();
+      }
+    });
+
+    // Menu texte
+    JMenu texteMenu = new JMenu("Texte");
+    texteMenu.setMnemonic(KeyEvent.VK_T);
+    menuBar.add(texteMenu);
+    texteMenu.add(new GAction("Modifier le texte") {
+      public void executer() {
+        panneauEditeur.initModifierTexte();
+      }
+    });
+    texteMenu.insertSeparator(texteMenu.getMenuComponentCount());
+    texteMenu.add(item = new JMenuItem(new GAction("Rechercher...") {
+      public void executer() {
+        panneauEditeur.initRechercherTexte();
+      }
+    }));
+    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, ActionEvent.CTRL_MASK));
+    texteMenu.add(item = new JMenuItem(new GAction("Suivant") {
+      public void executer() {
+        panneauEditeur.rechercherSuivantTexte();
+      }
+    }));
+    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, ActionEvent.CTRL_MASK));
+    texteMenu.insertSeparator(texteMenu.getMenuComponentCount());
+    texteMenu.add(new GAction("Style du document...") {
+      public void executer() {
+        panneauEditeur.saisirStyleTexte(vue);
+      }
+    });
+    texteMenu.add(new GAction("Exporter format RTF...") {
+      public void executer() {
+        FichiersTexte.exporterTexteRTF(panneauEditeur);
+      }
+    });
+    texteMenu.add(new GAction("Exporter format HTML...") {
+      public void executer() {
+        FichiersTexte.exporterTexteHTML(panneauEditeur);
+      }
+    });
+
+
+    // Menu unités
+    JMenu unitesMenu = new JMenu("Unités");
+    unitesMenu.setMnemonic(KeyEvent.VK_U);
+    menuBar.add(unitesMenu);
+    unitesMenu.add(new GAction("Gestion des unités") {
+      public void executer() {
+        panneauEditeur.initGestionUnites();
+      }
+    });
+    unitesMenu.add(new GAction("Création d'unités typographiques") {
+      public void executer() {
+        GMessages.pasImplemente();
+      }
+    });
+    unitesMenu.add(new GAction("Création d'unités de constituance") {
+      public void executer() {
+        GMessages.pasImplemente();
+      }
+    });
+
+    // Menu relations
+    JMenu relationsMenu = new JMenu("Relations");
+    relationsMenu.setMnemonic(KeyEvent.VK_R);
+    relationsMenu.setMnemonic(KeyEvent.VK_R);
+    menuBar.add(relationsMenu);
+    relationsMenu.add(new GAction("Gestion des relations") {
+      public void executer() {
+        panneauEditeur.initGestionRelations();
+      }
+    });
+    relationsMenu.add(new GAction("Visualisation d'arborescences") {
+      public void executer() {
+        GMessages.pasImplemente();
+      }
+    });
+    relationsMenu.add(new GAction("Saisie d'arborescences") {
+      public void executer() {
+        GMessages.pasImplemente();
+      }
+    });
+    relationsMenu.add(new GAction("Création d'arborescences") {
+      public void executer() {
+        GMessages.pasImplemente();
+      }
+    });
+
+    // Menu schémas
+    JMenu schemasMenu = new JMenu("Schémas");
+    schemasMenu.setMnemonic(KeyEvent.VK_H);
+    menuBar.add(schemasMenu);
+    schemasMenu.add(new GAction("Gestion des schémas") {
+      public void executer() {
+        panneauEditeur.initGestionSchemas();
+      }
+    });
+    schemasMenu.add(new GAction("Création de schémas à partir des annotations") {
+      public void executer() {
+        new VisuConversion(getContentPane(), vue, panneauEditeur);
+      }  
+    }); 
+    schemasMenu.add(new GAction("Visualisation de la suite d'occurences") {
+      public void executer() {
+        new VisuChaines(getContentPane(), vue, panneauEditeur);
+      }
+    });
+    schemasMenu.add(new GAction("Visualisation des chaines de coréférences") {
+      public void executer() {
+        new VisuCoref(getContentPane(), vue, panneauEditeur);
+      }  
+    });
+    schemasMenu.add(new GAction("Statistique Générale") {
+      public void executer() {
+        new VisuStatGenerale(getContentPane(), vue, panneauEditeur);
+      }  
+    });          
+
+    // Menu règles
+    JMenu reglesMenu = new JMenu("Règles");
+    reglesMenu.setMnemonic(KeyEvent.VK_G);
+    menuBar.add(reglesMenu);
+    
+    // Menu Stats
+    JMenu statsMenu = new JMenu("Statistiques");
+    statsMenu.setMnemonic(KeyEvent.VK_A);
+    menuBar.add(statsMenu);
+    statsMenu.add(new GAction("Fréquences...") {
+      public void executer() {
+        new VisuStatsFrequences(getContentPane(), vue, panneauEditeur);
+      }
+    });
+    statsMenu.add(new GAction("Corrélations...") {
+      public void executer() {
+        new VisuStatsCorrelations(getContentPane(), vue, panneauEditeur);
+      }
+    });
+    statsMenu.add(new GAction("Représentations géométriques...") {
+      @SuppressWarnings("ResultOfObjectAllocationIgnored")
+      public void executer() {
+        new VisuStatsGeometrie(getContentPane(), vue, panneauEditeur);
+      }
+    });
+    // Fermeture de la fenêtre
+    setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+    addWindowListener(new WindowAdapter() {
+      @Override
+      public void windowClosing(WindowEvent evt) {
+        fermerFenetre();
+      }
+    });
+
+  }
+  public void premierPlan() {
+    if ((getExtendedState()&Frame.ICONIFIED)>0) {
+      setExtendedState(getExtendedState()&~Frame.ICONIFIED);
+    }
+    toFront();
+
+  }
+  private void fermerFenetre() {
+    if (sauvegarde()) System.exit(0);
+  }
+  boolean sauvegarde() {
+    if (!corpus.isModifie()) return true;
+    int rep = JOptionPane.showOptionDialog(this, "Sauvegarder le document en cours ?",
+            "Document modifié", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+            null, new Object[]{"Oui", "Non", "Annuler"}, "Non");
+    if (rep==2) {
+      return false;
+    }
+    if (rep==0) {
+      FichiersJava.enregistrerCorpusSous(corpus);
+    }
+    return true;
+  }
+  boolean fusionStructure() {
+    if (corpus.getStructure().isVide()) return true;
+    int rep = JOptionPane.showOptionDialog(this, "La nouvelle structure va être fusionnée avec la structure courante",
+            "Structure déjà présente", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+            null, new Object[]{"Poursuivre", "Annuler"}, "Poursuivre");
+    return rep==0;
+  }
+  public void traiterEvent(Message evt) {
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        nomCorpus = "";
+        Fichiers.removeFichierCourant(Fichiers.TypeFichier.DOC_ANALEC);
+        setTitre();
+        return;
+      case NEW_CORPUS:
+        nomCorpus = Fichiers.getNomFichierCourant(Fichiers.TypeFichier.DOC_ANALEC);
+        setTitre();
+        return;
+      case CORPUS_SAVED:
+          return;
+      case MODIF_VUE:
+        switch (((VueEvent) evt).getModif()) {
+          case VUE_DEFAUT:
+            nomVue = "";
+            setTitre();
+            return;
+          case NEW_VUE:
+            nomVue = Fichiers.getNomFichierCourant(Fichiers.TypeFichier.VUE);
+            setTitre();
+            return;
+          case EXTRACTION:
+            setTitre();
+            return;
+          default:
+            throw new UnsupportedOperationException("Cas "+((VueEvent) evt).getModif()+" oublié dans un switch");
+        }
+      case MODIF_TEXTE:
+      case MODIF_STRUCTURE:
+      case MODIF_ELEMENT:
+        setTitre();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+  }
+  private void setTitre() {
+    String titre = "Analec 1.4";
+    if (!nomCorpus.isEmpty()) {
+      titre += " : "+nomCorpus;
+      if (corpus.isModifie()) titre += "*";
+      if (nomVue.isEmpty()) {
+        if (vue.isModifiee()) titre += " - vue modifiée*";
+        else titre += " - vue par défaut";
+      } else {
+        titre += " - vue : "+nomVue;
+        if (vue.isModifiee()) titre += "*";
+      }
+    }
+    setTitle(titre);
+  }
+  public static void main(String[] args) {
+    VisuMain.args = args;
+    javax.swing.SwingUtilities.invokeLater(new Runnable() {
+      public void run() {
+        try {
+          // Fenêtre
+          lancerVisuAnalec();
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    });
+  }
+//    try {
+//      // Fenêtre
+//      lancerVisuAnalec(args);
+//    } catch (Throwable ex) {
+//      GMessages.erreurFatale(ex);
+//    }
+//  }
+  public static void lancerVisuAnalec() throws IOException, ClassNotFoundException {
+    // Fenêtre
+    VisuMain fenetre = new VisuMain();
+    fenetre.setTitre();
+    Rectangle rmax = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
+    fenetre.setLocation(50, 50);
+    fenetre.setSize(rmax.width-100, rmax.height-100);
+    fenetre.setVisible(true);
+    fenetre.panneauEditeur.agencerPanneaux();
+    fenetre.traiterArguments(args);
+//    System.out.println(fenetre.corpus.getStructure().toString());
+//   new GMessages.GProgression(fenetre);
+  }
+  private void traiterArguments(String[] args) throws IOException, ClassNotFoundException {
+    if (args.length==0) return;
+    FichiersJava.ouvrirCorpusVue(corpus, vue, args[0]);
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/VisuMain.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/donnees/VisuStructure.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/donnees/VisuStructure.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/donnees/VisuStructure.java	(revision 3653)
@@ -0,0 +1,684 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.donnees;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.tree.*;
+
+import org.eclipse.osgi.util.NLS;
+import org.txm.utils.logger.Log;
+
+import visuAnalec.*;
+import visuAnalec.Message.*;
+import visuAnalec.donnees.Corpus.*;
+import visuAnalec.vue.Vue.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.GMessages;
+import visuAnalec.util.GMessages.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class VisuStructure extends JFrame implements CorpusListener {
+	static private VisuStructure instance = null;
+	private Corpus corpus;
+	private Structure structure;
+	private JScrollPane panneauUnites, panneauRelations, panneauSchemas;
+	private HashMap<Class<? extends Element>, ModeleArbreProp> donneesClasse =
+			new HashMap<Class<? extends Element>, ModeleArbreProp>();
+	static public VisuStructure newVisuStructure(Container fenetre, Corpus corpus) {
+		if (instance==null) instance = new VisuStructure(fenetre, corpus);
+		return instance;
+	}
+	private VisuStructure(Container fenetre, Corpus corps) {
+		super("Structure des annotations");
+		if (fenetre != null) {
+			Point locFenetre = new Point(fenetre.getX()+20, fenetre.getY()+50);
+			Dimension dimFenetre = new Dimension(fenetre.getWidth(), fenetre.getHeight()-30);
+			setLocation(locFenetre);
+			setSize(dimFenetre);
+		}
+		this.corpus = corps;
+		this.structure = corps.getStructure();
+		corps.addEventListener(this);
+		// Panneau des types d'unités
+		ModeleArbreProp donneesPropUnites = new ModeleArbreProp(structure, Unite.class);
+		JTree arbrePropUnites = new JTree(donneesPropUnites);
+		donneesClasse.put(Unite.class, donneesPropUnites);
+		arbrePropUnites.setRootVisible(true);
+		arbrePropUnites.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+		panneauUnites = new JScrollPane(arbrePropUnites);
+		panneauUnites.setBorder(new TitledBorder("Unités"));
+		// Panneau des types de relations
+		ModeleArbreProp donneesPropRelations = new ModeleArbreProp(structure, Relation.class);
+		JTree arbrePropRelations = new JTree(donneesPropRelations);
+		donneesClasse.put(Relation.class, donneesPropRelations);
+		arbrePropRelations.setRootVisible(true);
+		arbrePropRelations.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+		panneauRelations = new JScrollPane(arbrePropRelations);
+		panneauRelations.setBorder(new TitledBorder("Relations"));
+		// Panneau des types de schémas
+		ModeleArbreProp donneesPropSchemas = new ModeleArbreProp(structure, Schema.class);
+		JTree arbrePropSchemas = new JTree(donneesPropSchemas);
+		donneesClasse.put(Schema.class, donneesPropSchemas);
+		arbrePropSchemas.setRootVisible(true);
+		arbrePropSchemas.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+		panneauSchemas = new JScrollPane(arbrePropSchemas);
+		panneauSchemas.setBorder(new TitledBorder("Schémas"));
+
+		// cadre global de la fenêtre
+		JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, panneauUnites,
+				new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+						panneauRelations, panneauSchemas));
+		getContentPane().add(split);
+
+		// Gestion des menus contextuels
+		final JPopupMenuStructure popupMenuStructure = new JPopupMenuStructure();
+
+		MouseListener popupListener = new MouseAdapter() {
+			@Override
+			public void mousePressed(MouseEvent e) {
+				try {
+					if (e.isPopupTrigger()) showPopup(e);
+					else if (e.getClickCount()==2) {
+						JTree arbre = (JTree) e.getComponent();
+						TreePath item = arbre.getPathForLocation(e.getX(), e.getY());
+						if (item==null) return;
+						if (item.getPathCount()!=4) return;
+						ModeleArbreProp donnees = (ModeleArbreProp) arbre.getModel();
+						Class<? extends Element> classe = donnees.classe;
+						DefaultMutableTreeNode noeudType = (DefaultMutableTreeNode) item.getPathComponent(1);
+						DefaultMutableTreeNode noeudProp = (DefaultMutableTreeNode) item.getPathComponent(2);
+						DefaultMutableTreeNode noeudVal = (DefaultMutableTreeNode) item.getPathComponent(3);
+						String type = (String) noeudType.getUserObject();
+						String prop = (String) noeudProp.getUserObject();
+						String val = (String) noeudVal.getUserObject();
+						if (isDefaut(val)) {
+							corpus.modifierValParDefaut(classe, type, prop, "");
+							//             noeudVal.setUserObject(oteDefaut(val));
+						} else {
+							corpus.modifierValParDefaut(classe, type, prop, val);
+							//              for (Enumeration noeuds = noeudProp.children(); noeuds.hasMoreElements();) {
+							//                DefaultMutableTreeNode noeud1 = (DefaultMutableTreeNode) noeuds.nextElement();
+							//                String val1 = (String) noeud1.getUserObject();
+							//                if (isDefaut(val1)) {
+							//                  noeud1.setUserObject(oteDefaut(val1));
+							//                  donnees.nodeChanged(noeudVal);
+							//                  break;
+							//                }
+							//              }
+							////              noeudVal.setUserObject(placeDefaut(val));
+							//             corpus.newValeurDefaut(classe, type, prop, val);
+						}
+						//          donnees.nodeChanged(noeudVal);
+
+					}
+				} catch (Throwable ex) {
+					GMessages.erreurFatale(ex);
+				}
+			}
+			@Override
+			public void mouseReleased(MouseEvent e) {
+				try {
+					if (e.isPopupTrigger()) showPopup(e);
+				} catch (Throwable ex) {
+					GMessages.erreurFatale(ex);
+				}
+			}
+			private void showPopup(MouseEvent e) {
+				JTree arbre = (JTree) e.getComponent();
+				TreePath item = arbre.getPathForLocation(e.getX(), e.getY());
+				if (item==null) return;
+				popupMenuStructure.init(arbre, item);
+				popupMenuStructure.show(e.getComponent(), e.getX(), e.getY());
+			}
+		};
+
+		arbrePropUnites.addMouseListener(popupListener);
+		arbrePropRelations.addMouseListener(popupListener);
+		arbrePropSchemas.addMouseListener(popupListener);
+		// Fermeture de la fenêtre
+		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+		addWindowListener(new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent evt) {
+				fermerFenetre();
+			}
+		});
+
+	}
+	public void agencer() {
+		((JSplitPane) panneauUnites.getParent()).setDividerLocation(1./3);
+		((JSplitPane) panneauRelations.getParent()).setDividerLocation(1./3);
+	}
+	private void fermerFenetre() {
+		corpus.removeEventListener(this);
+		dispose();
+		instance = null;
+	}
+	public void traiterEvent(Message evt) {
+		switch (evt.getType()) {
+		case CLEAR_CORPUS:
+			fermerFenetre();
+			return;
+		case CORPUS_SAVED:
+			return;
+		case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+			throw new UnsupportedOperationException("Fenêtre stat présente lors d'un message NEW_CORPUS ???");
+		case MODIF_STRUCTURE:
+			StructureEvent evtS = (StructureEvent) evt;
+			ModeleArbreProp donnees = donneesClasse.get(evtS.getClasse());
+			switch (evtS.getModif()) { // pour les modifs ayant lieu en dehors de VisuStructure 
+			case AJOUT_TYPE:
+				donnees.insererNewType(evtS.getArg(0));
+				return;
+			case AJOUT_PROP:
+				donnees.insererNewProp(evtS.getArg(0), evtS.getArg(1));
+				return;
+			case AJOUT_VALEUR:
+				donnees.insererNewValeur(evtS.getArg(0), evtS.getArg(1), evtS.getArg(2));
+				return;
+			case VALEUR_PAR_DEFAUT:
+				donnees.modifierValDefaut(evtS.getArg(0), evtS.getArg(1), evtS.getArg(2));
+				return;
+			default:
+				return;
+			}
+		case MODIF_ELEMENT:
+		case MODIF_TEXTE:
+			return;
+		default:
+			throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+		}
+	}
+	static boolean isDefaut(String val) {
+		return val.startsWith("=>");
+	}
+	static String placeDefaut(String val) {
+		return isDefaut(val) ? val : "=>"+val;
+	}
+	static String oteDefaut(String val) {
+		return isDefaut(val) ? val.substring(2) : val;
+	}
+
+	private class JPopupMenuStructure extends JPopupMenu {
+		void init(JTree arbre, TreePath item) {
+			ModeleArbreProp donnees = (ModeleArbreProp) arbre.getModel();
+			removeAll();
+			int niveau = item.getPathCount();
+			if (niveau<4) {
+				add(new ActionAjouter(donnees.classe, arbre, donnees, item));
+			}
+			if (niveau>1) {
+				if (niveau!=3||!donnees.classe.equals(Unite.class)||!Structure.FORME.equals(
+						((DefaultMutableTreeNode) item.getLastPathComponent()).getUserObject()))
+					add(new ActionRenommer(donnees.classe, donnees, item));
+				add(new ActionSupprimer(donnees.classe, donnees, item));
+			}
+			if (niveau==2&&donnees.classe.equals(Unite.class)
+					&&!donnees.hasForme((DefaultMutableTreeNode) item.getLastPathComponent()))
+				add(new ActionAjouterForme(arbre, donnees, item));
+			if (niveau==3)
+				add(new ActionDispatcher(donnees.classe, arbre, donnees, item));
+		}
+	}
+	static String[] commandesAjout = new String[]{
+		"Ajouter un type",
+		"Ajouter une propriété",
+		"Ajouter une valeur"
+	};
+
+	private class ActionAjouter extends GAction {
+		TreePath item;
+		Class<? extends Element> classe;
+		JTree arbre;
+		ModeleArbreProp donnees;
+		ActionAjouter(Class<? extends Element> classe, JTree arbre, ModeleArbreProp donnees, TreePath item) {
+			super(commandesAjout[item.getPathCount()-1]);
+			this.item = item;
+			this.classe = classe;
+			this.donnees = donnees;
+			this.arbre = arbre;
+		}
+		public void executer() {
+			corpus.removeEventListener(VisuStructure.this);
+			DefaultMutableTreeNode noeud, noeud1, noeud2;
+			noeud = (DefaultMutableTreeNode) item.getLastPathComponent();
+			switch (item.getPathCount()) {
+			case 1: // racine : ajout d'un type
+			String newType =
+			corpus.saisirAjouterType(VisuStructure.this, classe);
+			if (newType!=null) {
+				noeud1 = new DefaultMutableTreeNode(newType, true);
+				donnees.insertNodeInto(noeud1, noeud, 0);
+				arbre.makeVisible(item.pathByAddingChild(noeud1));
+			}
+			break;
+			case 2: // type : ajout d'une prop
+				String newProp =
+				corpus.saisirAjouterProp(VisuStructure.this, classe,
+						(String) noeud.getUserObject());
+				if (newProp!=null) {
+					noeud1 = new DefaultMutableTreeNode(newProp, true);
+					donnees.insertNodeInto(noeud1, noeud, 0);
+					arbre.makeVisible(item.pathByAddingChild(noeud1));
+				}
+				break;
+			case 3: // prop : ajout d'une valeur
+				noeud1 = (DefaultMutableTreeNode) item.getPathComponent(1);
+				String newVal = corpus.saisirAjouterVal(VisuStructure.this, classe,
+						(String) noeud1.getUserObject(), (String) noeud.getUserObject());
+				if (newVal!=null) {
+					noeud2 = new DefaultMutableTreeNode(newVal, false);
+					donnees.insertNodeInto(noeud2, noeud, 0);
+					arbre.makeVisible(item.pathByAddingChild(noeud1));
+				}
+				break;
+			default:
+				throw new UnsupportedOperationException("Cas d'ajout non prévu ");
+			}
+			corpus.addEventListener(VisuStructure.this);
+		}
+	}
+	static String[] commandesRenom = new String[]{
+		"Renommer le type",
+		"Renommer la propriété",
+		"Renommer la valeur"
+	};
+
+	private class ActionRenommer extends GAction {
+		TreePath item;
+		Class<? extends Element> classe;
+		ModeleArbreProp donnees;
+		ActionRenommer(Class<? extends Element> classe, ModeleArbreProp donnees, TreePath item) {
+			super(commandesRenom[item.getPathCount()-2]);
+			this.item = item;
+			this.classe = classe;
+			this.donnees = donnees;
+		}
+		@SuppressWarnings("unchecked")
+		public void executer() {
+			corpus.removeEventListener(VisuStructure.this);
+			DefaultMutableTreeNode noeud, noeud0, noeud1, noeud2;
+			noeud = (DefaultMutableTreeNode) item.getLastPathComponent();
+			switch (item.getPathCount()) {
+			case 2: // type
+				String newType = corpus.saisirRenommerType(VisuStructure.this, classe, (String) noeud.getUserObject());
+				if (newType!=null) {
+					DefaultMutableTreeNode ntypefusion = null;
+					noeud0 = (DefaultMutableTreeNode) item.getPathComponent(0);
+					for (Enumeration<TreeNode> etype = noeud0.children(); etype.hasMoreElements();) {
+						DefaultMutableTreeNode ntype = (DefaultMutableTreeNode) etype.nextElement();
+						String type0 = (String) ntype.getUserObject();
+						if (newType.equals(type0)) {
+							ntypefusion = ntype;
+							break;
+						}
+					}
+					if (ntypefusion!=null)
+						donnees.fusionnerType(noeud, ntypefusion);
+					else {
+						noeud.setUserObject(newType);
+						donnees.nodeChanged(noeud);
+					}
+				}
+				Log.info(NLS.bind("Warning: the Vue must be updated to show the new annotation name: {0}.", newType));
+				break;
+			case 3: // prop
+				noeud1 = (DefaultMutableTreeNode) item.getPathComponent(1);
+				String newProp = corpus.saisirRenommerProp(VisuStructure.this, classe, (String) noeud1.getUserObject(), (String) noeud.getUserObject());
+				if (newProp!=null) {
+					DefaultMutableTreeNode npropfusion = null;
+					for (Enumeration<TreeNode> eprop = noeud1.children(); eprop.hasMoreElements();) {
+						DefaultMutableTreeNode nprop = (DefaultMutableTreeNode) eprop.nextElement();
+						String prop0 = (String) nprop.getUserObject();
+						if (newProp.equals(prop0)) {
+							npropfusion = nprop;
+							break;
+						}
+					}
+					if (npropfusion!=null)
+						donnees.fusionnerProp(noeud1, noeud, npropfusion);
+					else {
+						noeud.setUserObject(newProp);
+						donnees.nodeChanged(noeud);
+					}
+				}
+				Log.info(NLS.bind("Warning: the Vue must be updated to show the new annotation property name: {0}.", newProp));
+				break;
+			case 4: // val
+				noeud1 = (DefaultMutableTreeNode) item.getPathComponent(1);
+				noeud2 = (DefaultMutableTreeNode) item.getPathComponent(2);
+				String val = (String) noeud.getUserObject();
+				boolean isDefaut = isDefaut(val);
+				if (isDefaut) val = oteDefaut(val);
+				String newVal = corpus.saisirRenommerVal(VisuStructure.this, classe,
+						(String) noeud1.getUserObject(), (String) noeud2.getUserObject(), val);
+				if (newVal!=null) {
+					for (Enumeration<TreeNode> eval = noeud2.children(); eval.hasMoreElements();) {
+						DefaultMutableTreeNode nval = (DefaultMutableTreeNode) eval.nextElement();
+						String val0 = (String) nval.getUserObject();
+						if (newVal.equals(isDefaut(val0) ? oteDefaut(val0) : val0)) {
+							isDefaut = isDefaut||isDefaut(val0);
+							donnees.removeNodeFromParent(nval);
+							break;
+						}
+					}
+					if (isDefaut) newVal = placeDefaut(newVal);
+					noeud.setUserObject(newVal);
+					donnees.nodeChanged(noeud);
+				}
+				break;
+			default:
+				throw new UnsupportedOperationException("Cas de renommage non prévu ");
+			}
+			corpus.addEventListener(VisuStructure.this);
+		}
+	}
+	static String[] commandesSuppr = new String[]{
+		"Supprimer le type",
+		"Supprimer la propriété",
+		"Supprimer la valeur"
+	};
+
+	private class ActionSupprimer extends GAction {
+		TreePath item;
+		Class<? extends Element> classe;
+		ModeleArbreProp donnees;
+		ActionSupprimer(Class<? extends Element> classe, ModeleArbreProp donnees, TreePath item) {
+			super(commandesSuppr[item.getPathCount()-2]);
+			this.item = item;
+			this.classe = classe;
+			this.donnees = donnees;
+		}
+		@SuppressWarnings("unchecked")
+		public void executer() {
+			corpus.removeEventListener(VisuStructure.this);
+			DefaultMutableTreeNode noeud, noeud1, noeud2;
+			noeud = (DefaultMutableTreeNode) item.getLastPathComponent();
+			switch (item.getPathCount()) {
+			case 1: // racine
+				return;
+			case 2: // type
+				if (corpus.saisirSupprimerType(VisuStructure.this, classe,
+						(String) noeud.getUserObject())) {
+					donnees.removeNodeFromParent(noeud);
+				}
+				break;
+			case 3: // prop
+				noeud1 = (DefaultMutableTreeNode) item.getPathComponent(1);
+				if (corpus.saisirSupprimerProp(VisuStructure.this, classe,
+						(String) noeud1.getUserObject(), (String) noeud.getUserObject())) {
+					donnees.removeNodeFromParent(noeud);
+				}
+				;
+				break;
+			case 4: // val
+				noeud1 = (DefaultMutableTreeNode) item.getPathComponent(1);
+				noeud2 = (DefaultMutableTreeNode) item.getPathComponent(2);
+				String val = (String) noeud.getUserObject();
+				if (isDefaut(val)) val = oteDefaut(val);
+				if (corpus.saisirSupprimerVal(VisuStructure.this, classe,
+						(String) noeud1.getUserObject(), (String) noeud2.getUserObject(), val)) {
+					donnees.removeNodeFromParent(noeud);
+				}
+				break;
+			default:
+				throw new UnsupportedOperationException("Cas de suppression non prévu ");
+			}
+			corpus.addEventListener(VisuStructure.this);
+		}
+	}
+
+	private class ActionAjouterForme extends GAction {
+		TreePath item;
+		Class<? extends Element> classe;
+		JTree arbre;
+		ModeleArbreProp donnees;
+		ActionAjouterForme(JTree arbre, ModeleArbreProp donnees, TreePath item) {
+			super("Ajouter la forme de surface");
+			this.item = item;
+			this.donnees = donnees;
+			this.arbre = arbre;
+		}
+		@SuppressWarnings("unchecked")
+		public void executer() {
+			corpus.removeEventListener(VisuStructure.this);
+			DefaultMutableTreeNode noeud, noeud1;
+			noeud = (DefaultMutableTreeNode) item.getLastPathComponent();
+			String type = (String) noeud.getUserObject();
+			corpus.ajouterFormeUnite(type);
+			noeud1 = new DefaultMutableTreeNode(Structure.FORME, true);
+			donnees.insertNodeInto(noeud1, noeud, 0);
+			arbre.makeVisible(item.pathByAddingChild(noeud1));
+			corpus.addEventListener(VisuStructure.this);
+			corpus.instancierFormeUnite(type);
+
+		}
+	}
+
+	private class ActionDispatcher extends GAction {
+		TreePath item;
+		Class<? extends Element> classe;
+		JTree arbre;
+		ModeleArbreProp donnees;
+		ActionDispatcher(Class<? extends Element> classe, JTree arbre,
+				ModeleArbreProp donnees, TreePath item) {
+			super("Transformer en types distincts");
+			this.item = item;
+			this.classe = classe;
+			this.donnees = donnees;
+			this.arbre = arbre;
+		}
+		@SuppressWarnings("unchecked")
+		public void executer() {
+			corpus.removeEventListener(VisuStructure.this);
+			DefaultMutableTreeNode noeudprop = (DefaultMutableTreeNode) item.getLastPathComponent();
+			int nbval = noeudprop.getChildCount();
+			String[] vals = new String[nbval];
+			Enumeration<TreeNode> eval = noeudprop.children();
+			for (int i = 0; i<nbval; i++)
+				vals[i] = (String) ((DefaultMutableTreeNode)eval.nextElement()).getUserObject();
+			DefaultMutableTreeNode noeudtype = (DefaultMutableTreeNode) item.getPathComponent(1);
+			int nbprop = noeudtype.getChildCount();
+			String[] props = new String[nbprop-1];
+			String[][] propsvals = new String[nbprop-1][];
+			Enumeration<TreeNode> eprop = noeudtype.children();
+			for (int i = 0; eprop.hasMoreElements(); i++) {
+				DefaultMutableTreeNode nprop = (DefaultMutableTreeNode) eprop.nextElement();
+				if (nprop!=noeudprop) {
+					props[i] = (String) nprop.getUserObject();
+					propsvals[i] = new String[nprop.getChildCount()];
+					Enumeration<TreeNode> epropval = nprop.children();
+					for (int j = 0; epropval.hasMoreElements(); j++)
+						propsvals[i][j] = (String) ((DefaultMutableTreeNode)epropval.nextElement()).getUserObject();
+				} else i--;
+			}
+			if (corpus.saisirDispatcherProp(VisuStructure.this, classe,
+					(String) noeudtype.getUserObject(),
+					(String) noeudprop.getUserObject(), vals, props, propsvals))
+				donnees.dispatcherProp(noeudtype, noeudprop, vals, props, propsvals);
+			corpus.addEventListener(VisuStructure.this);
+		}
+	}
+
+	private static class ModeleArbreProp extends DefaultTreeModel {
+		Structure structure;
+		Class<? extends Element> classe;
+		ModeleArbreProp(Structure structure, Class<? extends Element> classe) {
+			super(null, true);
+			this.structure = structure;
+			this.classe = classe;
+			setModele();
+		}
+		private void setModele() {
+			DefaultMutableTreeNode racine = new DefaultMutableTreeNode("TYPES :", true);
+			setRoot(racine);
+			String[] types = structure.getTypes(classe).toArray(new String[0]);
+			Arrays.sort(types);
+			for (String type : types) {
+				DefaultMutableTreeNode ntype =
+						new DefaultMutableTreeNode(type, true);
+				racine.add(ntype);
+				String[] props =
+						structure.getNomsProps(classe, type).toArray(new String[0]);
+				Arrays.sort(props);
+				for (String prop : props) {
+					DefaultMutableTreeNode nprop =
+							new DefaultMutableTreeNode(prop, true);
+					ntype.add(nprop);
+					String[] vals =
+							structure.getValeursProp(classe, type, prop).toArray(new String[0]);
+					Arrays.sort(vals);
+					for (String val : vals) {
+						if (val.equals(structure.getValeurParDefaut(classe, type, prop)))
+							val = placeDefaut(val);
+						DefaultMutableTreeNode nval =
+								new DefaultMutableTreeNode(val, false);
+						nprop.add(nval);
+					}
+				}
+			}
+			reload();
+		}
+		@SuppressWarnings("unchecked")
+		void insererNewType(String type) {
+			DefaultMutableTreeNode racine = (DefaultMutableTreeNode) getRoot();
+			insertNodeInto(new DefaultMutableTreeNode(type, true), racine, 0);
+		}
+		@SuppressWarnings("unchecked")
+		void insererNewProp(String type, String prop) {
+			DefaultMutableTreeNode racine = (DefaultMutableTreeNode) getRoot();
+			DefaultMutableTreeNode ntype = null;
+			for (Enumeration<TreeNode> etype = racine.children();
+					etype.hasMoreElements();) {
+				ntype = (DefaultMutableTreeNode) etype.nextElement();
+				if (type.equals(ntype.getUserObject())) break;
+			}
+			insertNodeInto(new DefaultMutableTreeNode(prop, true), ntype, 0);
+		}
+		@SuppressWarnings("unchecked")
+		void insererNewValeur(String type, String prop, String valeur) {
+			DefaultMutableTreeNode racine = (DefaultMutableTreeNode) getRoot();
+			DefaultMutableTreeNode ntype = null;
+			DefaultMutableTreeNode nprop = null;
+			for (Enumeration<TreeNode> etype = racine.children();
+					etype.hasMoreElements();) {
+				ntype = (DefaultMutableTreeNode) etype.nextElement();
+				if (type.equals(ntype.getUserObject())) {
+					for (Enumeration<TreeNode> eprop = ntype.children(); eprop.hasMoreElements();) {
+						nprop = (DefaultMutableTreeNode) eprop.nextElement();
+						if (prop.equals(nprop.getUserObject())) break;
+					}
+					break;
+				}
+			}
+			insertNodeInto(new DefaultMutableTreeNode(valeur, false), nprop, 0);
+		}
+		@SuppressWarnings("unchecked")
+		void modifierValDefaut(String type, String prop, String valeur) {
+			DefaultMutableTreeNode racine = (DefaultMutableTreeNode) getRoot();
+			DefaultMutableTreeNode ntype = null;
+			DefaultMutableTreeNode nprop = null;
+			DefaultMutableTreeNode nval = null;
+			for (Enumeration<TreeNode> etype = racine.children(); etype.hasMoreElements();) {
+				ntype = (DefaultMutableTreeNode) etype.nextElement();
+				if (type.equals(ntype.getUserObject())) {
+					for (Enumeration<TreeNode> eprop = ntype.children(); eprop.hasMoreElements();) {
+						nprop = (DefaultMutableTreeNode) eprop.nextElement();
+						if (prop.equals(nprop.getUserObject())) break;
+					}
+					break;
+				}
+			}
+			for (Enumeration<TreeNode> eval = nprop.children(); eval.hasMoreElements();) {
+				nval = (DefaultMutableTreeNode) eval.nextElement();
+				String val = (String) nval.getUserObject();
+				if (isDefaut(val)) {
+					nval.setUserObject(oteDefaut(val));
+					nodeChanged(nval);
+				}
+				if (val.equals(valeur)) {
+					nval.setUserObject(placeDefaut(val));
+					nodeChanged(nval);
+				}
+
+			}
+		}
+		void fusionnerType(DefaultMutableTreeNode noeudafusionner,
+				DefaultMutableTreeNode noeudagarder) {
+			removeNodeFromParent(noeudafusionner);
+			noeudagarder.removeAllChildren();
+			String type = (String) noeudagarder.getUserObject();
+			String[] props = structure.getNomsProps(classe, type).toArray(new String[0]);
+			Arrays.sort(props);
+			for (String prop : props) {
+				DefaultMutableTreeNode nprop = new DefaultMutableTreeNode(prop, true);
+				noeudagarder.add(nprop);
+				String[] vals = structure.getValeursProp(classe, type, prop).toArray(new String[0]);
+				Arrays.sort(vals);
+				for (String val : vals) {
+					if (val.equals(structure.getValeurParDefaut(classe, type, prop)))
+						val = placeDefaut(val);
+					DefaultMutableTreeNode nval = new DefaultMutableTreeNode(val, false);
+					nprop.add(nval);
+				}
+			}
+			nodeStructureChanged(noeudagarder);
+		}
+		void fusionnerProp(DefaultMutableTreeNode noeudtype, DefaultMutableTreeNode noeudafusionner,
+				DefaultMutableTreeNode noeudagarder) {
+			removeNodeFromParent(noeudafusionner);
+			noeudagarder.removeAllChildren();
+			String type = (String) noeudtype.getUserObject();
+			String prop = (String) noeudagarder.getUserObject();
+			String[] vals = structure.getValeursProp(classe, type, prop).toArray(new String[0]);
+			Arrays.sort(vals);
+			for (String val : vals) {
+				if (val.equals(structure.getValeurParDefaut(classe, type, prop)))
+					val = placeDefaut(val);
+				DefaultMutableTreeNode nval = new DefaultMutableTreeNode(val, false);
+				noeudagarder.add(nval);
+			}
+			nodeStructureChanged(noeudagarder);
+		}
+		void dispatcherProp(DefaultMutableTreeNode noeudtype,
+				DefaultMutableTreeNode noeudprop, String[] newtypes, String[] props,
+				String[][] propsvals) {
+			removeNodeFromParent(noeudtype);
+			removeNodeFromParent(noeudprop);
+			DefaultMutableTreeNode racine = (DefaultMutableTreeNode) getRoot();
+			DefaultMutableTreeNode ntype = null;
+			DefaultMutableTreeNode nprop = null;
+			for (String type : newtypes) {
+				insertNodeInto(ntype = new DefaultMutableTreeNode(type, true), racine, 0);
+				for (int i = 0; i<props.length; i++) {
+					insertNodeInto(nprop = new DefaultMutableTreeNode(props[i], true),
+							ntype, i);
+					for (int j = 0; j<propsvals[i].length; j++)
+						insertNodeInto(new DefaultMutableTreeNode(oteDefaut(propsvals[i][j]),
+								false), nprop, j);
+
+				}
+
+			}
+		}
+		@SuppressWarnings("unchecked")
+		boolean hasForme(DefaultMutableTreeNode noeudtype) {
+			for (Enumeration<TreeNode> eprop = noeudtype.children();
+					eprop.hasMoreElements();) {
+				DefaultMutableTreeNode nprop = (DefaultMutableTreeNode) eprop.nextElement();
+				if (Structure.FORME.equals(nprop.getUserObject())) return true;
+			}
+
+			return false;
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/donnees/VisuStructure.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/donnees/Corpus.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/donnees/Corpus.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/donnees/Corpus.java	(revision 3653)
@@ -0,0 +1,1122 @@
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.donnees;
+
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+
+import javax.swing.*;
+
+import visuAnalec.*;
+import visuAnalec.elements.*;
+import visuAnalec.Message.*;
+import visuAnalec.texte.PanneauTexte;
+import visuAnalec.util.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class Corpus {
+	public static interface CorpusListener extends EventListener {  // VisuAnalec, Vue et VisuStructure sont les seuls destinaires
+		void traiterEvent(Message e);
+	}
+	private ArrayList<CorpusListener> listeCorrespondants = new ArrayList<CorpusListener>();
+	private boolean modifie = false;
+	private String texte = "";
+	private ArrayList<Integer> finParagraphes = new ArrayList<Integer>();
+	private Structure structure = new Structure();
+	private HashMap<String, ArrayList<Unite>> unites = new HashMap<String, ArrayList<Unite>>();
+	private HashMap<String, ArrayList<Relation>> relations = new HashMap<String, ArrayList<Relation>>();
+	private HashMap<String, ArrayList<Schema>> schemas = new HashMap<String, ArrayList<Schema>>();
+	public void addEventListener(CorpusListener correspondant) {
+		listeCorrespondants.add(correspondant);
+	}
+	public void removeEventListener(CorpusListener correspondant) {
+		listeCorrespondants.remove(correspondant);
+	}
+	private void fireMessage(Message evt) {
+		TypeMessage type = evt.getType();
+		boolean newModifie = !(EnumSet.of(TypeMessage.CLEAR_CORPUS, TypeMessage.NEW_CORPUS, TypeMessage.CORPUS_SAVED).
+				contains(type));
+		//    if (!modifie && newModifie) {
+		//    	System.out.println("corpus modified: "+evt);
+		//    }
+		modifie = newModifie;
+		for (Object corresp : listeCorrespondants.toArray()) {
+			((CorpusListener) corresp).traiterEvent(evt);
+		}
+	}
+	public Structure getStructure() {
+		return structure;
+	}
+	public String getTexte() {
+		return texte;
+	}
+	public void setTexte(String texte) {
+		this.texte = texte;
+	}
+	public Integer[] getFinParagraphes() {
+		return finParagraphes.toArray(new Integer[0]);
+	}
+	public void setFinParagraphes(ArrayList<Integer> finpars) {
+		finParagraphes = finpars;
+	}
+	public String getTexteUnite(Unite unit) {
+		int deb = unit.getDeb();
+		int fin = unit.getFin();
+		return PanneauTexte.insereCarFinParagraphe(getTexte().substring(deb, fin),
+				getFinParagraphes(), deb);
+	}
+	public void modifTexte(String texte, ArrayList<Integer> finparag) {
+		this.texte = texte;
+		this.finParagraphes = finparag;
+		verifierFormesUnites();
+		fireMessage(new Message(this, TypeMessage.MODIF_TEXTE));
+	}
+	private void verifierFormesUnites() {
+		for (String type : structure.getTypes(Unite.class)) {
+			if (structure.getNomsProps(Unite.class, type).contains(Structure.FORME)) {
+				boolean modif = false;
+				for (Unite unit : getUnites(type)) {
+					String forme = getTexteUnite(unit);
+					if (!forme.equals(unit.getProp(Structure.FORME))) {
+						setValeurPropElement(unit, Structure.FORME, forme);
+					}
+				}
+			}
+		}
+	}
+	public void addFinParagraphe(int ind) {
+		finParagraphes.add(ind);
+	}
+	public void verifierFinParagrapheFinTexte() {
+		if (finParagraphes.isEmpty()
+				||finParagraphes.get(finParagraphes.size()-1)<texte.length())
+			finParagraphes.add(texte.length());
+	}
+	public void trierFinParagraphes() {
+		Integer[] fins = getFinParagraphes();
+		Arrays.sort(fins);
+		finParagraphes = new ArrayList<Integer>(Arrays.asList(fins));
+	}
+	public void verifierFinParagraphesTypesUnites(String[] types) {
+		// Attention : les fins de paragraphes sont en désordre à la fin de la fonction
+		Integer[] fins = getFinParagraphes();
+		Arrays.sort(fins);
+		ArrayList<Integer> newFinPars = new ArrayList<Integer>();
+		for (String type : types) for (Unite unit : getUnites(type)) {
+			Integer fin = unit.getFin();
+			if (Arrays.binarySearch(fins, fin)<0) newFinPars.add(fin);
+		}
+		finParagraphes.addAll(newFinPars);
+	}
+	public int[] calculerNoParagraphe(Unite[] unites) {
+		// les unites sont triées
+		// les numéros de paragraphe commencent à 1 
+		int[] nosPar = new int[unites.length];
+		Integer[] finPar = getFinParagraphes();
+		Arrays.sort(finPar);
+		int nopar = 0;
+		for (int i = 0; i<unites.length; i++) {
+			while (unites[i].getDeb()>=finPar[nopar]) nopar++;
+			nosPar[i] = nopar+1;
+		}
+		return nosPar;
+	}
+	public String[][] getConcordances(Element[] elts, int empan) {
+		Integer[] finPar = getFinParagraphes();
+		String[][] concordances = new String[elts.length][3];
+		for (int i = 0; i<elts.length; i++) {
+			Unite unite0 = elts[i].getUnite0();
+			int debElt = unite0.getDeb();
+			int finElt = unite0.getFin();
+			int deb;
+			if (debElt-empan>0) {
+				concordances[i][0] = "[...]";
+				deb = debElt-empan;
+			} else {
+				concordances[i][0] = "";
+				deb = 0;
+			}
+			concordances[i][0] += PanneauTexte.insereCarFinParagraphe(
+					texte.substring(deb, debElt), finPar, deb);
+			concordances[i][1] = PanneauTexte.insereCarFinParagraphe(
+					texte.substring(debElt, finElt), finPar, debElt);
+			if (finElt+empan<texte.length()) {
+				concordances[i][2] = PanneauTexte.insereCarFinParagraphe(
+						texte.substring(finElt, finElt+empan), finPar, finElt)+"[...]";
+			} else
+				concordances[i][2] = PanneauTexte.insereCarFinParagraphe(
+						texte.substring(finElt), finPar, finElt);
+		}
+		return concordances;
+	}
+	public Unite addUniteSaisie(String type, int deb, int fin) { // ajout d'une unité saisie
+		Unite unite = new Unite(type, deb, fin);
+		addValeursDefauts(unite);
+		if (!unites.containsKey(type)) {
+			unites.put(type, new ArrayList<Unite>());
+		}
+		unites.get(type).add(unite);
+		fireMessage(new ElementEvent(this, TypeModifElement.AJOUT_UNITE, unite));
+		return unite;
+	}
+	public Unite addUniteSaisie(String type, int deb, int fin, HashMap<String, String> properties) { // ajout d'une unité saisie
+		Unite unite = new Unite(type, deb, fin);
+		addValeursDefauts(unite);
+		for (String k : properties.keySet()) {
+			unite.getProps().put(k, properties.get(k));
+		}
+		if (!unites.containsKey(type)) {
+			unites.put(type, new ArrayList<Unite>());
+		}
+		unites.get(type).add(unite);
+		fireMessage(new ElementEvent(this, TypeModifElement.AJOUT_UNITE, unite));
+		return unite;
+	}
+	public void addUniteLue(Unite unite) { // ajout d'une unité créée par la lecture d'un corpus: pas de message 
+		// et mise à jour éventuelle de la structure et de la HashMap unites
+		String type = unite.getType();
+		if (type==null||type.isEmpty()) return;
+		structure.majNewElement(unite);
+		if (!unites.containsKey(type)) {
+			unites.put(type, new ArrayList<Unite>());
+		}
+		unites.get(type).add(unite);
+	}
+
+	public void addUniteConvertit(Unite unite) {  // ajout d'une unité créé par fusion de tous les types d'unités
+		//: pas de message et mise à jour éventuelle de la structure et de la HashMap schemas
+		String type = unite.getType();
+		if (type==null||type.isEmpty()) return;
+		structure.majNewElement(unite);
+		if (!unites.containsKey(type)) {
+			unites.put(type, new ArrayList<Unite>());
+		}
+		unites.get(type).add(unite);
+		fireMessage(new Message(this, TypeMessage.NEW_CORPUS));
+	}
+
+	public void modifBornesUnite(Unite unite, int deb, int fin) {
+		
+		// fixing new bornes if necessary
+		if (deb == unite.getDeb()) { // the start did not change so try fixing the end
+			if (fin < deb) fin = deb;
+		} else if (fin == unite.getFin()) { // the end did not change so try fixing the start
+			if (deb > fin) deb = fin;
+		} else if (fin < deb) { // try fixing the end
+			fin = deb;
+		}
+		
+		unite.setDeb(deb);
+		unite.setFin(fin);
+		fireMessage(new ElementEvent(this, TypeModifElement.BORNES_UNITE, unite));
+	}
+	public void supUnite(Unite unite) {
+		String type = unite.getType();
+		unites.get(type).remove(unite);
+		fireMessage(new ElementEvent(this, TypeModifElement.SUP_UNITE, unite));
+		supLiensElement(unite);
+	}
+	public boolean checkPresenceUnite(String type, int deb, int fin) { // pas très efficace
+		if (!unites.containsKey(type)) return false;
+		for (Unite unit : getUnites(type))
+			if (unit.getDeb()==deb&&unit.getFin()==fin) return true;
+		return false;
+
+	}
+	private int checkFusionnerUnites(HashMap<String, ArrayList<Unite>> newunites, HashSet<Unite> unitesAajouter,
+			HashMap<Unite, Unite> unitesAfusionner) {
+		int nbEcrases = 0;
+		for (String type : newunites.keySet()) {
+			if (!unites.containsKey(type)) {
+				unitesAajouter.addAll(newunites.get(type));
+				continue;
+			}
+			for (Unite newunite : newunites.get(type)) {
+				Unite unit = chercherUniteCoincidente(newunite, unites.get(type));
+				if (unit==null) unitesAajouter.add(newunite);
+				else {
+					unitesAfusionner.put(newunite, unit);
+					for (String prop : newunite.getProps().keySet())
+						if (!unit.getProp(prop).isEmpty()&&!newunite.getProp(prop).isEmpty()
+								&&!unit.getProp(prop).equals(newunite.getProp(prop))) {
+							nbEcrases++;
+							break;
+						}
+				}
+			}
+		}
+		return nbEcrases;
+	}
+	private Unite chercherUniteCoincidente(Unite unite, ArrayList<Unite> lunites) {
+		for (Unite unit : lunites) if (unite.coincide(unit)) return unit;
+		return null;
+	}
+	public Relation addRelationSaisie(String type, Element elt1, Element elt2) {
+		Relation relation = new Relation(type, elt1, elt2);
+		addValeursDefauts(relation);
+		if (!relations.containsKey(type)) {
+			relations.put(type, new ArrayList<Relation>());
+		}
+		relations.get(type).add(relation);
+		relation.getElt2().addRelationEntrante(relation);
+		relation.getElt1().addRelationSortante(relation);
+		fireMessage(new ElementEvent(this, TypeModifElement.AJOUT_RELATION, relation));
+		return relation;
+	}
+	public Relation addRelationLue(Relation relation) { // ajout d'une relation créée par la lecture d'un corpus: pas de message
+		// et mise à jour éventuelle de la structure et de la HashMap relations
+		String type = relation.getType();
+		if (type==null||type.isEmpty()) return null;
+		structure.majNewElement(relation);
+		if (!relations.containsKey(type)) {
+			relations.put(type, new ArrayList<Relation>());
+		}
+		relations.get(type).add(relation);
+		relation.getElt2().addRelationEntrante(relation);
+		relation.getElt1().addRelationSortante(relation);
+		
+		return relation;
+	}
+	public void supRelation(Relation rel) {
+		String type = rel.getType();
+		relations.get(type).remove(rel);
+		rel.getElt1().oteRelationSortante(rel);
+		rel.getElt2().oteRelationEntrante(rel);
+		fireMessage(new ElementEvent(this, TypeModifElement.SUP_RELATION, rel));
+		supLiensElement(rel);
+	}
+	private int checkFusionnerRelations(HashMap<String, ArrayList<Relation>> newrels, HashSet<Relation> relsAajouter,
+			HashMap<Relation, Relation> relsAfusionner) {
+		int nbEcrases = 0;
+		for (String type : newrels.keySet()) {
+			if (!relations.containsKey(type)) {
+				relsAajouter.addAll(newrels.get(type));
+				continue;
+			}
+			for (Relation newrel : newrels.get(type)) {
+				Relation rel = chercherRelationCoincidente(newrel, relations.get(type));
+				if (rel==null) relsAajouter.add(newrel);
+				else {
+					relsAfusionner.put(newrel, rel);
+					for (String prop : newrel.getProps().keySet())
+						if (!rel.getProp(prop).isEmpty()&&!newrel.getProp(prop).isEmpty()
+								&&!rel.getProp(prop).equals(newrel.getProp(prop))) {
+							nbEcrases++;
+							break;
+						}
+				}
+			}
+		}
+		return nbEcrases;
+	}
+	private Relation chercherRelationCoincidente(Relation rel, ArrayList<Relation> lrels) {
+		for (Relation rel1 : lrels) if (rel.coincide(rel1)) return rel1;
+		return null;
+	}
+	private static void fusionnerElementsRelation(Relation relation, HashMap<Unite, Unite> unitesAfusionner,
+			HashMap<Relation, Relation> relationsAfusionner, HashMap<Schema, Schema> schemasAfusionner) {
+		if (relation.getElt1().getClass()==Unite.class&&unitesAfusionner.containsKey(relation.getElt1()))
+			relation.setElt1(unitesAfusionner.get(relation.getElt1()));
+		else if (relation.getElt1().getClass()==Relation.class&&relationsAfusionner.containsKey(relation.getElt1()))
+			relation.setElt1(relationsAfusionner.get(relation.getElt1()));
+		else if (relation.getElt1().getClass()==Schema.class&&schemasAfusionner.containsKey(relation.getElt1()))
+			relation.setElt1(schemasAfusionner.get(relation.getElt1()));
+		if (relation.getElt2().getClass()==Unite.class&&unitesAfusionner.containsKey(relation.getElt2()))
+			relation.setElt2(unitesAfusionner.get(relation.getElt2()));
+		else if (relation.getElt2().getClass()==Relation.class&&relationsAfusionner.containsKey(relation.getElt2()))
+			relation.setElt2(relationsAfusionner.get(relation.getElt2()));
+		else if (relation.getElt2().getClass()==Schema.class&&schemasAfusionner.containsKey(relation.getElt2()))
+			relation.setElt2(schemasAfusionner.get(relation.getElt2()));
+	}
+	public void addSchemaSaisi(String type, Element elt) {
+		Schema schema = new Schema(type);
+		addValeursDefauts(schema);
+		if (!schemas.containsKey(type)) {
+			schemas.put(type, new ArrayList<Schema>());
+		}
+		schemas.get(type).add(schema);
+		if (elt!=null) {
+			schema.ajouter(elt);
+			elt.addSchemaContenant(schema);
+		}
+		fireMessage(new ElementEvent(this, TypeModifElement.AJOUT_SCHEMA, schema));
+	}
+	public void addSchemaLu(Schema schema) {  // ajout d'un schéma créé par la lecture d'un corpus: pas de message
+		// et mise à jour éventuelle de la structure et de la HashMap schemas
+		String type = schema.getType();
+		if (type==null||type.isEmpty()) return;
+		structure.majNewElement(schema);
+		if (!schemas.containsKey(type)) {
+			schemas.put(type, new ArrayList<Schema>());
+		}
+		schemas.get(type).add(schema);
+		for (Element elt : schema.getContenu()) {
+			elt.addSchemaContenant(schema);
+		}
+	}
+	public void addSchemaConvertit(Schema schema) {  // ajout d'un schéma créé par conversion des données: pas de message
+		// et mise à jour éventuelle de la structure et de la HashMap schemas
+		String type = schema.getType();
+		if (type==null||type.isEmpty()) return;
+		structure.majNewElement(schema);
+		if (!schemas.containsKey(type)) {
+			schemas.put(type, new ArrayList<Schema>());
+		}
+		schemas.get(type).add(schema);
+		for (Element elt : schema.getContenu()) {
+			elt.addSchemaContenant(schema);
+		}
+		fireMessage(new Message(this, TypeMessage.NEW_CORPUS));
+	}
+
+
+
+	public void ajouterElementSchemaSaisi(Element elt, Schema sch) {
+		if (!sch.ajouter(elt)) {
+			GMessages.impossibiliteAction("Impossible d'ajouter cet élément "
+					+"au schéma courant :\n problème de récursivité infinie");
+		}
+		elt.addSchemaContenant(sch);
+		fireMessage(new ElementEvent(this, TypeModifElement.MODIF_SCHEMA, sch));
+	}
+	public void oterElementSchema(Element elt, Schema sch) {
+		sch.oter(elt);
+		elt.oteSchemaContenant(sch);
+		fireMessage(new ElementEvent(this, TypeModifElement.MODIF_SCHEMA, sch));
+	}
+	public void supSchema(Schema sch) {
+		String type = sch.getType();
+		schemas.get(type).remove(sch);
+		fireMessage(new ElementEvent(this, TypeModifElement.SUP_SCHEMA, sch));
+		supLiensElement(sch);
+	}
+	private int checkFusionnerSchemas(HashMap<String, ArrayList<Schema>> newschs, HashSet<Schema> schsAajouter,
+			HashMap<Schema, Schema> schsAfusionner) {
+		int nbEcrases = 0;
+		for (String type : newschs.keySet()) {
+			if (!schemas.containsKey(type)) {
+				schsAajouter.addAll(newschs.get(type));
+				continue;
+			}
+			for (Schema newsch : newschs.get(type)) {
+				Schema sch = chercherSchemaCoincident(newsch, schemas.get(type));
+				if (sch==null) schsAajouter.add(newsch);
+				else {
+					schsAfusionner.put(newsch, sch);
+					for (String prop : newsch.getProps().keySet())
+						if (!sch.getProp(prop).isEmpty()&&!newsch.getProp(prop).isEmpty()
+								&&!sch.getProp(prop).equals(newsch.getProp(prop))) {
+							nbEcrases++;
+							break;
+						}
+				}
+			}
+		}
+		return nbEcrases;
+	}
+	private Schema chercherSchemaCoincident(Schema sch, ArrayList<Schema> lschs) {
+		for (Schema sch1 : lschs) if (sch.coincide(sch1)) return sch1;
+		return null;
+	}
+	private static void fusionnerElementsSchema(Schema schema, HashMap<Unite, Unite> unitesAfusionner,
+			HashMap<Relation, Relation> relationsAfusionner, HashMap<Schema, Schema> schemasAfusionner) {
+		for (Element elt : schema.getContenu()) {
+			if (elt.getClass()==Unite.class&&unitesAfusionner.containsKey(elt)) {
+				schema.oter(elt);
+				schema.ajouter(unitesAfusionner.get(elt));
+			} else if (elt.getClass()==Relation.class&&relationsAfusionner.containsKey(elt)) {
+				schema.oter(elt);
+				schema.ajouter(relationsAfusionner.get(elt));
+			} else if (elt.getClass()==Schema.class&&schemasAfusionner.containsKey(elt)) {
+				schema.oter(elt);
+				schema.ajouter(schemasAfusionner.get(elt));
+			}
+		}
+	}
+	private void supLiensElement(Element elt) {
+		ArrayList<Relation> rels = elt.getRelations();
+		for (Relation rel : rels) {
+			supRelation(rel);
+		}
+		ArrayList<Schema> schs = elt.getSchemas();
+		for (Schema sch : schs) {
+			oterElementSchema(elt, sch);
+		}
+	}
+	public void addValeur(Class<? extends Element> classe, String type, String prop, String valeur) {
+		structure.ajouterVal(classe, type, prop, valeur);
+		fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_VALEUR, classe, type, prop, valeur));
+	}
+	public void addValeursDefauts(Element elt) {
+		for (String prop : structure.getNomsProps(elt.getClass(), elt.getType())) {
+			elt.putProp(prop, structure.getValeurParDefaut(elt.getClass(), elt.getType(), prop));
+		}
+	}
+	public void ajouterFormeUnite(String type) {
+		structure.ajouterProp(Unite.class, type, Structure.FORME);
+		fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_FORME_UNITE,
+				Unite.class, type));
+	}
+	public void instancierFormeUnite(String type) {
+		ArrayList<Unite> units = getUnites(type);
+		for (Unite unit : units) {
+			String forme = getTexteUnite(unit);
+			setValeurPropElement(unit, Structure.FORME, forme);
+		}
+	}
+	public void modifierValParDefaut(Class<? extends Element> classe, String type, String prop, String val) {
+		structure.modifierValParDefaut(classe, type, prop, val);
+		if (!val.isEmpty()) instancierParValeurDefaut(classe, type, prop, val);
+		fireMessage(new StructureEvent(this, TypeModifStructure.VALEUR_PAR_DEFAUT, classe, type, prop, val));
+	}
+	private void instancierParValeurDefaut(Class<? extends Element> classe, String type, String prop, String val) {
+		ArrayList<? extends Element> elts = getElements(classe, type);
+		boolean noninstancies = false;
+		for (Element elt : elts) if (elt.getProp(prop).isEmpty()) {
+			noninstancies = true;
+			break;
+		}
+		if (noninstancies&&JOptionPane.showConfirmDialog(null, "Voulez-vous donner "
+				+"cette valeur par défaut aux éléments existants non encore instanciés",
+				"Action optionnelle", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE)
+				!=JOptionPane.NO_OPTION)
+			for (Element elt : elts) if (elt.getProp(prop).isEmpty())
+				elt.putProp(prop, val);
+	}
+	public void setValeurPropElement(Element elt, String prop, String newval) {
+		if (newval.isEmpty()) {
+			elt.supProp(prop);
+		} else {
+			if (!structure.getValeursProp(elt.getClass(), elt.getType(), prop).contains(newval)) {
+				addValeur(elt.getClass(), elt.getType(), prop, newval);
+			}
+			elt.putProp(prop, newval);
+		}
+		fireMessage(new ElementEvent(this, TypeModifElement.MODIF_VALEUR, elt, prop, newval));
+
+	}
+	public ArrayList<? extends Element> getElements(Class<? extends Element> classe, String type) {
+		if (classe==Unite.class) return getUnites(type);
+		if (classe==Relation.class) return getRelations(type);
+		if (classe==Schema.class) return getSchemas(type);
+		throw new UnsupportedOperationException("sous-classe non traitée");
+	}
+	public ArrayList<Unite> getUnites(String type) {
+		if (unites.get(type)==null) {
+			return new ArrayList<Unite>();
+		}
+		return unites.get(type);
+	}
+	public ArrayList<Unite> getToutesUnites() {
+		ArrayList<Unite> ttesUnites = new ArrayList<Unite>();
+		for (String type : structure.getTypes(Unite.class)) {
+			ttesUnites.addAll(getUnites(type));
+		}
+		return ttesUnites;
+	}
+	public ArrayList<Relation> getRelations(String type) {
+		if (relations.get(type)==null) {
+			return new ArrayList<Relation>();
+		}
+		return relations.get(type);
+	}
+	public ArrayList<Relation> getToutesRelations() {
+		ArrayList<Relation> ttesRelations = new ArrayList<Relation>();
+		for (String type : structure.getTypes(Relation.class)) {
+			ttesRelations.addAll(getRelations(type));
+		}
+		return ttesRelations;
+	}
+	public ArrayList<Schema> getSchemas(String type) {
+		if (schemas.get(type)==null) {
+			return new ArrayList<Schema>();
+		}
+		return schemas.get(type);
+	}
+	public ArrayList<Schema> getTousSchemas() {
+		ArrayList<Schema> tsSchemas = new ArrayList<Schema>();
+		for (String type : structure.getTypes(Schema.class)) {
+			tsSchemas.addAll(getSchemas(type));
+		}
+		return tsSchemas;
+	}
+	// Modifs de la structure provenant de VisuStructure
+	public String saisirAjouterType(Container fenetre, Class<? extends Element> classe) {
+		String newNom = JOptionPane.showInputDialog(fenetre, "Nom du nouveau type ",
+				"Ajouter un type "+GVisu.getNomDeClasse(classe),
+				JOptionPane.PLAIN_MESSAGE);
+		if (newNom==null) return null;
+		newNom = newNom.trim();
+		if (newNom.isEmpty()) return null;
+		if (structure.getTypes(classe).contains(newNom)) {
+			JOptionPane.showMessageDialog(fenetre, "Ajout impossible : le type "+"\""+newNom+"\""+" existe déjà",
+					"Erreur d'ajout de type", JOptionPane.ERROR_MESSAGE);
+			return null;
+		}
+		ajouterType(classe, newNom);
+		
+		return newNom;
+	}
+	/**
+	 * Ajoute un nouveau type et lance un StructureEvent
+	 * 
+	 * @param classe
+	 * @param type
+	 * @param newNom
+	 * @return
+	 */
+	public void ajouterType(Class<? extends Element> classe, String type) {
+		structure.ajouterType(classe, type);
+		if (classe==Unite.class) {
+			unites.put(type, new ArrayList<Unite>());
+		} else if (classe==Relation.class) {
+			relations.put(type, new ArrayList<Relation>());
+		} else if (classe==Schema.class) {
+			schemas.put(type, new ArrayList<Schema>());
+		}
+		fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_TYPE, classe, type));
+	}
+
+	/**
+	 * Ajoute une nouvelle propriété et lance un StructureEvent
+	 * 
+	 * @param classe
+	 * @param type
+	 * @param newNom
+	 * @return
+	 */
+	public String ajouterProp(Class<? extends Element> classe, String type, String newNom) {
+
+		if (newNom.isEmpty()) return null;
+		if (Structure.FORME.equals(newNom)) {
+			GMessages.impossibiliteAction("Le nom "+Structure.FORME+" est réservé par le système");
+			return null;
+		}
+		if (structure.getNomsProps(classe, type).contains(newNom)) {
+			return null;
+		}
+		structure.ajouterProp(classe, type, newNom);
+		fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_PROP, classe, type, newNom));
+		return newNom;
+	}
+
+	public String saisirAjouterProp(Container fenetre, Class<? extends Element> classe, String type) {
+		String newNom = JOptionPane.showInputDialog(fenetre, "Nom de la nouvelle propriété",
+				"Ajouter une propriété au type "+"\""+type+"\"", JOptionPane.PLAIN_MESSAGE);
+		if (newNom==null) return null;
+		newNom = newNom.trim();
+		if (newNom.isEmpty()) return null;
+		if (Structure.FORME.equals(newNom)) {
+			GMessages.impossibiliteAction("Le nom "+Structure.FORME+" est réservé par le système");
+			return null;
+		}
+		if (structure.getNomsProps(classe, type).contains(newNom)) {
+			JOptionPane.showMessageDialog(fenetre, "Ajout impossible :la propriété "+"\""+newNom+"\""+" existe déjà",
+					"Erreur d'ajout de propriété", JOptionPane.ERROR_MESSAGE);
+			return null;
+		}
+		structure.ajouterProp(classe, type, newNom);
+		fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_PROP, classe, type, newNom));
+		return newNom;
+	}
+	public String saisirAjouterVal(Container fenetre, Class<? extends Element> classe, String type, String prop) {
+		String newNom = JOptionPane.showInputDialog(fenetre, "Nom de la nouvelle valeur",
+				"Ajouter une valeur pour la propriété "+"\""+prop+"\"", JOptionPane.PLAIN_MESSAGE);
+		if (newNom==null) return null;
+		newNom = newNom.trim();
+		if (newNom.isEmpty()) return null;
+		if (structure.getValeursProp(classe, type, prop).contains(newNom)) {
+			JOptionPane.showMessageDialog(fenetre, "Ajout impossible : la valeur "+"\""+newNom+"\""+" existe déjà",
+					"Erreur d'ajout de valeur", JOptionPane.ERROR_MESSAGE);
+			return null;
+		}
+		structure.ajouterVal(classe, type, prop, newNom);
+		fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_VALEUR, classe, type, prop, newNom));
+		return newNom;
+	}
+	/**
+	 * Ajoute une nouvelle valeur et lance un StructureEvent
+	 * 
+	 * @param classe
+	 * @param type
+	 * @param newNom
+	 * @return
+	 */
+	public String ajouterVal(Class<? extends Element> classe, String type, String prop, String newNom) {
+		if (newNom==null) return null;
+		newNom = newNom.trim();
+		if (newNom.isEmpty()) return null;
+		if (structure.getValeursProp(classe, type, prop).contains(newNom)) {
+			return null;
+		}
+		structure.ajouterVal(classe, type, prop, newNom);
+		fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_VALEUR, classe, type, prop, newNom));
+		return newNom;
+	}
+	public String saisirRenommerType(Container fenetre, Class<? extends Element> classe, String oldNom) {
+		String newNom = (String) JOptionPane.showInputDialog(fenetre, "Nouveau nom pour le type "+"\""+oldNom+"\"",
+				"Renommer un type "+GVisu.getNomDeClasse(classe), JOptionPane.PLAIN_MESSAGE, null, null, oldNom);
+		if (newNom==null) return null;
+		newNom = newNom.trim();
+		if (oldNom.equals(newNom)||newNom.isEmpty()) return null;
+		boolean fusion = structure.getTypes(classe).contains(newNom);
+		if (fusion&&!GMessages.confirmationAction("Le type "+"\""+newNom+"\""
+				+" existe déjà. Fusionner les deux types ? ")) return null;
+		if (classe==Unite.class) {
+			if (fusion) unites.get(newNom).addAll(unites.get(oldNom));
+			else unites.put(newNom, unites.get(oldNom));
+			for (Unite unit : unites.get(oldNom)) unit.setType(newNom);
+			unites.remove(oldNom);
+		} else if (classe==Relation.class) {
+			if (fusion) relations.get(newNom).addAll(relations.get(oldNom));
+			else relations.put(newNom, relations.get(oldNom));
+			for (Relation rel : relations.get(oldNom)) {
+				rel.getElt1().oteRelationSortante(rel);
+				rel.getElt2().oteRelationEntrante(rel);
+				rel.setType(newNom);
+				rel.getElt1().addRelationSortante(rel);
+				rel.getElt2().addRelationEntrante(rel);
+			}
+			relations.remove(oldNom);
+		} else if (classe==Schema.class) {
+			if (fusion) schemas.get(newNom).addAll(schemas.get(oldNom));
+			else schemas.put(newNom, schemas.get(oldNom));
+			for (Schema sch : schemas.get(oldNom)) {
+				for (Element elt : sch.getContenu()) elt.oteSchemaContenant(sch);
+				sch.setType(newNom);
+				for (Element elt : sch.getContenu()) elt.addSchemaContenant(sch);
+			}
+			schemas.remove(oldNom);
+		}
+		if (fusion) {
+			structure.fusionnerType(classe, oldNom, newNom);
+			fireMessage(new StructureEvent(this, TypeModifStructure.FUSION_TYPE,
+					classe, oldNom, newNom));
+		} else {
+			structure.renommerType(classe, oldNom, newNom);
+			fireMessage(new StructureEvent(this, TypeModifStructure.RENOM_TYPE,
+					classe, oldNom, newNom));
+		}
+		return newNom;
+	}
+	public String saisirRenommerProp(Container fenetre,
+			Class<? extends Element> classe, String type, String oldNom) {
+		String newNom = (String) JOptionPane.showInputDialog(fenetre, "Nouveau nom pour la propriété "+"\""+oldNom+"\"",
+				"Renommer une propriété du type "+"\""+type+"\"", JOptionPane.PLAIN_MESSAGE, null, null, oldNom);
+		if (newNom==null) return null;
+		newNom = newNom.trim();
+		if (oldNom.equals(newNom)||newNom.isEmpty()) return null;
+		if (Structure.FORME.equals(newNom)) {
+			GMessages.impossibiliteAction("Le nom "+Structure.FORME+" est réservé par le système");
+			return null;
+		}
+		boolean fusion = false;
+		ArrayList<? extends Element> elements = getElements(classe, type);
+		if (structure.getNomsProps(classe, type).contains(newNom)) {
+			int rep = JOptionPane.showOptionDialog(fenetre, "La propriété "+"\""+newNom+"\""+" existe déjà."
+					+" Fusionner les deux propriétés ? ", "Propriété existante",
+					JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+					null, new Object[]{"Oui", "Annuler"}, "Oui");
+			if (rep==1) return null;
+			int nbEcrases = 0;
+			for (Element elt : elements) if (!elt.getProp(newNom).isEmpty()
+					&&!elt.getProp(newNom).equals(elt.getProp(oldNom))) nbEcrases++;
+			if (nbEcrases>0) {
+				int rep1 = JOptionPane.showOptionDialog(fenetre, "L'opération de fusion va écraser l'ancienne valeur de la propriété "
+						+"\""+newNom+"\""+" pour "+nbEcrases+" élément(s)", "Fusion de deux propriétés",
+						JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+						null, new Object[]{"Continuer", "Annuler"}, "Annuler");
+				if (rep1==1 || rep == JOptionPane.CLOSED_OPTION) return null;
+			}
+			fusion = true;
+		}
+		if (fusion) structure.fusionnerProp(classe, type, oldNom, newNom);
+		else structure.renommerProp(classe, type, oldNom, newNom);
+		for (Element elt : elements) {
+			String val = elt.getProp(oldNom);
+			if (!val.isEmpty()) elt.putProp(newNom, val);
+			elt.getProps().remove(oldNom);
+		}
+		if (fusion)
+			fireMessage(new StructureEvent(this, TypeModifStructure.FUSION_PROP, classe, type, oldNom, newNom));
+		else
+			fireMessage(new StructureEvent(this, TypeModifStructure.RENOM_PROP, classe, type, oldNom, newNom));
+		return newNom;
+	}
+	public String saisirRenommerVal(Container fenetre, Class<? extends Element> classe, String type,
+			String prop, String oldNom) {
+		String newNom = (String) JOptionPane.showInputDialog(fenetre, "Nouveau nom pour la valeur "+"\""+oldNom+"\"",
+				"Renommer une valeur de la propriété "+"\""+prop+"\"", JOptionPane.PLAIN_MESSAGE, null, null, oldNom);
+		if (newNom==null) return null;
+		newNom = newNom.trim();
+		if (oldNom.equals(newNom)||newNom.isEmpty()) return null;
+		boolean fusion = false;
+		if (structure.getValeursProp(classe, type, prop).contains(newNom)) {
+			int rep = JOptionPane.showOptionDialog(fenetre, "La valeur "+"\""+newNom+"\""+" existe déjà."
+					+" Fusionner les deux valeurs ? ", "Valeur existante",
+					JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+					null, new Object[]{"Oui", "Annuler"}, "Oui");
+			if (rep==1) return null;
+			fusion = true;
+		}
+		structure.renommerVal(classe, type, prop, oldNom, newNom);
+		ArrayList<? extends Element> elements = getElements(classe, type);
+		for (Element elt : elements) {
+			String val = elt.getProp(prop);
+			if (oldNom.equals(val)) {
+				elt.putProp(prop, newNom);
+			}
+		}
+		if (fusion)
+			fireMessage(new StructureEvent(this, TypeModifStructure.FUSION_VALEUR, classe, type, prop, oldNom, newNom));
+		else
+			fireMessage(new StructureEvent(this, TypeModifStructure.RENOM_VALEUR, classe, type, prop, oldNom, newNom));
+		return newNom;
+	}
+	public boolean saisirSupprimerType(Container fenetre, Class<? extends Element> classe, String type) {
+		Element[] elements = null;
+		if (classe==Unite.class)
+			elements = unites.get(type).toArray(new Element[0]);
+		else if (classe==Relation.class)
+			elements = relations.get(type).toArray(new Element[0]);
+		else if (classe==Schema.class)
+			elements = schemas.get(type).toArray(new Element[0]);
+
+		if (elements.length>0) {
+			int nbSupprimes = elements.length;
+			int rep = JOptionPane.showOptionDialog(fenetre, "La suppresion du type  "+"\""+type+"\""
+					+" va entraîner la suppression "+(nbSupprimes==1 ? "d'un élément" : "de "+nbSupprimes+" éléments"),
+					"Suppression "+GVisu.getNomDeClasse(classe)+"s",
+					JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+					null, new Object[]{"Continuer", "Annuler"}, "Annuler");
+			if (rep==1 || rep == JOptionPane.CLOSED_OPTION) return false;
+			if (classe==Unite.class) {
+				for (Element elt : elements) supUnite((Unite) elt);
+				unites.remove(type);
+			}
+			if (classe==Relation.class) {
+				for (Element elt : elements) supRelation((Relation) elt);
+				relations.remove(type);
+			}
+			if (classe==Schema.class) {
+				for (Element elt : elements) supSchema((Schema) elt);
+				schemas.remove(type);
+			}
+		}
+		structure.supprimerType(classe, type);
+		fireMessage(new StructureEvent(this, TypeModifStructure.SUPPR_TYPE, classe, type));
+		return true;
+	}
+	public boolean saisirSupprimerProp(Container fenetre, Class<? extends Element> classe, String type, String oldNom) {
+		ArrayList<? extends Element> elements = getElements(classe, type);
+		int nbSup = 0;
+		for (Element elt : elements) if (!elt.getProp(oldNom).isEmpty()) nbSup++;
+		if (nbSup>0) {
+			int rep = JOptionPane.showOptionDialog(fenetre, "La propriété "+"\""+oldNom+"\""+" était instanciée pour "
+					+(nbSup==1 ? "un élément" : nbSup+" éléments"), "Suppression d'une propriété",
+					JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+					null, new Object[]{"Continuer", "Annuler"}, "Annuler");
+			if (rep==1 || rep == JOptionPane.CLOSED_OPTION) return false;
+		}
+		for (Element elt : elements) elt.supProp(oldNom);
+		structure.supprimerProp(classe, type, oldNom);
+		fireMessage(new StructureEvent(this, TypeModifStructure.SUPPR_PROP, classe, type, oldNom));
+		return true;
+	}
+	public boolean saisirSupprimerVal(Container fenetre, Class<? extends Element> classe, String type,
+			String prop, String oldNom) {
+		ArrayList<? extends Element> elements = getElements(classe, type);
+		int nbSup = 0;
+		for (Element elt : elements) if (oldNom.equals(elt.getProp(prop)))
+			nbSup++;
+		if (nbSup>0) {
+			int rep = JOptionPane.showOptionDialog(fenetre, "La valeur "+"\""+oldNom+"\""+" était attribuée à "
+					+(nbSup==1 ? "un élément" : nbSup+" éléments"), "Suppression d'une valeur",
+					JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+					null, new Object[]{"Continuer", "Annuler"}, "Annuler");
+			if (rep==1 || rep == JOptionPane.CLOSED_OPTION) return false;
+		}
+		structure.supprimerVal(classe, type, prop, oldNom);
+		for (Element elt : elements) if (oldNom.equals(elt.getProp(prop)))
+			elt.supProp(prop);
+		fireMessage(new StructureEvent(this, TypeModifStructure.SUPPR_VALEUR, classe, type, prop, oldNom));
+		return true;
+	}
+	public boolean saisirDispatcherProp(Container fenetre,
+			Class<? extends Element> classe, String oldtype, String oldprop,
+			String[] newtypes, String[] props, String[][] propsvals) {
+		HashSet<String> types = structure.getTypes(classe);
+		for (String type : newtypes) if (types.contains(type)) {
+			GMessages.impossibiliteAction("Le type "+type+" existe déjà");
+			return false;
+		}
+		ArrayList<? extends Element> elements = getElements(classe, oldtype);
+		for (Element elt : elements) if (elt.getProp(oldprop).isEmpty()) {
+			GMessages.impossibiliteAction("Certains éléments de type "+oldtype
+					+" ne possèdent pas de valeur pour la propriété "+oldprop);
+			return false;
+		}
+		structure.supprimerType(classe, oldtype);
+		for (String type : newtypes) {
+			structure.ajouterType(classe, type);
+			for (int i = 0; i<props.length; i++) {
+				structure.ajouterProp(classe, type, props[i]);
+				for (String val : propsvals[i])
+					structure.ajouterVal(classe, type, props[i], val);
+			}
+		}
+		if (classe==Unite.class) {
+			for (String type : newtypes) unites.put(type, new ArrayList<Unite>());
+			for (Unite unit : unites.get(oldtype)) {
+				String newtype = unit.getProp(oldprop);
+				unit.supProp(oldprop);
+				unit.setType(newtype);
+				unites.get(newtype).add(unit);
+			}
+			unites.remove(oldtype);
+		} else if (classe==Relation.class) {
+			for (String type : newtypes)
+				relations.put(type, new ArrayList<Relation>());
+			for (Relation rel : relations.get(oldtype)) {
+				String newtype = rel.getProp(oldprop);
+				rel.supProp(oldprop);
+				rel.getElt1().oteRelationSortante(rel);
+				rel.getElt2().oteRelationEntrante(rel);
+				rel.setType(newtype);
+				rel.getElt1().addRelationSortante(rel);
+				rel.getElt2().addRelationEntrante(rel);
+				relations.get(newtype).add(rel);
+			}
+			relations.remove(oldtype);
+		} else if (classe==Schema.class) {
+			for (String type : newtypes) schemas.put(type, new ArrayList<Schema>());
+			for (Schema sch : schemas.get(oldtype)) {
+				String newtype = sch.getProp(oldprop);
+				sch.supProp(oldprop);
+				for (Element elt : sch.getContenu()) elt.oteSchemaContenant(sch);
+				sch.setType(newtype);
+				for (Element elt : sch.getContenu()) elt.addSchemaContenant(sch);
+				schemas.get(newtype).add(sch);
+			}
+			schemas.remove(oldtype);
+		}
+		fireMessage(new StructureEvent(this, TypeModifStructure.SUPPR_TYPE,
+				classe, oldtype));
+		for (String type : newtypes) {
+			fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_TYPE_ET_ELEMENTS,
+					classe, type));
+			for (String prop : props)
+				fireMessage(new StructureEvent(this, TypeModifStructure.AJOUT_PROP,
+						classe, type, prop));
+		}
+		return true;
+	}
+	public void clearAnnot() {
+		finParagraphes.clear();
+		unites.clear();
+		relations.clear();
+		schemas.clear();
+	}
+	public void clearAll() {
+		clearAnnot();
+		structure.clear();
+		texte = "";
+	}
+	public boolean isModifie() {
+		return modifie;
+	}
+	public boolean isVide() {
+		return texte.isEmpty()&&structure.isVide();
+	}
+	public void fermer() {
+		if (isVide()) return;
+		clearAnnot();
+		structure.clear();
+		texte = "";
+		fireMessage(new Message(this, TypeMessage.CLEAR_CORPUS));
+	}
+	public void fermerConserverStructure() {
+		if (texte.isEmpty()) return;
+		clearAnnot();
+		texte = "";
+		fireMessage(new Message(this, TypeMessage.CLEAR_CORPUS));
+	}
+	@SuppressWarnings("unchecked")
+	public void lireJava(ObjectInputStream ois, boolean batch) throws IOException, ClassNotFoundException, ClassCastException {
+		texte = (String) ois.readObject();
+		finParagraphes = (ArrayList<Integer>) ois.readObject();
+		unites = (HashMap<String, ArrayList<Unite>>) ois.readObject();
+		relations = (HashMap<String, ArrayList<Relation>>) ois.readObject();
+		schemas = (HashMap<String, ArrayList<Schema>>) ois.readObject();
+		structure = Structure.lireJava(ois);
+		if (!batch) fireMessage(new Message(this, TypeMessage.NEW_CORPUS));
+	}
+	@SuppressWarnings("unchecked")
+	public void fusionnerAnnotJava(ObjectInputStream ois) throws IOException, ClassNotFoundException, ClassCastException {
+		String texte1 = (String) ois.readObject();
+		ArrayList<Integer> finParagraphes1 = (ArrayList<Integer>) ois.readObject();
+		if (!texte1.equals(texte)||!finParagraphes1.equals(finParagraphes)) {
+			JOptionPane.showMessageDialog(null, "Le texte du corpus à fusionner est différent du texte en cours",
+					"Fusion d'annotations impossible.", JOptionPane.ERROR_MESSAGE);
+			return;
+		}
+		HashMap<String, ArrayList<Unite>> unites1 = (HashMap<String, ArrayList<Unite>>) ois.readObject();
+		HashMap<String, ArrayList<Relation>> relations1 = (HashMap<String, ArrayList<Relation>>) ois.readObject();
+		HashMap<String, ArrayList<Schema>> schemas1 = (HashMap<String, ArrayList<Schema>>) ois.readObject();
+		Structure structure1 = Structure.lireJava(ois);
+		fusionnerStructureLue(structure1);
+		HashSet<Unite> unitesAajouter = new HashSet<Unite>();
+		HashMap<Unite, Unite> unitesAfusionner = new HashMap<Unite, Unite>();
+		int nbUnitesEcrasees = checkFusionnerUnites(unites1, unitesAajouter, unitesAfusionner);
+		HashSet<Relation> relationsAajouter = new HashSet<Relation>();
+		HashMap<Relation, Relation> relationsAfusionner = new HashMap<Relation, Relation>();
+		int nbRelationsEcrasees = checkFusionnerRelations(relations1, relationsAajouter, relationsAfusionner);
+		HashSet<Schema> schemasAajouter = new HashSet<Schema>();
+		HashMap<Schema, Schema> schemasAfusionner = new HashMap<Schema, Schema>();
+		int nbSchemasEcrases = checkFusionnerSchemas(schemas1, schemasAajouter, schemasAfusionner);
+		int nbEcrases = nbUnitesEcrasees+nbRelationsEcrasees+nbSchemasEcrases; // à améliorer
+		if (nbUnitesEcrasees>0||nbRelationsEcrasees>0||nbSchemasEcrases>0) {
+			int rep = JOptionPane.showOptionDialog(null, "L'opération de fusion va écraser d'anciennes valeurs de propriétés "
+					+" pour "+nbEcrases+" élément(s)", "Fusion d'annotations",
+					JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+					null, new Object[]{"Continuer", "Annuler"}, "Annuler");
+			if (rep==1 || rep == JOptionPane.CLOSED_OPTION) return;
+		}
+		for (Unite unit : unitesAajouter) addUniteLue(unit);
+		for (Unite unit : unitesAfusionner.keySet())
+			for (String prop : unit.getProps().keySet())
+				unitesAfusionner.get(unit).putProp(prop, unit.getProp(prop));
+		for (Relation rel : relationsAajouter) {
+			fusionnerElementsRelation(rel, unitesAfusionner, relationsAfusionner, schemasAfusionner);
+			addRelationLue(rel);
+		}
+		for (Relation rel : relationsAfusionner.keySet())
+			for (String prop : rel.getProps().keySet())
+				relationsAfusionner.get(rel).putProp(prop, rel.getProp(prop));
+		for (Schema sch : schemasAajouter) {
+			fusionnerElementsSchema(sch, unitesAfusionner, relationsAfusionner, schemasAfusionner);
+			addSchemaLu(sch);
+		}
+		for (Schema sch : schemasAfusionner.keySet())
+			for (String prop : sch.getProps().keySet())
+				schemasAfusionner.get(sch).putProp(prop, sch.getProp(prop));
+		fireMessage(new Message(this, TypeMessage.NEW_CORPUS));
+	}
+	@SuppressWarnings("unchecked")
+	public void concatenerCorpusJava(ObjectInputStream ois) throws IOException, ClassNotFoundException, ClassCastException {
+		String texte1 = (String) ois.readObject();
+		ArrayList<Integer> finParagraphes1 = (ArrayList<Integer>) ois.readObject();
+		int offset = texte.length();
+		texte += texte1;
+		for (int finP : finParagraphes1) finParagraphes.add(finP+offset);
+		verifierFinParagrapheFinTexte();
+		HashMap<String, ArrayList<Unite>> unites1 = (HashMap<String, ArrayList<Unite>>) ois.readObject();
+		HashMap<String, ArrayList<Relation>> relations1 = (HashMap<String, ArrayList<Relation>>) ois.readObject();
+		HashMap<String, ArrayList<Schema>> schemas1 = (HashMap<String, ArrayList<Schema>>) ois.readObject();
+		Structure structure1 = Structure.lireJava(ois);
+		fusionnerStructureLue(structure1);
+		for (String type : unites1.keySet()) for (Unite unit : unites1.get(type)) {
+			unit.setDeb(unit.getDeb()+offset);
+			unit.setFin(unit.getFin()+offset);
+			addUniteLue(unit);
+		}
+		for (String type : relations1.keySet())
+			for (Relation rel : relations1.get(type)) {
+				addRelationLue(rel);
+			}
+		for (String type : schemas1.keySet())
+			for (Schema sch : schemas1.get(type)) {
+				addSchemaLu(sch);
+			}
+	}
+	@SuppressWarnings("unchecked")
+	public void extraireEtConcatenerCorpusJava(ObjectInputStream ois,
+			String nomDocument, String type)
+					throws IOException, ClassNotFoundException, ClassCastException {
+		//    System.out.println(nomDocument);
+		String texte1 = (String) ois.readObject();
+		ArrayList<Integer> finParagraphes1 = (ArrayList<Integer>) ois.readObject();
+		HashMap<String, ArrayList<Unite>> unites1 = (HashMap<String, ArrayList<Unite>>) ois.readObject();
+		if (unites1.containsKey(type)) {
+			int indFinPar1 = -1;
+			int offset1 = -1;
+			int offset = -1;
+			for (Unite unit : unites1.get(type)) {
+				int finUnit = unit.getFin();
+				if (indFinPar1<0||finUnit>finParagraphes1.get(indFinPar1)) {
+					do indFinPar1++;
+					while (finUnit>finParagraphes1.get(indFinPar1));
+					offset1 = indFinPar1==0 ? 0 : finParagraphes1.get(indFinPar1-1);
+					offset = texte.length();
+					texte += texte1.substring(offset1, finParagraphes1.get(indFinPar1));
+					finParagraphes.add(texte.length());
+				}
+				unit.setDeb(unit.getDeb()-offset1+offset);
+				unit.setFin(unit.getFin()-offset1+offset);
+				unit.putProp("sourceFile", nomDocument);
+				addUniteLue(unit);
+			}
+		}
+	}
+	public void ecrireJava(ObjectOutputStream oos) throws IOException {
+		oos.writeObject(texte);
+		oos.writeObject(finParagraphes);
+		oos.writeObject(unites);
+		oos.writeObject(relations);
+		oos.writeObject(schemas);
+		structure.ecrireJava(oos);
+		modifie = false;
+		fireMessage(new Message(this, TypeMessage.CORPUS_SAVED));
+	}
+	@SuppressWarnings("unchecked")
+	public void fusionnerStructureLue(Structure structureLue) {
+		for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class
+		}) {
+			for (String typeLu : structureLue.getTypes(classe)) {
+				if (!structure.getTypes(classe).contains(typeLu))
+					ajouterType(classe, typeLu);
+				for (String propLue : structureLue.getNomsProps(classe, typeLu)) {
+					if (!structure.getNomsProps(classe, typeLu).contains(propLue))
+						structure.ajouterProp(classe, typeLu, propLue);
+					for (String valLue : structureLue.getValeursProp(classe, typeLu, propLue))
+						if (!structure.getValeursProp(classe, typeLu, propLue).contains(valLue))
+							structure.ajouterVal(classe, typeLu, propLue, valLue);
+					String valdefLue = structureLue.getValeurParDefaut(classe, typeLu, propLue);
+					String valdef = structure.getValeurParDefaut(classe, typeLu, propLue);
+					if (!valdefLue.isEmpty()&&!valdefLue.equals(valdef)) {
+						structure.modifierValParDefaut(classe, typeLu, propLue, valdefLue);
+					}
+				}
+			}
+		}
+		fireMessage(new StructureEvent(this, TypeModifStructure.FUSION_TYPE, Unite.class, "", "", ""));
+	}
+	public void ecrireStructureJava(ObjectOutputStream oos) throws IOException {
+		structure.ecrireJava(oos);
+	}
+	public Structure lireStructureJava(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+		return Structure.lireJava(ois);
+	}
+	public void lireTexte(BufferedReader text) throws IOException {
+		String parag;
+		String newtexte = "";
+		ArrayList<Integer> newfinParag = new ArrayList<Integer>();
+		while ((parag = text.readLine())!=null) {
+			newtexte += parag;
+			newfinParag.add(newtexte.length());
+		}
+		texte = newtexte;
+		finParagraphes = newfinParag;
+		fireMessage(new Message(this, TypeMessage.NEW_CORPUS));
+	}
+	public void newCorpusLu() {
+		fireMessage(new Message(this, TypeMessage.NEW_CORPUS));
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/donnees/Corpus.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/donnees/Structure.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/donnees/Structure.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/donnees/Structure.java	(revision 3653)
@@ -0,0 +1,319 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.donnees;
+
+import java.io.*;
+import java.util.*;
+import visuAnalec.elements.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class Structure implements Serializable {
+	
+	public final static String FORME = "#forme#";
+	
+	private HashMap<Class<? extends Element>, HashSet<String>> types = new HashMap<>();
+	
+	private HashMap<Class<? extends Element>, HashMap<String, HashSet<String>>> nomsProps = new HashMap<>();
+	
+	private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashSet<String>>>> valeursProps = new HashMap<>();
+	
+	private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, String>>> valeursParDefaut = new HashMap<>();
+	
+	@SuppressWarnings("unchecked")
+	public Structure() {
+		for (Class<? extends Element> classe : new Class[] { Unite.class, Relation.class, Schema.class }) {
+			types.put(classe, new HashSet<String>());
+			nomsProps.put(classe, new HashMap<String, HashSet<String>>());
+			valeursProps.put(classe, new HashMap<String, HashMap<String, HashSet<String>>>());
+			valeursParDefaut.put(classe, new HashMap<String, HashMap<String, String>>());
+		}
+	}
+	
+	public HashSet<String> getSchemas() {
+		return this.getTypes(Schema.class);
+	}
+	
+	public HashSet<String> getRelations() {
+		return this.getTypes(Relation.class);
+	}
+	
+	public HashSet<String> getUnites() {
+		return this.getTypes(Unite.class);
+	}
+	
+	public HashSet<String> getSchemaProperties(String schema_type) {
+		return getNomsProps(Schema.class, schema_type);
+	}
+	
+	public HashSet<String> getUniteProperties(String schema_type) {
+		return getNomsProps(Unite.class, schema_type);
+	}
+	
+	public HashSet<String> getRelationProperties(String schema_type) {
+		return getNomsProps(Relation.class, schema_type);
+	}
+	
+	@Override
+	public String toString() {
+		String dump = "STRUCTURE :";
+		dump += "\n\tUNITES : ";
+		dump += "\n\t\tTYPES : ";
+		for (String type : types.get(Unite.class)) {
+			dump += type + "; ";
+		}
+		dump += "\n\t\tNOMSPROP : ";
+		for (String type : nomsProps.get(Unite.class).keySet()) {
+			dump += "\n\t\t\t" + type + " : ";
+			for (String prop : nomsProps.get(Unite.class).get(type)) {
+				dump += prop + "; ";
+			}
+		}
+		dump += "\n\t\tVALEURSPROP : ";
+		for (String type : valeursProps.get(Unite.class).keySet()) {
+			dump += "\n\t\t\t" + type + " : ";
+			for (String prop : valeursProps.get(Unite.class).get(type).keySet()) {
+				dump += "\n\t\t\t\t" + prop + " : ";
+				for (String val : valeursProps.get(Unite.class).get(type).get(prop)) {
+					dump += val + "; ";
+				}
+			}
+		}
+		
+		dump += "\n\tRELATIONS : ";
+		dump += "\n\t\tTYPES : ";
+		for (String type : types.get(Relation.class)) {
+			dump += type + "; ";
+		}
+		dump += "\n\t\tNOMSPROP : ";
+		for (String type : nomsProps.get(Relation.class).keySet()) {
+			dump += "\n\t\t\t" + type + " : ";
+			for (String prop : nomsProps.get(Relation.class).get(type)) {
+				dump += prop + "; ";
+			}
+		}
+		dump += "\n\t\tVALEURSPROP : ";
+		for (String type : valeursProps.get(Relation.class).keySet()) {
+			dump += "\n\t\t\t" + type + " : ";
+			for (String prop : valeursProps.get(Relation.class).get(type).keySet()) {
+				dump += "\n\t\t\t\t" + prop + " : ";
+				for (String val : valeursProps.get(Relation.class).get(type).get(prop)) {
+					dump += val + "; ";
+				}
+			}
+		}
+		
+		dump += "\n\tSCHEMAS : ";
+		dump += "\n\t\tTYPES : ";
+		for (String type : types.get(Schema.class)) {
+			dump += type + "; ";
+		}
+		dump += "\n\t\tNOMSPROP : ";
+		for (String type : nomsProps.get(Schema.class).keySet()) {
+			dump += "\n\t\t\t" + type + " : ";
+			for (String prop : nomsProps.get(Schema.class).get(type)) {
+				dump += prop + "; ";
+			}
+		}
+		dump += "\n\t\tVALEURSPROP : ";
+		for (String type : valeursProps.get(Schema.class).keySet()) {
+			dump += "\n\t\t\t" + type + " : ";
+			for (String prop : valeursProps.get(Schema.class).get(type).keySet()) {
+				dump += "\n\t\t\t\t" + prop + " : ";
+				for (String val : valeursProps.get(Schema.class).get(type).get(prop)) {
+					dump += val + "; ";
+				}
+			}
+		}
+		
+		
+		return dump;
+	}
+	
+	public HashSet<String> getNomsProps(Class<? extends Element> classe, String type) {
+		if (nomsProps.get(classe).containsKey(type)) {
+			return nomsProps.get(classe).get(type);
+		}
+		return new HashSet<>();
+	}
+	
+	public HashSet<String> getValeursProp(Class<? extends Element> classe, String type, String prop) {
+		if (valeursProps.get(classe).containsKey(type) && valeursProps.get(classe).get(type).containsKey(prop)) {
+			return (valeursProps.get(classe).get(type).get(prop));
+		}
+		return new HashSet<>();
+	}
+	
+	public String getValeurParDefaut(Class<? extends Element> classe, String type, String prop) {
+		if (valeursParDefaut.get(classe).containsKey(type) && valeursParDefaut.get(classe).get(type).containsKey(prop)) {
+			return (valeursParDefaut.get(classe).get(type).get(prop));
+		}
+		return "";
+	}
+	
+	public HashSet<String> getTypes(Class<? extends Element> classe) {
+		return (types.get(classe));
+	}
+	
+	public boolean isVide() {
+		for (Class<? extends Element> classe : new Class[] { Unite.class, Relation.class, Schema.class }) {
+			if (!types.get(classe).isEmpty()) return false;
+		}
+		return true;
+	}
+	
+	void clear() {
+		for (Class<? extends Element> classe : new Class[] { Unite.class, Relation.class, Schema.class }) {
+			types.get(classe).clear();
+			nomsProps.get(classe).clear();
+			valeursProps.get(classe).clear();
+			valeursParDefaut.get(classe).clear();
+		}
+	}
+	
+	public void ajouterVal(Class<? extends Element> classe, String type, String prop, String val) {
+		valeursProps.get(classe).get(type).get(prop).add(val);
+	}
+	
+	void renommerVal(Class<? extends Element> classe, String type, String prop, String oldNom, String newNom) {
+		valeursProps.get(classe).get(type).get(prop).add(newNom);
+		valeursProps.get(classe).get(type).get(prop).remove(oldNom);
+		if (oldNom.equals(valeursParDefaut.get(classe).get(type).get(prop))) {
+			valeursParDefaut.get(classe).get(type).put(prop, newNom);
+		}
+	}
+	
+	void supprimerVal(Class<? extends Element> classe, String type, String prop, String oldNom) {
+		valeursProps.get(classe).get(type).get(prop).remove(oldNom);
+		if (oldNom.equals(valeursParDefaut.get(classe).get(type).get(prop))) {
+			valeursParDefaut.get(classe).get(type).put(prop, "");
+		}
+	}
+	
+	public void modifierValParDefaut(Class<? extends Element> classe, String type, String prop, String val) {
+		valeursParDefaut.get(classe).get(type).put(prop, val);
+	}
+	
+	public void ajouterProp(Class<? extends Element> classe, String type, String prop) {
+		nomsProps.get(classe).get(type).add(prop);
+		valeursProps.get(classe).get(type).put(prop, new HashSet<String>());
+		valeursParDefaut.get(classe).get(type).put(prop, "");
+	}
+	
+	void renommerProp(Class<? extends Element> classe, String type, String oldNom, String newNom) {
+		nomsProps.get(classe).get(type).add(newNom);
+		nomsProps.get(classe).get(type).remove(oldNom);
+		valeursProps.get(classe).get(type).put(newNom, valeursProps.get(classe).get(type).get(oldNom));
+		valeursProps.get(classe).get(type).remove(oldNom);
+		valeursParDefaut.get(classe).get(type).put(newNom, valeursParDefaut.get(classe).get(type).get(oldNom));
+		valeursParDefaut.get(classe).get(type).remove(oldNom);
+	}
+	
+	void fusionnerProp(Class<? extends Element> classe, String type, String oldNom, String newNom) {
+		nomsProps.get(classe).get(type).remove(oldNom);
+		if (!valeursProps.get(classe).containsKey(type)) {
+			ajouterType(classe, type);
+		}
+		if (!valeursProps.get(classe).get(type).containsKey(newNom)) {
+			ajouterProp(classe, type, newNom);
+		}
+		valeursProps.get(classe).get(type).get(newNom).addAll(valeursProps.get(classe).get(type).get(oldNom));
+		valeursProps.get(classe).get(type).remove(oldNom);
+		if (!valeursParDefaut.get(classe).get(type).get(oldNom).isEmpty()) {
+			valeursParDefaut.get(classe).get(type).put(newNom, valeursParDefaut.get(classe).get(type).get(oldNom));
+		}
+		valeursParDefaut.get(classe).get(type).remove(oldNom);
+	}
+	
+	void supprimerProp(Class<? extends Element> classe, String type, String prop) {
+		nomsProps.get(classe).get(type).remove(prop);
+		valeursProps.get(classe).get(type).remove(prop);
+		valeursParDefaut.get(classe).get(type).remove(prop);
+	}
+	
+	@SuppressWarnings("unchecked")
+	public void ajouterType(Class<? extends Element> classe, String type) {
+		types.get(classe).add(type);
+		nomsProps.get(classe).put(type, new HashSet<String>());
+		valeursProps.get(classe).put(type, new HashMap<String, HashSet<String>>());
+		valeursParDefaut.get(classe).put(type, new HashMap<String, String>());
+	}
+	// }
+	
+	void renommerType(Class<? extends Element> classe, String oldType, String newType) {
+		types.get(classe).add(newType);
+		types.get(classe).remove(oldType);
+		nomsProps.get(classe).put(newType, nomsProps.get(classe).get(oldType));
+		nomsProps.get(classe).remove(oldType);
+		valeursProps.get(classe).put(newType, valeursProps.get(classe).get(oldType));
+		valeursProps.get(classe).remove(oldType);
+		valeursParDefaut.get(classe).put(newType, valeursParDefaut.get(classe).get(oldType));
+		valeursParDefaut.get(classe).remove(oldType);
+	}
+	
+	void fusionnerType(Class<? extends Element> classe, String oldType, String newType) {
+		types.get(classe).remove(oldType);
+		for (String prop : nomsProps.get(classe).get(oldType)) {
+			if (!nomsProps.get(classe).get(newType).contains(prop))
+				ajouterProp(classe, newType, prop);
+			for (String val : valeursProps.get(classe).get(oldType).get(prop))
+				if (!valeursProps.get(classe).get(newType).get(prop).contains(val))
+					ajouterVal(classe, newType, prop, val);
+			String valdef1 = getValeurParDefaut(classe, oldType, prop);
+			String valdef = getValeurParDefaut(classe, newType, prop);
+			if (!valdef1.isEmpty() && !valdef1.equals(valdef)) {
+				modifierValParDefaut(classe, newType, prop, valdef1);
+			}
+		}
+		nomsProps.get(classe).remove(oldType);
+		valeursProps.get(classe).remove(oldType);
+		valeursParDefaut.get(classe).remove(oldType);
+		
+	}
+	
+	void supprimerType(Class<? extends Element> classe, String type) {
+		types.get(classe).remove(type);
+		nomsProps.get(classe).remove(type);
+		valeursProps.get(classe).remove(type);
+		valeursParDefaut.get(classe).remove(type);
+	}
+	
+	void majNewElement(Element element) { // appelé par corpus.addUniteLue, addRelationLue, addSchemaLu
+		String type = element.getType();
+		Class<? extends Element> classe = element.getClass();
+		if (!types.get(classe).contains(type)) {
+			ajouterType(classe, type);
+		}
+		HashMap<String, String> props = element.getProps();
+		for (String prop : props.keySet()) {
+			if (!nomsProps.get(classe).get(type).contains(prop)) {
+				ajouterProp(classe, type, prop);
+			}
+			String val = props.get(prop);
+			if (val != null && !val.isEmpty() && !valeursProps.get(classe).get(type).get(prop).contains(val)) {
+				ajouterVal(classe, type, prop, val);
+			}
+		}
+	}
+	
+	@SuppressWarnings("unchecked")
+	public static Structure lireJava(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+		Structure structure = new Structure();
+		structure.types = (HashMap<Class<? extends Element>, HashSet<String>>) ois.readObject();
+		structure.nomsProps = (HashMap<Class<? extends Element>, HashMap<String, HashSet<String>>>) ois.readObject();
+		structure.valeursProps = (HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashSet<String>>>>) ois.readObject();
+		structure.valeursParDefaut = (HashMap<Class<? extends Element>, HashMap<String, HashMap<String, String>>>) ois.readObject();
+		return structure;
+	}
+	
+	public void ecrireJava(ObjectOutputStream oos) throws IOException {
+		oos.writeObject(types);
+		oos.writeObject(nomsProps);
+		oos.writeObject(valeursProps);
+		oos.writeObject(valeursParDefaut);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/donnees/Structure.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Element.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Element.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Element.java	(revision 3653)
@@ -0,0 +1,193 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.elements;
+
+import java.io.Serializable;
+import java.util.*;
+import java.util.ArrayList;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public abstract class Element implements Serializable, Comparable {
+  private String type;
+  private HashMap<String, String> props = new HashMap<String, String>();
+  private HashMap<String, ArrayList<Relation>> relationsEntrantes = new HashMap<String, ArrayList<Relation>>();
+  private HashMap<String, ArrayList<Relation>> relationsSortantes = new HashMap<String, ArrayList<Relation>>();
+  private HashMap<String, ArrayList<Schema>> schemasContenants = new HashMap<String, ArrayList<Schema>>();
+  Element() {
+  }
+  Element(String type) {
+    this.type = type;
+  }
+  @Override
+  public String toString() {
+    String dump = "ELEMENT "+type;
+    dump += "\n\tPROPS : ";
+    for (String prop : props.keySet()) {
+      dump += "\n\t\t"+prop+" : "+props.get(prop);
+    }
+    dump += "\n\tRELATIONS ENTRANTES : ";
+    for (String typ : relationsEntrantes.keySet()) {
+      dump += "\n\t\t"+typ+" : ";
+      for (Relation rel : relationsEntrantes.get(typ)) {
+        dump += rel.getElt1().getType();
+      }
+    }
+    dump += "\n\tRELATIONS SORTANTES : ";
+    for (String typ : relationsSortantes.keySet()) {
+      dump += "\n\t\t"+typ+" : ";
+      for (Relation rel : relationsSortantes.get(typ)) {
+        dump += rel.getElt2().getType();
+      }
+    }
+    return dump;
+  }
+  public String getType() {
+    return type;
+  }
+  public void setType(String type) {
+    this.type = type;
+  }
+  public HashMap<String, String> getProps() {
+    return props;
+  }
+  public String getProp(String prop) {
+    if (props.get(prop)==null) {
+      return "";
+    }
+    return props.get(prop);
+  }
+  public void putProp(String prop, String valeur) {
+    props.put(prop, valeur);
+  }
+  public void supProp(String prop) {
+    props.remove(prop);
+  }
+  public void addRelationEntrante(Relation rel) {
+    if (!relationsEntrantes.containsKey(rel.getType())) {
+      relationsEntrantes.put(rel.getType(), new ArrayList<Relation>());
+    }
+    relationsEntrantes.get(rel.getType()).add(rel);
+  }
+  public void oteRelationEntrante(Relation rel) {
+    relationsEntrantes.get(rel.getType()).remove(rel);
+  }
+  public void addRelationSortante(Relation rel) {
+    if (!relationsSortantes.containsKey(rel.getType())) {
+      relationsSortantes.put(rel.getType(), new ArrayList<Relation>());
+    }
+    relationsSortantes.get(rel.getType()).add(rel);
+  }
+  public void oteRelationSortante(Relation rel) {
+    relationsSortantes.get(rel.getType()).remove(rel);
+  }
+  public void addSchemaContenant(Schema sch) {
+    if (!schemasContenants.containsKey(sch.getType())) {
+      schemasContenants.put(sch.getType(), new ArrayList<Schema>());
+    }
+    schemasContenants.get(sch.getType()).add(sch);
+  }
+  public void oteSchemaContenant(Schema sch) {
+    schemasContenants.get(sch.getType()).remove(sch);
+  }
+  public ArrayList<Relation> getRelations() {
+    ArrayList<Relation> rels = new ArrayList<Relation>();
+    for (String typerel : relationsEntrantes.keySet()) {
+      rels.addAll(relationsEntrantes.get(typerel));
+    }
+    for (String typerel : relationsSortantes.keySet()) {
+      rels.addAll(relationsSortantes.get(typerel));
+    }
+    return rels;
+  }
+  public ArrayList<Schema> getSchemas() {
+    ArrayList<Schema> schs = new ArrayList<Schema>();
+    for (String typesch : schemasContenants.keySet()) {
+      schs.addAll(schemasContenants.get(typesch));
+    }
+    return schs;
+  }
+  public Element getElementSuivant(Jalon jalon) {
+    switch (jalon.origine) {
+      case ELT_0:
+        return this;
+      case REL_SORTANTE:
+        if (!relationsSortantes.containsKey(jalon.type)||relationsSortantes.get(jalon.type).isEmpty()) {
+          return null;
+        }
+        return relationsSortantes.get(jalon.type).get(0);
+      case REL_ENTRANTE:
+        if (!relationsEntrantes.containsKey(jalon.type)||relationsEntrantes.get(jalon.type).isEmpty()) {
+          return null;
+        }
+        return relationsEntrantes.get(jalon.type).get(0);
+      case SCH_CONTENANT:
+        if (!schemasContenants.containsKey(jalon.type)||schemasContenants.get(jalon.type).isEmpty()) {
+          return null;
+        }
+        return schemasContenants.get(jalon.type).get(0);
+      default:  // les cas ELT_1 et ELT_2 sont traités par la classe Relation
+        throw new UnsupportedOperationException("Pas encore implémenté");
+    }
+  }
+  protected abstract HashSet<Unite> getUnitesSousjacentesNonTriees();
+  public Unite[] getUnitesSousjacentes() { // triées
+    Unite[] units = getUnitesSousjacentesNonTriees().toArray(new Unite[0]);
+    Arrays.sort(units);
+    return units;
+  }
+  public Unite getUnite0() {
+    Unite[] units = getUnitesSousjacentes();
+    if (units.length==0) return null;
+    return units[0];
+  }
+  public static Unite[] getUnites0(Element[] elts) {
+    Unite[] units = new Unite[elts.length];
+    for (int i = 0; i<elts.length; i++) units[i] = elts[i].getUnite0();
+    return units;
+  }
+  public static Unite[] getUnitesSousjacentes(Element[] elts) { // triées : est-ce nécessaire ??
+    ArrayList<Unite> lunits = new ArrayList<Unite>();
+    for (Element elt : elts)
+      lunits.addAll(elt.getUnitesSousjacentesNonTriees());
+    Unite[] units = lunits.toArray(new Unite[0]);
+    Arrays.sort(units);
+    return units;
+  }
+  public static Element trouverElementParUniteSousjacente(Element[] elements, Unite unite) { // prend le premier
+    for (Element elt : elements) {
+      int i = Arrays.binarySearch(elt.getUnitesSousjacentes(), unite);
+      if (i>=0) return elt;
+    }
+    return null;
+  }
+  public static ArrayList<Element> trouverElementsParUniteSousjacente(Element[] elements, Unite unite) {
+    ArrayList<Element> elts = new ArrayList<Element>();
+    for (Element elt : elements) {
+      int i = Arrays.binarySearch(elt.getUnitesSousjacentes(), unite);
+      if (i>=0) elts.add(elt);
+    }
+    return elts;
+  }
+  public int compareTo(Object obj) {
+    if (obj.getClass().getSuperclass()!=Element.class) {
+      throw new ClassCastException("Comparaison impossible : "+obj.toString()+" n'est pas une instance d'Elément");
+    }
+    Unite[] unites1 = getUnitesSousjacentes();
+    Unite[] unites2 = ((Element) obj).getUnitesSousjacentes();
+    int comp;
+    for (int i = 0; i<unites1.length; i++) {
+      if (i==unites2.length) return 1;
+      if ((comp = unites1[i].compareTo(unites2[i]))!=0) return comp;
+    }
+    if (unites1.length<unites2.length) return -1;
+    return Integer.signum(hashCode()-obj.hashCode());
+  }
+  abstract public boolean coincide(Element elt);
+//  abstract boolean contientSchemaSousJacent(Schema sch);
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Element.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Relation.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Relation.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Relation.java	(revision 3653)
@@ -0,0 +1,64 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.elements;
+
+import java.util.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class Relation extends Element {
+  private Element elt1, elt2;
+  public Relation() {
+    super();
+  }
+  public Relation(String type, Element elt1, Element elt2) {
+    super(type);
+    setElt1(elt1);
+    setElt2(elt2);
+  }
+  public Element getElt1() {
+    return elt1;
+  }
+  public void setElt1(Element elt) {
+    elt1 = elt;
+  }
+  public Element getElt2() {
+    return elt2;
+  }
+  public void setElt2(Element elt) {
+    elt2 = elt;
+  }
+  @Override
+  public Element getElementSuivant(Jalon jalon) {
+    switch (jalon.origine) {
+      case ELT_2:
+        if (elt2.getClass()==jalon.classe&&elt2.getType().equals(jalon.type))
+          return elt2;
+        return null;
+      case ELT_1:
+        if (elt1.getClass()==jalon.classe&&elt1.getType().equals(jalon.type))
+          return elt1;
+        return null;
+      default:
+        return super.getElementSuivant(jalon);
+    }
+  }
+  protected HashSet<Unite> getUnitesSousjacentesNonTriees() {
+    HashSet<Unite> units = elt1.getUnitesSousjacentesNonTriees();
+    units.addAll(elt2.getUnitesSousjacentesNonTriees());
+    return units;
+  }
+//  boolean contientSchemaSousJacent(Schema sch) {
+//    return elt1.contientSchemaSousJacent(sch)||elt2.contientSchemaSousJacent(sch);
+//  }
+  public boolean coincide(Element elt) {
+    if (elt.getClass()!=Relation.class) return false;
+    Relation rel = (Relation) elt;
+    return getType().equals(rel.getType())&&elt1.coincide(rel.elt1)&&elt2.coincide(rel.elt2);
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Relation.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Schema.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Schema.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Schema.java	(revision 3653)
@@ -0,0 +1,83 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.elements;
+
+import java.util.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class Schema extends Element {
+  private HashSet<Element> contenu = new HashSet<Element>();
+  public Schema() {
+    super();
+  }
+  public Schema(String type) {
+    super(type);
+  }
+  public boolean ajouter(Element elt) {
+    // retourne false ssi pb de recursivité
+    if (elt==null) return true;
+    // à remplacer lors d'un chgt de version modifiant la signature de la classe
+// Element par :if (elt.contientSchemaSousJacent(this)) return false;
+    if (contientSchemaSousJacent(elt, this)) return false;
+    contenu.add(elt);
+    return true;
+  }
+  public boolean oter(Element elt) {
+    return contenu.remove(elt);
+  }
+  public HashSet<Element> getContenu() {
+    return contenu;
+  }
+  public boolean contient(Element elt) {
+    return contenu.contains(elt);
+  }
+  protected HashSet<Unite> getUnitesSousjacentesNonTriees() {
+    HashSet<Unite> units = new HashSet<Unite>();
+    for (Element elt : contenu) {
+      units.addAll(elt.getUnitesSousjacentesNonTriees());
+    }
+    return units;
+  }
+//  boolean contientSchemaSousJacent(Schema sch) {
+//    if (coincide(sch)) return true;
+//    for (Element elt : contenu) if (elt.contientSchemaSousJacent(sch))
+//        return true;
+//    return false;
+//  }
+  private static boolean contientSchemaSousJacent(Element elt, Schema sch) {
+    // Solution provisoire en attendant le chgt de version modifiant la signature
+    // de la classe Element
+    if (elt.getClass()==Unite.class) return false;
+    if (elt.getClass()==Relation.class) {
+      Relation rel = (Relation) elt;
+      return contientSchemaSousJacent(rel.getElt1(), sch)
+              ||contientSchemaSousJacent(rel.getElt2(), sch);
+    }
+    if (elt.getClass()==Schema.class) {
+      Schema sch1 = (Schema) elt;
+      if (sch1.coincide(sch)) return true;
+      for (Element elt1 : sch1.contenu) if (contientSchemaSousJacent(elt1, sch))
+          return true;
+      return false;
+    }
+    throw new IllegalArgumentException("Element de classe non identifiée");
+  }
+  public boolean coincide(Element elt) {
+    if (elt.getClass()!=Schema.class) return false;
+    Schema sch = (Schema) elt;
+    if (!getType().equals(sch.getType())) return false;
+    if (contenu.size()!=sch.getContenu().size()) return false;
+    Element[] contenu1 = contenu.toArray(new Element[0]);
+    Arrays.sort(contenu1);
+    Element[] contenu2 = sch.getContenu().toArray(new Element[0]);
+    Arrays.sort(contenu2);
+    for (int i = 0; i<contenu1.length; i++)
+      if (!contenu1[i].coincide(contenu2[i])) return false;
+    return true;
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Schema.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Unite.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Unite.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Unite.java	(revision 3653)
@@ -0,0 +1,70 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.elements;
+
+import java.util.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class Unite extends Element implements Comparable {
+  private int deb;
+  private int fin;
+  public Unite() {
+    super();
+  }
+  public Unite(String type, int deb, int fin) {
+    super(type);
+    this.deb = deb;
+    this.fin = fin;
+  }
+  public int getDeb() {
+    return deb;
+  }
+  public void setDeb(int deb) {
+    this.deb = deb;
+  }
+  public int getFin() {
+    return fin;
+  }
+  public void setFin(int fin) {
+    this.fin = fin;
+  }
+//  boolean contientSchemaSousJacent(Schema sch) {
+//    return false;
+//  }
+  public boolean coincide(Element elt) {
+    if (elt.getClass()!=Unite.class) return false;
+    Unite unit = (Unite) elt;
+    return getType().equals(unit.getType())&&deb==unit.deb&&fin==unit.fin;
+  }
+  public int compareTo(Unite unit2) {
+    int comp = Integer.signum(deb-unit2.deb);
+    if (comp==0) {
+      comp = -Integer.signum(fin-unit2.fin);
+      if (comp==0) {
+        comp = getType().compareTo(unit2.getType());
+        if (comp==0) {
+          comp = Integer.signum(hashCode()-unit2.hashCode());
+        }
+      }
+    }
+    return comp;
+  }
+  protected HashSet<Unite> getUnitesSousjacentesNonTriees() {
+    HashSet<Unite> units = new HashSet<Unite>();
+    units.add(this);
+    return units;
+  }
+  @Override
+  public Unite getUnite0() {
+    return this;
+  }
+  @Override
+  public Unite[] getUnitesSousjacentes() {
+    return new Unite[]{this};
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/elements/Unite.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/ProgressMonitorDemo.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/ProgressMonitorDemo.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/ProgressMonitorDemo.java	(revision 3653)
@@ -0,0 +1,173 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+/**
+ *
+ * @author Bernard
+ */
+/*
+ * 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.
+ */ 
+
+
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.beans.*;
+import java.util.Random;
+
+public class ProgressMonitorDemo extends JPanel
+                                 implements ActionListener,
+                                            PropertyChangeListener {
+
+    private ProgressMonitor progressMonitor;
+    private JButton startButton;
+    private JTextArea taskOutput;
+    private Task task;
+
+    class Task extends SwingWorker<Void, Void> {
+        @Override
+        public Void doInBackground() {
+            Random random = new Random();
+            int progress = 0;
+            setProgress(0);
+            try {
+                Thread.sleep(1000);
+                while (progress < 100 && !isCancelled()) {
+                    //Sleep for up to one second.
+                    Thread.sleep(random.nextInt(1000));
+                    //Make random progress.
+                    progress += random.nextInt(10);
+                    setProgress(Math.min(progress, 100));
+                }
+            } catch (InterruptedException ignore) {}
+            return null;
+        }
+
+        @Override
+        public void done() {
+            Toolkit.getDefaultToolkit().beep();
+            startButton.setEnabled(true);
+            progressMonitor.setProgress(0);
+        }
+    }
+
+    public ProgressMonitorDemo() {
+        super(new BorderLayout());
+
+        //Create the demo's UI.
+        startButton = new JButton("Start");
+        startButton.setActionCommand("start");
+        startButton.addActionListener(this);
+
+        taskOutput = new JTextArea(5, 20);
+        taskOutput.setMargin(new Insets(5,5,5,5));
+        taskOutput.setEditable(false);
+
+        add(startButton, BorderLayout.PAGE_START);
+        add(new JScrollPane(taskOutput), BorderLayout.CENTER);
+        setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
+
+    }
+
+
+    /**
+     * Invoked when the user presses the start button.
+     */
+    public void actionPerformed(ActionEvent evt) {
+        progressMonitor = new ProgressMonitor(ProgressMonitorDemo.this,
+                                  "Running a Long Task",
+                                  "", 0, 100);
+        progressMonitor.setProgress(0);
+        task = new Task();
+        task.addPropertyChangeListener(this);
+        task.execute();
+        startButton.setEnabled(false);
+    }
+
+    /**
+     * Invoked when task's progress property changes.
+     */
+    public void propertyChange(PropertyChangeEvent evt) {
+        if ("progress" == evt.getPropertyName() ) {
+            int progress = (Integer) evt.getNewValue();
+            progressMonitor.setProgress(progress);
+            String message =
+                String.format("Completed %d%%.\n", progress);
+            progressMonitor.setNote(message);
+            taskOutput.append(message);
+            if (progressMonitor.isCanceled() || task.isDone()) {
+                Toolkit.getDefaultToolkit().beep();
+                if (progressMonitor.isCanceled()) {
+                    task.cancel(true);
+                    taskOutput.append("Task canceled.\n");
+                } else {
+                    taskOutput.append("Task completed.\n");
+                }
+                startButton.setEnabled(true);
+            }
+        }
+
+    }
+
+    /**
+     * Create the GUI and show it.  For thread safety,
+     * this method should be invoked from the
+     * event-dispatching thread.
+     */
+    private static void createAndShowGUI() {
+        //Create and set up the window.
+        JFrame frame = new JFrame("ProgressMonitorDemo");
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+        //Create and set up the content pane.
+        JComponent newContentPane = new ProgressMonitorDemo();
+        newContentPane.setOpaque(true); //content panes must be opaque
+        frame.setContentPane(newContentPane);
+
+        //Display the window.
+        frame.pack();
+        frame.setVisible(true);
+    }
+
+    public static void main(String[] args) {
+        //Schedule a job for the event-dispatching thread:
+        //creating and showing this application's GUI.
+        javax.swing.SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+                createAndShowGUI();
+            }
+        });
+    }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/ProgressMonitorDemo.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersGlozz.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersGlozz.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersGlozz.java	(revision 3653)
@@ -0,0 +1,819 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.xml.parsers.*;
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public abstract class FichiersGlozz {
+	
+	public static void convertirCorpusGlozz(final Corpus corpus) {
+		File repGlozz;
+		final File repJava;
+		if ((repGlozz = Fichiers.choisirRepertoire("Choix du dossier Glozz")) == null)
+			return;
+		if ((repJava = Fichiers.choisirRepertoire("Choix du dossier Java")) == null)
+			return;
+		if (!repJava.exists()) {
+			if (!GMessages.confirmationAction("Le dossier spécifié n'existe pas."
+					+ " Voulez-vous le créer ?")) return;
+			if (!repJava.mkdir()) {
+				GMessages.impossibiliteAction("Echec de la création du dossier");
+				return;
+			}
+		}
+		final File[] fics = Fichiers.listerFichiers(repGlozz, Fichiers.TypeFichier.GLOZZ_CORPUS);
+		final GMessages.GProgression progression = new GMessages.GProgression(fics.length, "Conversion", "fichiers");
+		Thread traitement = new Thread() {
+			
+			@Override
+			public void run() {
+				try {
+					for (int i = 0; i < fics.length; i++) {
+						if (progression.isCanceled()) break;
+						progression.setNbTraites(i + 1);
+						File fichierCorpus = fics[i];
+						File fichierAnnot = Fichiers.trouverFichier(TypeFichier.GLOZZ_ANNOT, fichierCorpus);
+						if (fichierAnnot == null) continue;
+						importer(fichierCorpus, fichierAnnot, corpus);
+						FichiersJava.enregistrerCorpus(corpus, Fichiers.creerFichier(repJava, TypeFichier.DOC_ANALEC, fichierCorpus));
+						// corpus.fermer();
+					}
+					corpus.fermer();
+				}
+				catch (Throwable ex) {
+					GMessages.erreurFatale(ex);
+				}
+			}
+		};
+		traitement.start();
+	}
+	
+	public static boolean importerGlozz(Corpus corpus, File fichierCorpus, File fichierAnnot) {
+		if (!importer(fichierCorpus, fichierAnnot, corpus)) {
+			return false;
+		}
+		corpus.newCorpusLu();
+		
+		return true;
+	}
+	
+	/**
+	 * 
+	 * @param corpus
+	 */
+	public static boolean importerGlozz(Corpus corpus) {
+		File fichierCorpus;
+		File fichierAnnot;
+		if ((fichierCorpus = Fichiers.choisirFichier(Commande.OUVRIR,
+				"Choix du fichier corpus", Fichiers.TypeFichier.GLOZZ_CORPUS)) == null)
+			return false;
+		if ((fichierAnnot = Fichiers.choisirFichier(Commande.OUVRIR,
+				"Choix du fichier annotations", Fichiers.TypeFichier.GLOZZ_ANNOT)) == null)
+			return false;
+		
+		return importerGlozz(corpus, fichierCorpus, fichierAnnot);
+	}
+	
+	
+	private static boolean importer(File fichierCorpus, File fichierAnnot, Corpus corpus) {
+		BufferedReader text = null;
+		BufferedInputStream annot = null;
+		try {
+			text = new BufferedReader(new InputStreamReader(new FileInputStream(fichierCorpus), "UTF-8"));
+			annot = new BufferedInputStream(new FileInputStream(fichierAnnot));
+			corpus.setTexte(text.readLine());
+			SAXParserFactory pf = SAXParserFactory.newInstance();
+			SAXParser sp = pf.newSAXParser();
+			sp.parse(annot, new GlozzHandler(fichierAnnot, corpus));
+		}
+		catch (IOException ex) {
+			corpus.fermer();
+			JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		}
+		catch (ParserConfigurationException ex) {
+			corpus.fermer();
+			JOptionPane.showMessageDialog(null, ex, "Erreur de format de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		}
+		catch (SAXException ex) {
+			corpus.fermer();
+			JOptionPane.showMessageDialog(null, ex, "Erreur de format de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		}
+		finally {
+			try {
+				if (text != null) text.close();
+				if (annot != null) annot.close();
+			}
+			catch (IOException ex) {
+				JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture du fichier lu", JOptionPane.ERROR_MESSAGE);
+			}
+		}
+		return true;
+	}
+	
+	public static boolean importerModeleGlozz(Corpus corpus, File fichierModele) {
+		BufferedInputStream modele = null;
+		
+		try {
+			modele = new BufferedInputStream(new FileInputStream(fichierModele));
+			SAXParserFactory pf = SAXParserFactory.newInstance();
+			SAXParser sp = pf.newSAXParser();
+			Structure structureLue = new Structure();
+			sp.parse(modele, new ModeleGlozzHandler(fichierModele, structureLue));
+			corpus.fusionnerStructureLue(structureLue);
+			corpus.newCorpusLu();
+		}
+		catch (IOException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		}
+		catch (ParserConfigurationException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur de format de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		}
+		catch (SAXException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur de format de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		}
+		finally {
+			try {
+				if (modele != null) modele.close();
+			}
+			catch (IOException ex) {
+				JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture du fichier lu", JOptionPane.ERROR_MESSAGE);
+			}
+		}
+		return true;
+	}
+	
+	public static boolean importerModeleGlozz(Corpus corpus) {
+		File fichierModele;
+		if ((fichierModele = Fichiers.choisirFichier(Commande.OUVRIR,
+				"Choix du fichier modèle", Fichiers.TypeFichier.GLOZZ_MODELE)) == null)
+			return false;
+		
+		return importerModeleGlozz(corpus, fichierModele);
+	}
+	
+	public static boolean exporterGlozz(Corpus corpus) {
+		PrintWriter text = null;
+		PrintWriter annot = null;
+		PrintWriter model = null;
+		File fichierCorpus;
+		File fichierAnnot;
+		File fichierModel;
+		if ((fichierCorpus = Fichiers.choisirFichier(Commande.ENREGISTRER,
+				"Nom du fichier corpus", Fichiers.TypeFichier.GLOZZ_CORPUS)) == null) return false;
+		if ((fichierAnnot = Fichiers.choisirFichier(Commande.ENREGISTRER,
+				"Nom du fichier annotations", Fichiers.TypeFichier.GLOZZ_ANNOT)) == null)
+			return false;
+		try {
+			text = new PrintWriter(fichierCorpus, "UTF-8");
+			annot = new PrintWriter(fichierAnnot, "UTF-8");
+			text.print(corpus.getTexte());
+			GlozzPrinter gp = new GlozzPrinter(corpus, annot);
+			gp.ecrireAnnot();
+		}
+		catch (FileNotFoundException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		}
+		catch (UnsupportedEncodingException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		}
+		finally {
+			if (text != null) text.close();
+			if (annot != null) annot.close();
+		}
+		if ((fichierModel = Fichiers.choisirFichier(Commande.ENREGISTRER,
+				"Exporter aussi le modèle ?", Fichiers.TypeFichier.GLOZZ_MODELE)) == null)
+			return true;
+		try {
+			model = new PrintWriter(fichierModel, "UTF-8");
+			ModelGlozzPrinter gp = new ModelGlozzPrinter(corpus.getStructure(), model);
+			gp.ecrireModel();
+		}
+		catch (FileNotFoundException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+		}
+		catch (UnsupportedEncodingException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+		}
+		finally {
+			if (model != null) model.close();
+		}
+		return true;
+	}
+	
+	public static boolean exporterModeleGlozz(Structure structure) {
+		PrintWriter model = null;
+		File fichierModel;
+		if ((fichierModel = Fichiers.choisirFichier(Commande.ENREGISTRER,
+				"Nom du fichier modèle ?", Fichiers.TypeFichier.GLOZZ_MODELE)) == null)
+			return false;
+		try {
+			model = new PrintWriter(fichierModel, "UTF-8");
+			ModelGlozzPrinter gp = new ModelGlozzPrinter(structure, model);
+			gp.ecrireModel();
+		}
+		catch (Exception ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		}
+		finally {
+			if (model != null) model.close();
+		}
+		return true;
+	}
+	
+	static class GlozzHandler extends DefaultHandler {
+		
+		Corpus corpus;
+		
+		Balise etatCourant = null;
+		
+		Element elementCourant = null;
+		
+		String champCourant = null;
+		
+		String valCourant = null;
+		
+		HashMap<String, Element> elements = new HashMap<>();
+		
+		ArrayList<Relation> relations = new ArrayList<>();
+		
+		HashMap<Relation, ArrayList<String>> idTermes = new HashMap<>();
+		
+		ArrayList<Schema> schemas = new ArrayList<>();
+		
+		HashMap<Schema, ArrayList<String>> idContenus = new HashMap<>();
+		
+		File parsedFile;
+		
+		enum Balise {
+			ANNOTATIONS, UNIT, RELATION, SCHEMA, METADATA, AUTHOR, CREATIONDATE, LASTMODIFIER, LASTMODIFICATIONDATE, CHARACTERISATION, TYPE, FEATURESET, FEATURE, POSITIONING, START, END, SINGLEPOSITION, TERM, EMBEDDEDUNIT, EMBEDDEDRELATION, EMBEDDEDSCHEMA, FLAG, COMMENT
+			// , POSSIBLEVALUES, VALUE
+		};
+		
+		Balise balise(String nomBalise) {
+			String s = nomBalise.replaceAll("\\W", "").toUpperCase();
+			try {
+				return Balise.valueOf(s);
+			}
+			catch (java.lang.IllegalArgumentException e) {
+				System.out.println("Error: unknown tag '" + nomBalise + "' in " + parsedFile);
+				throw e;
+			}
+		}
+		
+		GlozzHandler(File parsedFile, Corpus corpus) {
+			super();
+			this.corpus = corpus;
+			this.parsedFile = parsedFile;
+		}
+		
+		@Override
+		public void startDocument() {
+			corpus.clearAnnot();
+		}
+		
+		@Override
+		public void endDocument() throws SAXNotSupportedException {
+			for (Relation rel : relations) {
+				ArrayList<String> idterms = idTermes.get(rel);
+				if (idterms.size() != 2) {
+					throw new SAXNotSupportedException("Une relation de type " + rel.getType() + " n'a pas deux termes");
+				}
+				if (elements.get(idterms.get(0)) == null) {
+					throw new SAXNotSupportedException("Terme inconnu id = " + idterms.get(0)
+							+ " pour une relation de type " + rel.getType());
+				}
+				rel.setElt1(elements.get(idterms.get(0)));
+				if (elements.get(idterms.get(1)) == null) {
+					throw new SAXNotSupportedException("Terme inconnu id = " + idterms.get(1)
+							+ " pour une relation de type " + rel.getType());
+				}
+				rel.setElt2(elements.get(idterms.get(1)));
+				corpus.addRelationLue(rel);
+			}
+			for (Schema sch : schemas) {
+				for (String id : idContenus.get(sch)) {
+					if (elements.get(id) == null) {
+						throw new SAXNotSupportedException("Contenu inconnu id = " + id
+								+ " pour un schéma de type " + sch.getType());
+					}
+					sch.ajouter(elements.get(id));
+				}
+				corpus.addSchemaLu(sch);
+			}
+			corpus.verifierFinParagraphesTypesUnites(new String[] {
+					"title", "subTitle", "sectionTitle", "subSectionTitle",
+					"subSubSectionTitle", "subSubSubSectionTitle", "quote", "listItem" });
+			corpus.trierFinParagraphes();
+			corpus.verifierFinParagrapheFinTexte();
+		}
+		
+		@Override
+		public void startElement(String uri, String local, String nomBalise, Attributes attributs) throws SAXException {
+			if (etatCourant == Balise.FLAG) return;
+			switch (balise(nomBalise)) {
+				case FLAG:
+					etatCourant = Balise.FLAG;
+					break;
+				case UNIT:
+					elementCourant = new Unite();
+					elements.put(attributs.getValue("id"), elementCourant);
+					break;
+				case RELATION:
+					elementCourant = new Relation();
+					elements.put(attributs.getValue("id"), elementCourant);
+					idTermes.put((Relation) elementCourant, new ArrayList<String>());
+					break;
+				case SCHEMA:
+					elementCourant = new Schema();
+					elements.put(attributs.getValue("id"), elementCourant);
+					idContenus.put((Schema) elementCourant, new ArrayList<String>());
+					break;
+				case TYPE:
+					etatCourant = Balise.TYPE;
+					valCourant = "";
+					break;
+				case FEATURE:
+					etatCourant = Balise.FEATURE;
+					champCourant = attributs.getValue("name");
+					valCourant = "";
+					break;
+				case START:
+					etatCourant = Balise.START;
+					break;
+				case END:
+					etatCourant = Balise.END;
+					break;
+				case SINGLEPOSITION:
+					if (elementCourant.getClass() != Unite.class) {
+						throw new SAXNotSupportedException("La balise singlePosition ne peut être utilisée que pour des unités");
+					}
+					if (elementCourant.getType().equals("paragraph")) {
+						if (etatCourant == Balise.END) {
+							corpus.addFinParagraphe(Integer.parseInt(attributs.getValue("index")));
+						}
+					}
+					else {
+						switch (etatCourant) {
+							case START:
+								((Unite) elementCourant).setDeb(Integer.parseInt(attributs.getValue("index")));
+								break;
+							case END:
+								((Unite) elementCourant).setFin(Integer.parseInt(attributs.getValue("index")));
+								break;
+						}
+					}
+					break;
+				case TERM:
+					if (elementCourant.getClass() != Relation.class)
+						throw new SAXNotSupportedException("La balise term ne peut être utilisée que pour des relations");
+					idTermes.get(elementCourant).add(attributs.getValue("id"));
+					break;
+				
+				case EMBEDDEDUNIT:
+				case EMBEDDEDRELATION:
+				case EMBEDDEDSCHEMA:
+					if (elementCourant.getClass() != Schema.class)
+						throw new SAXNotSupportedException(
+								"Les balises embedded ne peuvent être utilisées que pour des schémas");
+					idContenus.get(elementCourant).add(attributs.getValue("id"));
+					break;
+				default:
+					// System.out.println("Warning: not supported '" + nomBalise + "' tag while parsing file: " + parsedFile);
+			}
+		}
+		
+		@Override
+		public void endElement(String uri, String local, String nomBalise) throws SAXException {
+			if (etatCourant == Balise.FLAG) {
+				if (balise(nomBalise) == Balise.FLAG) etatCourant = null;
+				return;
+			}
+			String type = "";
+			switch (balise(nomBalise)) {
+				case UNIT:
+					type = elementCourant.getType();
+					if (type == null || type.isEmpty())
+						throw new SAXNotSupportedException("Pas trouvé de type pour cette unité");
+					if (!type.equals("paragraph")) {
+						corpus.addUniteLue((Unite) elementCourant);
+						elementCourant = null;
+					}
+					break;
+				case RELATION:
+					type = elementCourant.getType();
+					if (type == null || type.isEmpty())
+						throw new SAXNotSupportedException("Pas trouvé de type pour cette relation");
+					relations.add((Relation) elementCourant);
+					elementCourant = null;
+					break;
+				case SCHEMA:
+					type = elementCourant.getType();
+					if (type == null || type.isEmpty())
+						throw new SAXNotSupportedException("Pas trouvé de type pour ce shéma");
+					schemas.add((Schema) elementCourant);
+					elementCourant = null;
+					break;
+				case TYPE:
+					elementCourant.setType(valCourant);
+					valCourant = null;
+					etatCourant = null;
+					break;
+				case FEATURE:
+					elementCourant.putProp(champCourant, valCourant);
+					etatCourant = null;
+					champCourant = null;
+					valCourant = null;
+					break;
+				case START:
+					etatCourant = null;
+					break;
+				case END:
+					etatCourant = null;
+					break;
+				default:
+					// System.out.println("Warning: not supported '" + nomBalise + "' tag while parsing: " + parsedFile);
+			}
+		}
+		
+		@Override
+		public void characters(char[] ch, int start, int taille) throws SAXException {
+			if (etatCourant == null || !EnumSet.of(Balise.TYPE, Balise.FEATURE).contains(etatCourant)) {
+				return;
+			}
+			valCourant += new String(ch, start, taille);
+		}
+	}
+	
+	static class ModeleGlozzHandler extends DefaultHandler {
+		
+		Structure structure;
+		
+		boolean listeValeurs = false;
+		
+		Class<? extends Element> classeCourante = Unite.class;  // par défaut : balise <units> sous-entendue
+		
+		String typeCourant = null;
+		
+		String champCourant = null;
+		
+		String valeurCourante = null;
+		
+		File parsedFile;
+		
+		public enum Balise {
+			ANNOTATIONMODEL, UNITS, RELATIONS, SCHEMAS, TYPE, FEATURESET, FEATURE, POSSIBLEVALUES, VALUE
+		};
+		
+		static Balise balise(String nomBalise) throws SAXNotRecognizedException {
+			try {
+				return Balise.valueOf(nomBalise.replaceAll("\\W", "").toUpperCase());
+			}
+			catch (Exception e) {
+				throw new SAXNotRecognizedException("Balise non reconnue : " + nomBalise);
+			}
+		}
+		
+		ModeleGlozzHandler(File parsedFile, Structure structure) {
+			super();
+			this.structure = structure;
+			this.parsedFile = parsedFile;
+		}
+		
+		@Override
+		public void startDocument() {}
+		
+		@Override
+		public void endDocument() throws SAXNotSupportedException {}
+		
+		@Override
+		public void startElement(String uri, String local, String nomBalise, Attributes attributs) throws SAXException {
+			String valdef = null;
+			switch (balise(nomBalise)) {
+				case UNITS:
+					classeCourante = Unite.class;
+					break;
+				case RELATIONS:
+					classeCourante = Relation.class;
+					break;
+				case SCHEMAS:
+					classeCourante = Schema.class;
+					break;
+				case TYPE:
+					typeCourant = attributs.getValue("name");
+					if (typeCourant == null || typeCourant.isEmpty())
+						throw new SAXNotSupportedException("Nom de type absent");
+					structure.ajouterType(classeCourante, typeCourant);
+					break;
+				case FEATURE:
+					if (typeCourant == null || typeCourant.isEmpty())
+						throw new SAXNotSupportedException("Nom de type absent");
+					champCourant = attributs.getValue("name");
+					if (champCourant == null || champCourant.isEmpty())
+						throw new SAXNotSupportedException("Nom de type absent");
+					structure.ajouterProp(classeCourante, typeCourant, champCourant);
+					break;
+				case POSSIBLEVALUES:
+					if (typeCourant == null || typeCourant.isEmpty() || champCourant == null || champCourant.isEmpty())
+						throw new SAXNotSupportedException("Nom de type ou de feature absent");
+					listeValeurs = true;
+					valdef = attributs.getValue("default");
+					if (valdef != null && !valdef.isEmpty())
+						structure.modifierValParDefaut(classeCourante, typeCourant, champCourant, valdef);
+					break;
+				case VALUE:
+					if (listeValeurs) valeurCourante = "";
+					valdef = attributs.getValue("default");
+					if (valdef != null && !valdef.isEmpty()) {
+						if (typeCourant == null || typeCourant.isEmpty() || champCourant == null || champCourant.isEmpty())
+							throw new SAXNotSupportedException("Nom de type ou de feature absent");
+						structure.ajouterVal(classeCourante, typeCourant, champCourant, valdef);
+						structure.modifierValParDefaut(classeCourante, typeCourant, champCourant, valdef);
+					}
+					break;
+				default:
+					// System.out.println("Warning: not supported '" + nomBalise + "' tag while parsing file: " + parsedFile);
+			}
+		}
+		
+		@Override
+		public void endElement(String uri, String local, String nomBalise) throws SAXException {
+			switch (balise(nomBalise)) {
+				case POSSIBLEVALUES:
+					listeValeurs = false;
+					break;
+				case VALUE:
+					if (listeValeurs && valeurCourante != null && !valeurCourante.isEmpty())
+						structure.ajouterVal(classeCourante, typeCourant, champCourant, valeurCourante);
+					break;
+				default:
+					// System.out.println("Warning: not supported '" + nomBalise + "' tag while parsing file: " + parsedFile);
+			}
+		}
+		
+		@Override
+		public void characters(char[] ch, int start, int taille) throws SAXException {
+			if (listeValeurs) {
+				valeurCourante += new String(ch, start, taille);
+			}
+		}
+	}
+	
+	static class GlozzPrinter {
+		
+		Corpus corpus;
+		
+		PrintWriter annot;
+		
+		HashMap<Element, String> idDates = new HashMap<>();
+		
+		String idAuteur = "analec0.2";
+		
+		String idDateParagraphes = "0";
+		
+		String idParagraphes = idAuteur + "_" + idDateParagraphes;
+		
+		GlozzPrinter(Corpus corpus, PrintWriter annot) {
+			this.corpus = corpus;
+			this.annot = annot;
+			attribueIdDates();
+		}
+		
+		void attribueIdDates() {
+			long idDate = (new Date()).getTime();
+			for (Unite unite : corpus.getToutesUnites()) {
+				idDates.put(unite, Long.toString(idDate++));
+			}
+			for (Relation relation : corpus.getToutesRelations()) {
+				idDates.put(relation, Long.toString(idDate++));
+			}
+			for (Schema schema : corpus.getTousSchemas()) {
+				idDates.put(schema, Long.toString(idDate++));
+			}
+		}
+		
+		String getId(Element elt) {
+			return idAuteur + "_" + idDates.get(elt);
+		}
+		
+		void ecrireAnnot() {
+			annot.println("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
+			annot.println("<annotations>");
+			ecrireFinParagraphes();
+			ecrireUnites();
+			ecrireRelations();
+			ecrireSchemas();
+			annot.println("</annotations>");
+		}
+		
+		private void ecrireFinParagraphes() {
+			int deb = 0;
+			for (int fin : corpus.getFinParagraphes()) {
+				ecrireUnite("paragraph", idAuteur, idDateParagraphes, idParagraphes, new HashMap<String, String>(), deb, fin);
+				deb = fin;
+			}
+		}
+		
+		private void ecrireUnites() {
+			for (Unite unit : corpus.getToutesUnites()) {
+				ecrireUnite(unit.getType(), idAuteur, idDates.get(unit), getId(unit), unit.getProps(), unit.getDeb(), unit.getFin());
+			}
+		}
+		
+		private void ecrireRelations() {
+			for (Relation rel : corpus.getToutesRelations()) {
+				ecrireRelation(rel.getType(), idAuteur, idDates.get(rel), getId(rel), rel.getProps(), rel.getElt1(), rel.getElt2());
+			}
+		}
+		
+		private void ecrireSchemas() {
+			for (Schema sch : corpus.getTousSchemas()) {
+				ecrireSchema(sch.getType(), idAuteur, idDates.get(sch), getId(sch), sch.getProps(), sch.getContenu());
+			}
+		}
+		
+		private void ecrireUnite(String type, String idAuteur, String idDate, String id, HashMap<String, String> props, int deb, int fin) {
+			annot.println("<unit id=\"" + id + "\">");
+			ecrireMetadata(idAuteur, idDate);
+			ecrireProps(type, props);
+			ecrirePos(deb, fin);
+			annot.println("</unit>");
+		}
+		
+		private void ecrireRelation(String type, String idAuteur, String idDate, String id, HashMap<String, String> props, Element elt1, Element elt2) {
+			annot.println("<relation id=\"" + id + "\">");
+			ecrireMetadata(idAuteur, idDate);
+			ecrireProps(type, props);
+			ecrireRel(elt1, elt2);
+			annot.println("</relation>");
+		}
+		
+		private void ecrireSchema(String type, String idAuteur, String idDate, String id, HashMap<String, String> props, HashSet<Element> elts) {
+			annot.println("<schema id=\"" + id + "\">");
+			ecrireMetadata(idAuteur, idDate);
+			ecrireProps(type, props);
+			ecrireSch(elts);
+			annot.println("</schema>");
+		}
+		
+		private void ecrireMetadata(String idAuteur, String id) {
+			annot.println("<metadata>");
+			annot.println("<author>" + idAuteur + "</author>");
+			annot.println("<creation-date>" + id + "</creation-date>");
+			annot.println("</metadata>");
+		}
+		
+		private void ecrireProps(String type, HashMap<String, String> props) {
+			annot.println("<characterisation>");
+			annot.println("<type>" + encodeXMLTexte(type) + "</type>");
+			if (props.isEmpty()) {
+				annot.println("<featureSet/>");
+			}
+			else {
+				annot.println("<featureSet>");
+				for (String prop : props.keySet()) {
+					if (props.get(prop) != null) {
+						annot.println("<feature name =\"" + encodeXMLTexte(prop) + "\">"
+								+ encodeXMLTexte(props.get(prop)) + "</feature>");
+					}
+				}
+				annot.println("</featureSet>");
+				
+			}
+			annot.println("</characterisation>");
+		}
+		
+		private void ecrirePos(int deb, int fin) {
+			annot.println("<positioning>");
+			annot.println("<start>");
+			annot.println("<singlePosition index = \"" + deb + "\"/>");
+			annot.println("</start>");
+			annot.println("<end>");
+			annot.println("<singlePosition index = \"" + fin + "\"/>");
+			annot.println("</end>");
+			annot.println("</positioning>");
+		}
+		
+		private void ecrireRel(Element elt1, Element elt2) {
+			annot.println("<positioning>");
+			annot.println("<term id = \"" + getId(elt1) + "\"/>");
+			annot.println("<term id = \"" + getId(elt2) + "\"/>");
+			annot.println("</positioning>");
+		}
+		
+		private void ecrireSch(HashSet<Element> elts) {
+			annot.println("<positioning>");
+			for (Element elt : elts) {
+				Class classe = elt.getClass();
+				if (classe == Unite.class) {
+					annot.print("<embedded-unit ");
+				}
+				if (classe == Relation.class) {
+					annot.print("<embedded-relation ");
+				}
+				if (classe == Schema.class) {
+					annot.print("<embedded-schema ");
+				}
+				annot.println("id = \"" + getId(elt) + "\"/>");
+			}
+			annot.println("</positioning>");
+		}
+	}
+	
+	public static class ModelGlozzPrinter {
+		
+		Structure structure;
+		
+		PrintWriter model;
+		
+		public ModelGlozzPrinter(Structure structure, PrintWriter model) {
+			this.structure = structure;
+			this.model = model;
+		}
+		
+		public void ecrireModel() {
+			model.println("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
+			model.println("<annotationModel>");
+			ecrireUnites();
+			ecrireRelations();
+			ecrireSchemas();
+			model.println("</annotationModel>");
+		}
+		
+		private void ecrireUnites() {
+			model.println("<units>");
+			for (String type : structure.getTypes(Unite.class))
+				ecrireType(Unite.class, type);
+			model.println("</units>");
+		}
+		
+		private void ecrireRelations() {
+			model.println("<relations>");
+			for (String type : structure.getTypes(Relation.class))
+				ecrireType(Relation.class, type);
+			model.println("</relations>");
+		}
+		
+		private void ecrireSchemas() {
+			model.println("<schemas>");
+			for (String type : structure.getTypes(Schema.class))
+				ecrireType(Schema.class, type);
+			model.println("</schemas>");
+		}
+		
+		private void ecrireType(Class<? extends Element> classe, String type) {
+			model.print("<type name=\"" + encodeXMLTexte(type) + "\"");
+			if (classe == Relation.class) model.print(" oriented=\"true\"");
+			model.println(">");
+			model.println("<featureSet>");
+			for (String prop : structure.getNomsProps(classe, type))
+				ecrireProp(classe, type, prop);
+			model.println("</featureSet>");
+			model.println("</type>");
+		}
+		
+		private void ecrireProp(Class<? extends Element> classe, String type, String prop) {
+			model.println("<feature name=\"" + encodeXMLTexte(prop) + "\">");
+			if (structure.getValeursProp(classe, type, prop).isEmpty()) {
+				model.println("<value type=\"free\" default=\"\" />");
+			}
+			else {
+				model.println("<possibleValues default = \""
+						+ structure.getValeurParDefaut(classe, type, prop) + "\">");
+				for (String val : structure.getValeursProp(classe, type, prop))
+					model.println("<value>" + encodeXMLTexte(val) + "</value>");
+				model.println("</possibleValues>");
+			}
+			model.println("</feature>");
+			
+		}
+	}
+	
+	static String encodeXMLTexte(String ch) {
+		// return ch;
+		return ch.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("\'", "&apos;");
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersGlozz.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersGraphique.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersGraphique.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersGraphique.java	(revision 3653)
@@ -0,0 +1,216 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+import java.awt.*;
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class FichiersGraphique {
+
+  public static class CercleColore {
+
+    public int cx, cy, r;
+    public Color couleur;
+  }
+
+  public static interface GraphiqueExport {
+
+    public Dimension initExport();
+
+    public Rectangle getCadre();
+
+    public CercleColore[] getCerclesColores();
+  }
+
+  public static void exporterGraphiqueSVG(GraphiqueExport donnees) {
+    PrintWriter sortie = null;
+    File fichierGraphique;
+    if ((fichierGraphique = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier ?", Fichiers.TypeFichier.GRAPHIQUE_SVG)) == null) return;
+    try {
+      sortie = new PrintWriter(fichierGraphique, "UTF-8");
+      ecrireSVG(sortie, donnees);
+    } catch (FileNotFoundException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier",
+              JOptionPane.ERROR_MESSAGE);
+    } catch (UnsupportedEncodingException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier",
+              JOptionPane.ERROR_MESSAGE);
+    } finally {
+      if (sortie != null) sortie.close();
+    }
+  }
+  
+   public static void exporterGChaineSVG(String fichier) {
+    PrintWriter sortie = null;
+    File fichierGraphique;
+    if ((fichierGraphique = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier ?", Fichiers.TypeFichier.GRAPHIQUE_SVG)) == null) return;
+    try {
+      sortie = new PrintWriter(fichierGraphique, "UTF-8");
+      sortie.println(fichier);
+    } catch (FileNotFoundException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier",
+              JOptionPane.ERROR_MESSAGE);
+    } catch (UnsupportedEncodingException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier",
+              JOptionPane.ERROR_MESSAGE);
+    } finally {
+      if (sortie != null) sortie.close();
+    }
+  }
+  
+
+  public static void ecrireSVG(PrintWriter sortie, GraphiqueExport donnees) {
+    sortie.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
+    sortie.println("<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"");
+    Dimension dim = donnees.initExport();
+    sortie.println("x=\"0px\" y=\"0px\" width=\"" + dim.width
+            + "px\" height=\"" + dim.height + "px\">");
+    Rectangle cadre = donnees.getCadre();
+    if (cadre != null)
+      sortie.println("<rect x=\"" + cadre.x + "\" y=\"" + cadre.y
+              + "\" fill=\"none\" stroke=\"#000000\" width=\"" + cadre.width
+              + "\" height=\"" + cadre.height + "\"/>");
+    CercleColore[] cercles = donnees.getCerclesColores();
+    for (CercleColore cercle : cercles)
+      sortie.println("<ellipse cx=\"" + cercle.cx + "\" cy=\""
+              + cercle.cy + "\" fill=\"" + ecritCouleurSVG(cercle.couleur)
+              + "\" stroke=\"#000000\" rx=\"" + cercle.r
+              + "\" ry=\"" + cercle.r + "\"/>");
+
+    sortie.println("</svg>");
+  }
+  
+
+  private static String ecritCouleurSVG(Color c) {
+    String res = "#";
+    res += Integer.toHexString(c.getRGB()).substring(2);
+    return res;
+  }
+
+  public static void exporterGraphiqueEMF(GraphiqueExport donnees) {
+    FileChannel canal = null;
+    FileOutputStream sortie = null;
+    File fichierGraphique;
+    if ((fichierGraphique = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier ?", Fichiers.TypeFichier.GRAPHIQUE_EMF)) == null) return;
+    try {
+      sortie = new FileOutputStream(fichierGraphique);
+      canal = sortie.getChannel();
+      ByteBuffer buff = ecrireEMF(donnees);
+      canal.write(buff);
+    } catch (IOException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier",
+              JOptionPane.ERROR_MESSAGE);
+    } finally {
+      if (canal != null)
+        try {
+          canal.close();
+        } catch (IOException ex) {
+          JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier",
+                  JOptionPane.ERROR_MESSAGE);
+        }
+      if (sortie != null)
+        try {
+          sortie.close();
+        } catch (IOException ex) {
+          JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier",
+                  JOptionPane.ERROR_MESSAGE);
+        }
+    }
+  }
+
+  private static ByteBuffer ecrireEMF(GraphiqueExport donnees) {
+    ArrayList<Integer> dessin = new ArrayList<Integer>();
+        Dimension dim = donnees.initExport();
+    int nbrecords = 0;
+    dessin.add(1); // header
+    dessin.add(88); // taille du header 
+    dessin.addAll(Arrays.asList(0, 0, dim.width, dim.height)); 
+                                                   // taille du graphique en px 
+    dessin.addAll(Arrays.asList(0, 0, dim.width*32, dim.height*32)); 
+                                                  // taille en 0.01 mm (px * 32)
+    dessin.add(0x464D4520); // signature (" EMF" à l'endroit!!) 
+    dessin.add(0x00010000); // version 
+    int indTailles = dessin.size();  // endroit où mettre les tailles 
+    dessin.addAll(Arrays.asList(0, 0)); // taille du fichier, nb records : remplis à la fin
+    dessin.add(2); // nbobjs : pen et brush
+    dessin.addAll(Arrays.asList(0, 0));   //taille et offset de la description
+    dessin.add(0); // nb d'entrees de palette 
+    dessin.addAll(Arrays.asList(1024, 768, 320, 240)); // taille du device en px et en mm
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x11, 0xC, 0x8));  // mapmode : 0x8 (anisotropique)
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x12, 0xC, 0x1));  // bkmode : 0x1 (transparent)
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0xA, 0x10, 0, 0));  // setWindowOrgEx: 0,0
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0xC, 0x10, 0, 0));  // setViewPortOrgEx: 0,0
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x9, 0x10, dim.width, dim.height));  // setWindowExtEx
+    nbrecords++; // setWindowExtEx: 0,0
+    dessin.addAll(Arrays.asList(0xB, 0x10, dim.width, dim.height));  // setViewPortExtEx
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x27, 0x18, 1, 1, 0, 0));  // createBrushIndirect : 
+    nbrecords++;                                        //1 (NoObj) 1 (BS_NULL) 0 0
+    dessin.addAll(Arrays.asList(0x25, 0xC, 1));  // selectObject 1
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x5F, 0x34, 2, 0, 0, 0, 0, 0x12200, 0x4, 0, 0, 0, 0));
+    // extCreatePen : 2 (NoObj) 0 0 0 0 (absence de DIB) 
+    // 0x12200 (PS_GEOMETRIC, JOIN_MITER, ENDCAP_FLAT) 
+    // 0x4 (largeur) 0 (BS_NULL) 0 (Color) 0 (BrushHatch) 0 (numStyleEntries)     
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x25, 0xC, 2));  // selectObject 2
+    nbrecords++;
+      Rectangle cadre = donnees.getCadre();
+    if (cadre != null) {
+  
+    dessin.addAll(Arrays.asList(0x2B, 0x18, cadre.x, cadre.y, 
+            cadre.x+cadre.width, cadre.y+cadre.height));  //  Rectangle
+    nbrecords++;
+    }
+ CercleColore[] cercles = donnees.getCerclesColores();
+   for (CercleColore cercle : cercles) {
+//      sortie.println("<ellipse cx=\"" + cercle.cx + "\" cy=\""
+//              + cercle.cy + "\" fill=\"" + ecritCouleurSVG(cercle.couleur)
+//              + "\" stroke=\"#000000\" rx=\"" + cercle.r
+//              + "\" ry=\"" + cercle.r + "\"/>");
+    dessin.addAll(Arrays.asList(0x28, 0xC, 1));  // deleteObject 1
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x27, 0x18, 1, 0, ecritCouleurEMF(cercle.couleur), 0));  
+    nbrecords++;      // createBrushIndirect : 1 (NoObj) 0 (BS_SOLID) Color (0BGR) 0
+    dessin.addAll(Arrays.asList(0x25, 0xC, 1));  // selectObject 1
+    nbrecords++;
+    dessin.addAll(Arrays.asList(0x2A, 0x18, cercle.cx-cercle.r, cercle.cy-cercle.r,
+            cercle.cx+cercle.r, cercle.cy+cercle.r));  //  Ellipse
+    nbrecords++;
+   }
+    dessin.addAll(Arrays.asList(0xE, 0x14, 0, 0, 0x14));  //  EOF 0xE 
+    nbrecords++;                                      //+ taille (20?) et offset palette
+    dessin.set(indTailles++, dessin.size() * 4);
+    dessin.set(indTailles, nbrecords);
+    ByteBuffer buff = ByteBuffer.allocate(dessin.size() * 4).order(ByteOrder.LITTLE_ENDIAN);
+    buff.clear();
+    for (int n : dessin) buff.putInt(n);
+    buff.flip();
+    return buff;
+  }
+    private static int ecritCouleurEMF(Color c) {
+    return c.getRed() | (c.getGreen()<<8) | (c.getBlue()<<16);
+  }
+
+
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersGraphique.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersCoNLL.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersCoNLL.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersCoNLL.java	(revision 3653)
@@ -0,0 +1,212 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+
+/**
+ *
+ * @author Bernard Victorri
+ */
+public abstract class FichiersCoNLL {
+  static final String TYPE_UNITES = "Token";
+  static final String TYPE_RELATION = "Dependency";
+  static final String TYPE_RELATION_PROJ = "Projective Dependency";
+  static final String PROP_LEMME = "Lemma";
+  static final String PROP_C_POS = "C-POS";
+  static final String PROP_POS = "POS";
+  static final String PROP_TRAITS = "Features";
+  static final String PROP_REL = "Function";
+  public static void importerCoNLL(Corpus corpus) {
+    BufferedReader in = null;
+    File ficCoNLL;
+    GCodage codage = new GCodage();
+    if ((ficCoNLL = Fichiers.choisirFichier(Commande.OUVRIR,
+            "Choix du fichier CoNLL", TypeFichier.CONLL))==null)
+      return;
+    try {
+      in = new BufferedReader(new InputStreamReader(
+              new FileInputStream(ficCoNLL), "UTF-8"));
+      CoNLLParser parseur = new CoNLLParser(corpus);
+      parseur.parser(in);
+      corpus.newCorpusLu();
+    } catch (IOException ex) {
+      corpus.fermer();
+      JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } finally {
+      try {
+        if (in!=null) in.close();
+      } catch (IOException ex) {
+        JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture du fichier lu", JOptionPane.ERROR_MESSAGE);
+      }
+    }
+  }
+
+  static class CoNLLParser {
+    private Corpus corpus;
+    private String texte="";
+    private ArrayList<String> noHeads = new ArrayList<String>();
+    private ArrayList<String> depRels = new ArrayList<String>();
+    private ArrayList<String> noPHeads = new ArrayList<String>();
+    private ArrayList<String> pDepRels = new ArrayList<String>();
+    private ArrayList<Unite> units = new ArrayList<Unite>();
+    private HashMap<String, Integer> noTokenUnits = new HashMap<String, Integer>();
+    CoNLLParser(Corpus corpus) {
+      this.corpus = corpus;
+    }
+    private void parser(BufferedReader in) throws IOException {
+      String ligne;
+      int noligne = 0;
+      while (true) {
+        ligne = in.readLine();
+        if (ligne==null) {
+          finDocument(noligne);
+          break;
+        }
+        noligne++;
+        if (ligne.trim().isEmpty()) finPhrase(noligne);
+        else parserToken(ligne, noligne);
+      }
+    }
+    private void parserToken(String ligne, int noligne) throws IOException {
+      String ch;
+      String[] items = ligne.split("\\t");
+      if (items.length!=10)
+        throw new CoNLLException("Nombre de colonnes incorrect ("
+                +items.length+")", noligne);
+      Unite unit = new Unite();
+      unit.setType(TYPE_UNITES);
+      units.add(unit);
+      // champ ID
+      ch = items[0].replace('_', ' ').trim();
+      if (ch.isEmpty())
+        throw new CoNLLException("Pas trouvé de numéro de token", noligne);
+      noTokenUnits.put(ch, units.size()-1);
+      // champ FORM
+      ch = items[1].replace('_', ' ').trim();
+      if (ch.isEmpty())
+        throw new CoNLLException("Pas trouvé de token", noligne);
+      if (isPonct1(ch)) texte = texte.trim();
+      unit.setDeb(texte.length());
+      texte += ch;
+      unit.setFin(texte.length());
+      if (!isPonct2(ch)) texte += " ";
+      // champ LEMMA    
+      ch = items[2].replace('_', ' ').trim();
+      if (!ch.isEmpty())
+        unit.putProp(PROP_LEMME, ch);
+      // champ CPOSTAG
+      ch = items[3].replace('_', ' ').trim();
+      if (ch.isEmpty())
+        throw new CoNLLException("Pas trouvé de C-POS", noligne);
+      unit.putProp(PROP_C_POS, ch);
+      // champ POSTAG
+      ch = items[4].replace('_', ' ').trim();
+      if (ch.isEmpty())
+        throw new CoNLLException("Pas trouvé de POS", noligne);
+      unit.putProp(PROP_POS, ch);
+      // champ FEATS
+      ch = items[5].replace('_', ' ').trim();
+      if (!ch.isEmpty()) {
+        String[] chs = ch.split("\\|");
+        String traits = "";
+        for (String trait : chs) {
+          String[] attval = trait.split("=");
+          if (attval.length==2)
+            unit.putProp(attval[0].trim(), attval[1].trim());
+          else {
+            if (!traits.isEmpty()) traits += '|';
+            traits += trait;
+          }
+        }
+        if (!traits.isEmpty())
+          unit.putProp(PROP_TRAITS, traits);
+      }
+      // champ HEAD
+      ch = items[6].replace('_', ' ').trim();
+      if (ch.isEmpty())
+        throw new CoNLLException("Pas trouvé de HEAD", noligne);
+      noHeads.add(ch);
+      // champ DEPREL
+      ch = items[7].replace('_', ' ').trim();
+      if (ch.isEmpty())
+        throw new CoNLLException("Pas trouvé de DEP-REL", noligne);
+      depRels.add(ch);
+      // champ PHEAD
+      ch = items[8].replace('_', ' ').trim();
+      noPHeads.add(ch);
+      // champ PDEPREL
+      ch = items[9].replace('_', ' ').trim();
+      pDepRels.add(ch);
+    }
+    static private boolean isPonct1(String ch) {
+      if (ch.length()!=1) return false;
+      return ".,;:)]}!?'".contains(ch);
+    }
+    static private boolean isPonct2(String ch) {
+      if (ch.length()!=1) return false;
+      return "([{'".contains(ch);
+    }
+    private void finPhrase(int noligne) throws CoNLLException {
+      for (Unite unit : units) corpus.addUniteLue(unit);
+      for (int i = 0; i<units.size(); i++) {
+        Unite unit = units.get(i);
+        String nohead = noHeads.get(i);
+        String deprel = depRels.get(i);
+        if (!nohead.equals("0")) {
+          Integer k = noTokenUnits.get(nohead);
+          if (k==null)
+            throw new CoNLLException("Erreur de numéro de token de HEAD : "
+                    +nohead+" sur l'une des lignes précédentes", noligne);
+          Relation rel = new Relation(TYPE_RELATION, units.get(i), units.get(k));
+          if (deprel.isEmpty())
+            throw new CoNLLException("Pas trouvé de DEP-REL"
+                    +" sur l'une des lignes précédentes", noligne);
+          rel.putProp(PROP_REL, deprel);
+          corpus.addRelationLue(rel);
+          nohead = noPHeads.get(i);
+          deprel = pDepRels.get(i);
+          if (!nohead.isEmpty()&&!nohead.equals("0")) {
+            k = noTokenUnits.get(nohead);
+            if (k==null)
+              throw new CoNLLException("Erreur de numéro de token de P-HEAD : "
+                      +nohead+" sur l'une des lignes précédentes", noligne);
+            rel = new Relation(TYPE_RELATION_PROJ, units.get(i), units.get(k));
+            if (deprel.isEmpty())
+              throw new CoNLLException("Pas trouvé de P-DEP-REL"
+                      +" sur l'une des lignes précédentes", noligne);
+            rel.putProp(PROP_REL, deprel);
+            corpus.addRelationLue(rel);
+          }
+        }
+      }
+      units.clear();
+      noTokenUnits.clear();
+      noHeads.clear();
+      depRels.clear();
+      noPHeads.clear();
+      pDepRels.clear();
+    }
+    private void finDocument(int noligne) throws IOException {
+      finPhrase(noligne);
+      texte = texte.trim();
+      corpus.setTexte(texte);
+      corpus.addFinParagraphe(texte.length());
+    }
+
+    static class CoNLLException extends IOException {
+      public CoNLLException(String ex, int noligne) {
+        super("Erreur de syntaxe ligne "+noligne+" :\n"+ex);
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersCoNLL.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersTexte.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersTexte.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersTexte.java	(revision 3653)
@@ -0,0 +1,304 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+import java.awt.*;
+import java.io.*;
+import javax.swing.*;
+import javax.swing.text.*;
+import javax.swing.text.rtf.*;
+import visuAnalec.PanneauEditeur;
+import visuAnalec.donnees.*;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public abstract class FichiersTexte {
+  public static void importerTexte(Corpus corpus) {
+    BufferedReader fluxIn = null;
+    File fichier;
+    GCodage codage = new GCodage();
+    if ((fichier = Fichiers.choisirFichier(Commande.OUVRIR,
+            "Choix du corpus", Fichiers.TypeFichier.TEXTE, codage.getContenant())) == null) return;
+    String code = codage.getCode();
+    try {
+      fluxIn = new BufferedReader(new InputStreamReader(new FileInputStream(fichier), code));
+    } catch (UnsupportedEncodingException ex) {
+      JOptionPane.showMessageDialog(null, "Codage de caractères non pris en charge : " + code,
+              "Erreur d'ouverture de fichier texte", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (FileNotFoundException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'ouverture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    }
+    try {
+      corpus.lireTexte(fluxIn);
+    } catch (IOException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } finally {
+      try {
+        if (fluxIn != null) fluxIn.close();
+      } catch (IOException ex) {
+        JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier lu", JOptionPane.ERROR_MESSAGE);
+        return;
+      }
+    }
+  }
+  
+  /*ecrit simplement une chaine de caractère au dans un fichier csv*/
+     public static void exporterCSV(String fichier) {
+    PrintWriter sortie = null;
+    File fichierGraphique;
+    if ((fichierGraphique = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier ?", Fichiers.TypeFichier.DONNEES_CSV)) == null) return;
+    try {
+      sortie = new PrintWriter(fichierGraphique, "UTF-8");
+      sortie.println(fichier);
+    } catch (FileNotFoundException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier",
+              JOptionPane.ERROR_MESSAGE);
+    } catch (UnsupportedEncodingException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier",
+              JOptionPane.ERROR_MESSAGE);
+    } finally {
+      if (sortie != null) sortie.close();
+    }
+  }
+  
+  public static void exporterTexteRTF(PanneauEditeur pEditeur) {
+    FileOutputStream fluxOut = null;
+    FiltreCorrectionRTFOutputStream filtre = null;
+    File fichierCorpus;
+    if ((fichierCorpus = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier texte", Fichiers.TypeFichier.TEXTE_RTF)) == null) return;
+    try {
+      fluxOut = new FileOutputStream(fichierCorpus);
+      filtre = new FiltreCorrectionRTFOutputStream(fluxOut);
+      Document doc = pEditeur.getTexteFormate();
+      RTFEditorKit editeur = new RTFEditorKit();
+      editeur.write(filtre, doc, 0, doc.getLength());
+    } catch (FileNotFoundException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (UnsupportedEncodingException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (IOException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (BadLocationException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } finally {
+      if (fluxOut != null) try {
+          fluxOut.close();
+        } catch (IOException ex) {
+          JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier", JOptionPane.ERROR_MESSAGE);
+        }
+    }
+  }
+
+  private static class FiltreCorrectionRTFOutputStream extends FilterOutputStream {
+    // Note: Windows versions of Word have never supported \cbN, 
+    //but it can be emulated by the control word sequence 
+    // \chshdng0\chcbpatN.
+    private final static char[] CodeCouleurFondcorrect = "\\chshdng0\\chcbpat".toCharArray();
+    private final static char[] CodeUnicodecorrect = "\\'".toCharArray();
+    private int etat;
+    private int[] buffer;
+    private int pt = 0;
+    private FiltreCorrectionRTFOutputStream(OutputStream out) {
+      super(out);
+      pt = etat = 0;
+      buffer = new int[10];
+    }
+    @Override
+    public void write(int car) throws IOException {
+      switch (etat) {
+        case 0:
+          if (car == '\\') {
+            buffer[pt++] = car;
+            etat = 1;
+          } else out.write(car);
+          return;
+        case 1:
+          if (car == 'c') {  // debut d'une couleur de fond : etats 2, 3, 4
+            buffer[pt++] = car;
+            etat = 2;
+          } else if (car == 'u') {  // début d'un caractère unicode non décodé : etats 5, 6
+            buffer[pt++] = car;
+            etat = 5;
+          } else raz(car);
+          return;
+        case 2:
+          if (car == 'b') {
+            buffer[pt++] = car;
+            etat = 3;
+
+          } else raz(car);
+          return;
+        case 3:
+          if (car >= '0' && car <= '9') {
+            buffer[pt++] = car;
+            etat = 4;
+          } else raz(car);
+          return;
+        case 4:
+          if (car >= '0' && car <= '9') buffer[pt++] = car;
+          else correctionCouleurFond(car);
+          return;
+        case 5:
+          if (car >= '0' && car <= '9') {
+            buffer[pt++] = car;
+            etat = 6;
+          } else raz(car);
+          return;
+        case 6:
+          if (car >= '0' && car <= '9') buffer[pt++] = car;
+          else if (car == ' ') etat = 7;
+          else raz(car);
+          return;
+        case 7:
+          if (car == '?') correctionUnicode();
+          else raz(car);
+          return;
+        default:
+          throw new UnsupportedOperationException("Etat " + etat + " non prévu");
+      }
+    }
+    private void raz(int b) throws IOException {
+      for (int pt0 = 0; pt0 < pt; pt0++) out.write(buffer[pt0]);
+      pt = etat = 0;
+      write(b);
+    }
+    private void correctionCouleurFond(int b) throws IOException {
+      for (int c : CodeCouleurFondcorrect) out.write(c);
+      for (int pt0 = 3; pt0 < pt; pt0++) out.write(buffer[pt0]);
+      pt = etat = 0;
+      write(b);
+    }
+    private void correctionUnicode() throws IOException {
+      for (int c : CodeUnicodecorrect) out.write(c);
+      int n = 0;
+      for (int pt0 = 2; pt0 < pt; pt0++) n = 10 * n + (buffer[pt0] - '0');
+      String nhex = Integer.toHexString(n % 256);
+      if (nhex.length() == 1) out.write('0');
+      out.write(nhex.charAt(0));
+      if (nhex.length() == 2) out.write(nhex.charAt(1));
+      pt = etat = 0;
+    }
+  }
+  public static void exporterTexteHTML(PanneauEditeur pEditeur) {
+    FileWriter fluxOut = null;
+//   FiltreCorrectionRTFOutputStream filtre = null;
+    File fichierCorpus;
+    if ((fichierCorpus = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier texte", Fichiers.TypeFichier.TEXTE_HTML)) == null) return;
+    try {
+      fluxOut = new FileWriter(fichierCorpus);
+      Document doc = pEditeur.getTexteFormate();
+      HTMLWriterCorrige htmlWriter = new HTMLWriterCorrige(fluxOut, (StyledDocument) doc);
+      htmlWriter.write();
+    } catch (FileNotFoundException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (UnsupportedEncodingException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (IOException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (BadLocationException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'encodage de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } finally {
+      if (fluxOut != null)
+        try {
+          fluxOut.close();
+        } catch (IOException ex) {
+          JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier", JOptionPane.ERROR_MESSAGE);
+        }
+    }
+  }
+
+  private static class HTMLWriterCorrige extends AbstractWriter {
+    public HTMLWriterCorrige(Writer w, StyledDocument doc) {
+      super(w, doc);
+    }
+    @Override
+    protected void write() throws IOException, BadLocationException {
+      write("<html>\n");
+      ElementIterator it = getElementIterator();
+      Element elt;
+      it.first();  // le premier (la racine) n'a pas l'info intéressante)
+      if((elt = it.next()) != null) writeTagBody(elt.getAttributes());
+      while(elt!=null) {
+        if (elt.isLeaf()) {
+          writeSpan(elt.getAttributes(), getText(elt));
+        }
+        elt = it.next();
+      }       
+      write("</body>\n");
+      write("</html>\n");
+    }
+    private void writeTagBody(AttributeSet attr) throws IOException {
+      write("<body style=\" ");
+      write("font-family: " + StyleConstants.getFontFamily(attr));
+      write("; font-size: " + StyleConstants.getFontSize(attr) + "pt");
+      write("; font-style: " + (StyleConstants.isItalic(attr) ? "italic" : "normal"));
+      write("; font-weight: " + (StyleConstants.isBold(attr) ? "bold" : "normal"));
+      write("; text-decoration: " + (StyleConstants.isUnderline(attr) ? "underline" : "none"));
+      write("; color: ");
+      writeColor(StyleConstants.getForeground(attr));
+      write("; background-color: ");
+      writeColor(StyleConstants.getBackground(attr));
+      write("\">\n");
+    }
+    private void writeSpan(AttributeSet attr, String texte) throws IOException {
+      write("<span style=\" ");
+      write("; font-style: " + (StyleConstants.isItalic(attr) ? "italic" : ""));
+      write("; font-weight: " + (StyleConstants.isBold(attr) ? "bold" : ""));
+      write("; text-decoration: " + (StyleConstants.isUnderline(attr) ? "underline" : ""));
+      write("; color: ");
+      writeColor(StyleConstants.getForeground(attr));
+      write("; background-color: ");
+      writeColor(StyleConstants.getBackground(attr));
+      write("\">");
+      for(int i=0; i<texte.length(); i++) writeCar(texte.charAt(i));
+      write("</span>\n");
+    }
+    private void writeColor(Color couleur) throws IOException {
+      write('#');
+      String str = Integer.toHexString(couleur.getRed() % 256);
+      if (str.length() == 1) write('0');
+      write(str.charAt(0));
+      if (str.length() == 2) write(str.charAt(1));
+      str = Integer.toHexString(couleur.getGreen() % 256);
+      if (str.length() == 1) write('0');
+      write(str.charAt(0));
+      if (str.length() == 2) write(str.charAt(1));
+      str = Integer.toHexString(couleur.getBlue() % 256);
+      if (str.length() == 1) write('0');
+      write(str.charAt(0));
+      if (str.length() == 2) write(str.charAt(1));
+    }
+
+  private void writeCar(char car) throws IOException {
+    switch(car) {
+      case '\n': write("<p>"); return;
+      case '"': write("&quot;");return;
+      case'<': write("&lt;");return;
+      case'>': write("&gt;");return;
+      default:
+        if(car>128) write("&#"+(car%256)+";");
+        else write(car);
+    }   
+   }   
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersTexte.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersSyntex.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersSyntex.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersSyntex.java	(revision 3653)
@@ -0,0 +1,152 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class FichiersSyntex {
+  public static void importerSyntex(Corpus corpus) {
+    BufferedReader analyse = null;
+    File fichierCorpus;
+    GCodage codage = new GCodage();
+    if ((fichierCorpus = Fichiers.choisirFichier(Commande.OUVRIR, "Choix du fichier de résultats d'analyse syntaxique",
+            Fichiers.TypeFichier.SYNTEX, codage.getContenant())) == null) return;
+    String code = codage.getCode();
+    int cadence = 1; 
+    try {
+      analyse = new BufferedReader(new InputStreamReader(new FileInputStream(fichierCorpus), code));
+      SyntexParser sp = new SyntexParser(corpus);
+      sp.parser(analyse, cadence);
+      corpus.newCorpusLu();
+    } catch (IOException ex) {
+      corpus.fermer();
+      JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } finally {
+      try {
+        if (analyse != null) analyse.close();
+      } catch (IOException ex) {
+        JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture du fichier lu", JOptionPane.ERROR_MESSAGE);
+      }
+    }
+  }
+
+  static class SyntexParser {
+    Corpus corpus;
+    String texte;
+    SyntexParser(Corpus corpus) {
+      this.corpus = corpus;
+      texte = "";
+    }
+    private void parser(BufferedReader anasynt, int cadence) throws IOException {
+      String ligne;
+      int natLigne = 0;
+      int nophr = 0;
+      Schema phr = null;
+      String txt = null;
+      while ((ligne = anasynt.readLine()) != null) {
+        if (ligne.trim().isEmpty()) continue;
+        switch (natLigne) {
+          case 0:
+            phr = parserSEQ(ligne);
+            break;
+          case 1:
+            txt = parserTXT(ligne);
+            texte += txt;
+            corpus.addFinParagraphe(texte.length());
+            break;
+          case 2:
+            if (++nophr % cadence == 0) {
+              parserETIQ(ligne, phr, texte.length() - txt.length());
+            }
+            break;
+        }
+        natLigne = ++natLigne % 3;
+      }
+      if (natLigne > 0) throw new IOException("Fin de fichier prématurée");
+      corpus.setTexte(texte);
+    }
+    private Schema parserSEQ(String ligne) throws IOException {
+      if (!ligne.startsWith("<SEQ id=")) throw new IOException("SEQ attendu ligne :\n" + ligne);
+      Schema phr = new Schema("Phrase");
+      phr.putProp("id", ligne.substring(8, ligne.indexOf(';')));
+      return phr;
+    }
+    private String parserTXT(String ligne) throws IOException {
+      if (!ligne.startsWith("<TXT>")) throw new IOException("TXT attendu ligne :\n" + ligne);
+      return supBlancs(ligne.substring(5));
+    }
+    private String supBlancs(String txt) {
+      return txt.replaceAll("([\\'\\(\\-\\{\\[]) ", "$1").replaceAll(" ([\\.\\,\\-\\)\\%\\}\\]])", "$1");
+    }
+    private void parserETIQ(String ligne, Schema phr, int offset) throws IOException {
+      if (!ligne.startsWith("<ETIQ>")) throw new IOException("ETIQ attendu ligne :\n" + ligne);
+      String[] etiqs = ligne.substring(6).split("\t");
+      Unite[] units = new Unite[etiqs.length];
+      for (int i = 0; i < units.length; i++) units[i] = new Unite();
+      ArrayList<Relation> rels = new ArrayList<Relation>();
+      for (int i = 0; i < units.length; i++) {
+        String[] data = etiqs[i].split("\\|", -1);
+        if (data.length < 5) throw new IOException("Nombre de champs insuffisant pour " + etiqs[i]);
+        if (Integer.parseInt(data[3]) != i + 1) throw new IOException("Problème de numérotation pour " + etiqs[i]);
+        data[2] = supBlancs(data[2]);
+        while (texte.charAt(offset) == ' ') offset++;
+        if (!texte.startsWith(data[2], offset)) throw new IOException("Attendu : " + data[2] +
+                  " au début de la chaîne\n" + texte.substring(offset));
+        units[i].setType(typeSyntex(data[0]));
+        units[i].setDeb(offset);
+        units[i].setFin(offset += data[2].length());
+        units[i].putProp("Catégorie Syntex", data[0]);
+        units[i].putProp("Lemme", data[1]);
+        if (data[4].isEmpty()) continue;
+        String[] ascs = data[4].split(",");
+        for (String asc : ascs) {
+          String[] dataAsc = asc.split(";");
+          int noAsc = Integer.parseInt(dataAsc[1]);
+          if (noAsc <= 0 || noAsc > units.length)
+            throw new IOException("Problème de numérotation pour l'ascendant de " + etiqs[i]);
+          Relation rel = new Relation("Dépendance", units[i], units[noAsc - 1]);
+          rel.putProp("Fonction syntex", dataAsc[0]);
+          rels.add(rel);
+        }
+      }
+      for (Unite unit : units) {
+        corpus.addUniteLue(unit);
+        phr.ajouter(unit);
+      }
+      for (Relation rel : rels) {  
+        corpus.addRelationLue(rel);
+        phr.ajouter(rel);
+      }
+      corpus.addSchemaLu(phr);
+    }
+    private String typeSyntex(String catSyntex) throws IOException {
+      if (catSyntex.startsWith("Adj")) return "Adjectif";
+      if (catSyntex.startsWith("Adv")) return "Adverbe";
+      if (catSyntex.startsWith("CCoord") || catSyntex.startsWith("TypoCoord")) return "Coordonnant";
+      if (catSyntex.equals("CSub")) return "Subordonnant";
+      if (catSyntex.startsWith("Det")) return "Déterminant";
+      if (catSyntex.equals("Elim")) return "Interjection";
+      if (catSyntex.startsWith("Nom") || catSyntex.equals("NUM")) return "Nom";
+      if (catSyntex.startsWith("Pp") || catSyntex.startsWith("V")) return "Verbe";
+      if (catSyntex.startsWith("Prep")) return "Préposition";
+      if (catSyntex.equals("Pro")) return "Pronom";
+      if (catSyntex.equals("ProRel")) return "Relatif";
+      if (catSyntex.equals("Typo")) return "Ponctuation";
+      throw new IOException("Catégorie syntex non reconnue : " + catSyntex);
+    }
+  }
+}
+  

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersSyntex.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersTableur.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersTableur.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersTableur.java	(revision 3653)
@@ -0,0 +1,165 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.table.TableModel;
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.texte.PanneauOccurrences;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class FichiersTableur {
+  public static void importerExcel(Corpus corpus) {
+    BufferedReader enonces = null;
+    BufferedReader annot = null;
+    File fichierCorpus;
+    File fichierAnnot;
+    if ((fichierCorpus = Fichiers.choisirFichier(Commande.OUVRIR,
+            "Choix du fichier des énoncés", Fichiers.TypeFichier.TABLEUR_ENONCES))==null)
+      return;
+    if ((fichierAnnot = Fichiers.choisirFichier(Commande.OUVRIR,
+            "Choix du fichier des annotations", Fichiers.TypeFichier.TABLEUR_ANNOT))==null)
+      return;
+    try {
+      enonces = new BufferedReader(new InputStreamReader(new FileInputStream(fichierCorpus), "ISO-8859-1"));
+      annot = new BufferedReader(new InputStreamReader(new FileInputStream(fichierAnnot), "ISO-8859-1"));
+      ExcelParser ep = new ExcelParser(corpus);
+      corpus.setTexte(ep.parserEnonces(enonces, 2));
+      ep.parserAnnot(annot, 2, "<*", "*>");
+      corpus.newCorpusLu();
+    } catch (IOException ex) {
+      corpus.fermer();
+      GMessages.impossibiliteAction("Erreur de lecture de fichier : \n"
+              +ex.getLocalizedMessage());
+      return;
+    } finally {
+      try {
+        if (enonces!=null) enonces.close();
+        if (annot!=null) annot.close();
+      } catch (IOException ex) {
+        GMessages.impossibiliteAction("Erreur de fermeture du fichier lu : \n"
+                +ex.getLocalizedMessage());
+      }
+    }
+  }
+  public static void exporterTable(TableModel donnees) {
+    PrintWriter ecrittableur = null;
+    File fichierStats;
+    GCodage codage = new GCodage();
+    if ((fichierStats = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier ?", Fichiers.TypeFichier.TABLEUR_STATS,
+            codage.getContenant()))==null) return;
+    String code = codage.getCode();
+    try {
+      ecrittableur = new PrintWriter(fichierStats, code);
+      ecrireTable(ecrittableur, donnees);
+    } catch (FileNotFoundException ex) {
+      GMessages.impossibiliteAction("Erreur d'écriture de fichier : \n"
+              +"Codage de caractères non pris en charge : "+code);
+    } catch (UnsupportedEncodingException ex) {
+    } finally {
+      if (ecrittableur!=null) ecrittableur.close();
+    }
+  }
+  private static void ecrireTable(PrintWriter ecrittableur, TableModel donnees) {
+    int nbcol = donnees.getColumnCount();
+    for (int j = 0; j<nbcol; j++) {
+      ecrittableur.print(donnees.getColumnName(j));
+      ecrittableur.print(j==nbcol-1 ? '\n' : '\t');
+    }
+    int nblig = donnees.getRowCount();
+    for (int i = 0; i<nblig; i++) for (int j = 0; j<nbcol; j++) {
+        ecrittableur.print(donnees.getValueAt(i, j));
+        ecrittableur.print(j==nbcol-1 ? '\n' : '\t');
+      }
+
+  }
+
+  static class ExcelParser {
+    Corpus corpus;
+    HashMap<String, Unite> enonces;
+    ExcelParser(Corpus corpus) {
+      this.corpus = corpus;
+      this.enonces = new HashMap<String, Unite>();
+    }
+    private String parserEnonces(BufferedReader lEnonces, int nbPropEnonces) throws IOException {
+      String texte = "";
+      String lEnonce;
+      int nbcar = 0;
+      while ((lEnonce = lEnonces.readLine())!=null) {
+        if (lEnonce.trim().isEmpty()) continue;
+        String[] chs = lEnonce.split("\t");
+        if (chs.length!=2+nbPropEnonces) {
+          throw new IOException("Format incorrect de fichier d'énoncés ligne : \n"+lEnonce);
+        }
+        String idEnonce = chs[0].trim();
+        if (enonces.containsKey(idEnonce)) {
+          throw new IOException("Identifant d'énoncés non unique  : "+idEnonce);
+        }
+        String texteEnonce = chs[1].trim();
+        Unite enonce = new Unite("Enoncé", nbcar, nbcar += texteEnonce.length());
+        for (int i = 0; i<nbPropEnonces; i++) {
+          enonce.putProp("Propriété "+i, chs[i+2].trim());
+        }
+        enonces.put(idEnonce, enonce);
+        enonce.putProp("id", idEnonce);
+        corpus.addUniteLue(enonce);
+        corpus.addFinParagraphe(nbcar);
+        texte += texteEnonce;
+      }
+      return texte;
+    }
+    private void parserAnnot(BufferedReader lAnnots, int nbPropAnnots, String bGauche, String bDroite)
+            throws IOException {
+      String lAnnot;
+      while ((lAnnot = lAnnots.readLine())!=null) {
+        if (lAnnot.trim().isEmpty()) continue;
+        String[] chs = lAnnot.split("\t", -1);
+        if (chs.length!=2+nbPropAnnots) {
+          throw new IOException("Format incorrect de fichier d'énoncés ligne : \n"+lAnnot);
+        }
+        String idEnonce = chs[0].trim();
+        String texteEnonceAnnot = chs[1].trim();
+        if (!enonces.containsKey(idEnonce)) {
+          throw new IOException("Identifiant d'énoncés non trouvé : \n"+idEnonce);
+        }
+        int deb = texteEnonceAnnot.indexOf(bGauche);
+        if (texteEnonceAnnot.substring(deb+bGauche.length()).indexOf(bGauche)>=0) {
+          throw new IOException("Plusieurs bornes gauches dans : \n"+texteEnonceAnnot);
+        }
+        String texteEnonce = texteEnonceAnnot.replace(bGauche, "");
+        int fin = texteEnonce.indexOf(bDroite);
+        if (texteEnonce.substring(fin+bDroite.length()).indexOf(bDroite)>=0) {
+          throw new IOException("Plusieurs bornes droites dans : \n"+texteEnonceAnnot);
+        }
+        if (fin<=deb) {
+          throw new IOException("Borne droite précédant la borne gauche dans : \n"+texteEnonceAnnot);
+        }
+        texteEnonce = texteEnonce.replace(bDroite, "");
+        Unite enonce = enonces.get(idEnonce);
+        if (!texteEnonce.equals(corpus.getTexte().substring(enonce.getDeb(), enonce.getFin()))) {
+          throw new IOException("Erreur d'énoncé identifié par "+idEnonce+" : \n"+texteEnonceAnnot
+                  +"Enoncé dans le corpus : "+corpus.getTexte().substring(enonce.getDeb(), enonce.getFin()));
+        }
+        Unite marqueur = new Unite("Marqueur", enonce.getDeb()+deb, enonce.getDeb()+fin);
+        for (int i = 0; i<nbPropAnnots; i++) {
+          marqueur.putProp("Propriété "+i, chs[i+2].trim());
+        }
+        corpus.addUniteLue(marqueur);
+        Relation rel = new Relation("Inclusion", marqueur, enonce);
+        corpus.addRelationLue(rel);
+
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersTableur.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersJava.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersJava.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersJava.java	(revision 3653)
@@ -0,0 +1,454 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+import java.io.*;
+import javax.swing.*;
+import visuAnalec.donnees.*;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+import java.util.*;
+import visuAnalec.vue.*;
+import java.beans.PersistenceDelegate;
+import java.beans.XMLEncoder;
+import java.beans.XMLDecoder;
+/**
+ *
+ * @author Bernard
+ */
+public abstract class FichiersJava {
+  public static void ouvrirCorpusVue(Corpus corpus, Vue vue, String nomfichier) {
+    File fichierCorpus;
+    if (nomfichier.isEmpty()) {
+      if ((fichierCorpus = Fichiers.choisirFichier(Commande.OUVRIR,
+              "Choix du document", Fichiers.TypeFichier.DOC_ANALEC))==null) return;
+    } else {
+      if ((fichierCorpus = Fichiers.trouverFichier(Fichiers.TypeFichier.DOC_ANALEC, nomfichier))==null) {
+        JOptionPane.showMessageDialog(null, "Fichier "+nomfichier+" inexistant dans le dossier "
+                +Fichiers.getRepertoireCourant(Fichiers.TypeFichier.DOC_ANALEC).getPath(), "Erreur de lecture de fichier",
+                JOptionPane.ERROR_MESSAGE);
+        return;
+      }
+    }
+    if(!ouvrirCorpus(corpus, fichierCorpus, false)) return;
+    File fichierVue = Fichiers.trouverFichier(Fichiers.TypeFichier.VUE, fichierCorpus);
+    if (fichierVue==null) return;
+    ouvrirVue(vue, fichierVue);
+  }
+  
+  
+
+public static boolean ouvrirCorpus(Corpus corpus, File fichierCorpus, boolean batch) {
+     ObjectInputStream ois = null;
+     try {
+      ois = new ObjectInputStream(new FileInputStream(fichierCorpus));
+      corpus.lireJava(ois, batch);
+    } catch (ClassNotFoundException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire le document "+fichierCorpus.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+      return false;
+    } catch (InvalidClassException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire le document "+fichierCorpus.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+      return false;
+    } catch (ClassCastException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire le document "+fichierCorpus.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+      return false;
+    } catch (IOException ex) {
+      corpus.fermer();
+      JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+      return false;
+    } finally {
+      try {
+        if (ois!=null) ois.close();
+      } catch (IOException ex) {
+        JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier lu", JOptionPane.ERROR_MESSAGE);
+        return false;
+      }
+      return true;
+    }
+}
+  public static boolean ouvrirStructure(Corpus corpus) {
+    File fichierStructure;
+    if ((fichierStructure = Fichiers.choisirFichier(Commande.OUVRIR,
+            "Choix de la structure", Fichiers.TypeFichier.STRUCTURE))==null) return false;
+    ObjectInputStream ois = null;
+    try {
+      ois = new ObjectInputStream(new FileInputStream(fichierStructure));
+      Structure structureLue = corpus.lireStructureJava(ois);
+      corpus.fusionnerStructureLue(structureLue);
+      corpus.newCorpusLu();
+    } catch (ClassNotFoundException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire la structure "+fichierStructure.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ecs", JOptionPane.ERROR_MESSAGE);
+      return false;
+    } catch (InvalidClassException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire la structure "+fichierStructure.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ecs", JOptionPane.ERROR_MESSAGE);
+      return false;
+    } catch (ClassCastException ex) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire la structure "+fichierStructure.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ecs", JOptionPane.ERROR_MESSAGE);
+    } catch (IOException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+      return false;
+    } finally {
+      try {
+        if (ois!=null) ois.close();
+      } catch (IOException ex) {
+        JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier lu", JOptionPane.ERROR_MESSAGE);
+      }
+    }
+    return true;
+  }
+
+  public static boolean ouvrirVue(Vue vue, File fichierVue) {
+    ObjectInputStream ois = null;
+    try {
+      ois = new ObjectInputStream(new FileInputStream(fichierVue));
+      if (!vue.lireJava(ois)) {
+        JOptionPane.showMessageDialog(null, "Impossible d'utiliser la vue "+fichierVue.getName()
+                +" : vue incompatible avec le document courant", "Erreur de lecture de fichier .ecv", JOptionPane.ERROR_MESSAGE);
+        if (ois!=null) ois.close();
+        return false;
+      }
+    } catch (InvalidClassException ex) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire la vue "+fichierVue.getName()
+              +" : versions d'Analec incompatibles ", "Erreur d'ouverture de fichier .ecv", JOptionPane.ERROR_MESSAGE);
+      return false;
+    } catch (IOException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+      return false;
+    } catch (ClassNotFoundException ex) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire la vue "+fichierVue.getName()
+              +" : versions d'Analec incompatibles ", "Erreur d'ouverture de fichier .ecv", JOptionPane.ERROR_MESSAGE);
+      return false;
+    } catch (ClassCastException ex) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire la vue "+fichierVue.getName()
+              +" : versions d'Analec incompatibles ", "Erreur d'ouverture de fichier .ecv", JOptionPane.ERROR_MESSAGE);
+      return false;
+    } finally {
+      try {
+        if (ois!=null) ois.close();
+      } catch (IOException ex) {
+        JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier lu", JOptionPane.ERROR_MESSAGE);
+      }
+    }
+    return true;
+  }
+
+  public static boolean ouvrirVue(Vue vue) {
+    File fichierVue;
+    if ((fichierVue = Fichiers.choisirFichier(Commande.OUVRIR,
+            "Choix de la vue", Fichiers.TypeFichier.VUE))==null) return false;
+    return ouvrirVue(vue, fichierVue);
+  }
+
+  public static void fusionnerAnnot(Corpus corpus) {
+    File fichierCorpus;
+    if ((fichierCorpus = Fichiers.choisirFichier(Commande.OUVRIR,
+            "Choix du fichier à fusionner", Fichiers.TypeFichier.DOC_ANALEC))==null)
+      return;
+    ObjectInputStream ois = null;
+    try {
+      ois = new ObjectInputStream(new FileInputStream(fichierCorpus));
+      corpus.fusionnerAnnotJava(ois);
+    } catch (ClassNotFoundException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (ClassCastException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (InvalidClassException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (IOException ex) {
+      corpus.fermer();
+      JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } finally {
+      try {
+        if (ois!=null) ois.close();
+      } catch (IOException ex) {
+        JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier lu", JOptionPane.ERROR_MESSAGE);
+      }
+    }
+
+  }
+
+  public static void concatenerDocuments(Corpus corpus) {
+    File fichierCorpus;
+    if ((fichierCorpus = Fichiers.choisirFichier(Commande.OUVRIR,
+            "Choix du fichier à concaténer", Fichiers.TypeFichier.DOC_ANALEC))==null)
+      return;
+    concatener(fichierCorpus, corpus);
+    corpus.newCorpusLu();
+  }
+
+  public static void concatenerCorpus(final Corpus corpus) {
+    File rep;
+    if ((rep = Fichiers.choisirRepertoire("Choix du dossier à concaténer"))
+            ==null) return;
+    final File[] fics = Fichiers.listerFichiers(rep, Fichiers.TypeFichier.DOC_ANALEC);
+    final GMessages.GProgression progression =
+            new GMessages.GProgression(fics.length, "Concaténation", "fichiers");
+    Thread traitement = new Thread() {
+      @Override
+      public void run() {
+        for (int i = 0; i<fics.length; i++) {
+          if (progression.isCanceled()) break;
+          progression.setNbTraites(i+1);
+          concatener(fics[i], corpus);
+        }
+        corpus.newCorpusLu();
+      }
+    };
+    traitement.start();
+  }
+
+  public static void extraireTypeCorpus(final String type, final Corpus corpus) {
+    File rep;
+    if ((rep = Fichiers.choisirRepertoire("Choix du dossier à traiter"))
+            ==null) return;
+   final  File[] fics = Fichiers.listerFichiers(rep, Fichiers.TypeFichier.DOC_ANALEC);
+    final GMessages.GProgression progression =
+            new GMessages.GProgression(fics.length, "Extraction", "fichiers");
+  Thread traitement = new Thread() {
+      @Override
+      public void run() {
+        for (int i = 0; i<fics.length; i++) {
+          if (progression.isCanceled()) break;
+          progression.setNbTraites(i+1);
+      extraireType(fics[i], Fichiers.extraireNom(fics[i]), type, corpus);        
+        }
+        corpus.newCorpusLu();
+      }
+    };
+    traitement.start();
+  }
+
+  private static void extraireType(File fichierCorpus, String nomDocument,
+          String type, Corpus corpus) {
+    ObjectInputStream ois = null;
+    try {
+      ois = new ObjectInputStream(new FileInputStream(fichierCorpus));
+      corpus.extraireEtConcatenerCorpusJava(ois, nomDocument, type);
+    } catch (ClassNotFoundException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (ClassCastException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (InvalidClassException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (IOException ex) {
+      corpus.fermer();
+      JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } finally {
+      try {
+        if (ois!=null) ois.close();
+      } catch (IOException ex) {
+        JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier lu", JOptionPane.ERROR_MESSAGE);
+      }
+    }
+  }
+
+  public static void concatener(File fichierCorpus, Corpus corpus) {
+    ObjectInputStream ois = null;
+    try {
+      ois = new ObjectInputStream(new FileInputStream(fichierCorpus));
+      corpus.concatenerCorpusJava(ois);
+    } catch (ClassNotFoundException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (ClassCastException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (InvalidClassException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire le corpus "+fichierCorpus.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .ec", JOptionPane.ERROR_MESSAGE);
+      return;
+    } catch (IOException ex) {
+      corpus.fermer();
+      JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+      return;
+    } finally {
+      try {
+        if (ois!=null) ois.close();
+      } catch (IOException ex) {
+        JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier lu", JOptionPane.ERROR_MESSAGE);
+      }
+    }
+  }
+
+  public static boolean enregistrerCorpus(Corpus corpus, File fichier) {
+    if (fichier!=null) return ecrireCorpus(corpus, fichier);
+    return false;
+  }
+
+  public static boolean enregistrerCorpusSous(Corpus corpus) {
+    File fichier;
+    if ((fichier = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier corpus", Fichiers.TypeFichier.DOC_ANALEC))==null) return false;
+    return ecrireCorpus(corpus, fichier);
+  }
+
+	public static boolean enregistrerStructure(Corpus corpus) {
+		File fichier;
+		if ((fichier = Fichiers.choisirFichier(Commande.ENREGISTRER,
+				"Nom du fichier structure", Fichiers.TypeFichier.STRUCTURE))==null) return false;
+		
+		return enregistrerStructure(corpus, fichier);
+	}
+
+	public static boolean enregistrerStructure(Corpus corpus, File fichier) {
+		ObjectOutputStream oos = null;
+		try {
+			oos = new ObjectOutputStream(new FileOutputStream(fichier));
+			corpus.ecrireStructureJava(oos);
+		} catch (IOException ex) {
+			JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+			return false;
+		} finally {
+			try {
+				if (oos!=null) oos.close();
+			} catch (IOException ex) {
+				JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier écrit", JOptionPane.ERROR_MESSAGE);
+			}
+		}
+		return true;
+	}
+
+  private static boolean ecrireCorpus(Corpus corpus, File fichier) {
+    ObjectOutputStream oos = null;
+    try {
+      oos = new ObjectOutputStream(new FileOutputStream(fichier));
+      corpus.ecrireJava(oos);
+        return true;
+    } catch (IOException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+         if (oos!=null) try {
+        oos.close();
+      } catch (IOException ex1) {
+      }
+     return false;
+    
+    }
+  }
+
+  public static boolean enregistrerVue(Vue vue, File fichier) {
+	    ObjectOutputStream oos = null;
+	    try {
+	      oos = new ObjectOutputStream(new FileOutputStream(fichier));
+	      vue.ecrireJava(oos);
+	    } catch (IOException ex) {
+	      JOptionPane.showMessageDialog(null, ex, "Erreur d'écriture de fichier", JOptionPane.ERROR_MESSAGE);
+	      return false;
+	    } finally {
+	      try {
+	        if (oos!=null) oos.close();
+	        return true;
+	      } catch (IOException ex) {
+	        JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture de fichier écrit", JOptionPane.ERROR_MESSAGE);
+	        return false;
+	      }
+	    }
+	  }
+  
+  public static boolean enregistrerVue(Vue vue) {
+    File fichier;
+    if ((fichier = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier vue", Fichiers.TypeFichier.VUE))==null) return false;
+    return enregistrerVue(vue, fichier);
+  }
+  /*permet d'ouvrir un procédure d'affichage du module des chaines de coréférence*/
+    public static HashMap<String,Object> ouvrirChaineVue() {
+    File fichierAffichage;
+    HashMap<String,Object> choix = null;
+      if ((fichierAffichage = Fichiers.choisirFichier(Commande.OUVRIR,
+              "Choix du document", Fichiers.TypeFichier.VUE_CHAINE))==null){ 
+          return null;
+      }
+    
+    if((choix=ouvrirChaine(fichierAffichage))==null){
+        return null;
+    }
+    return choix;
+  }
+    public static HashMap<String,Object> ouvrirChaine(File fichierAffichage) {
+     XMLDecoder ois = null;
+     HashMap<String,Object> choix =null;
+     try {
+         ois = new XMLDecoder(new FileInputStream(fichierAffichage));
+         choix = (HashMap<String,Object>) ois.readObject();
+    } catch (ClassCastException e) {
+      JOptionPane.showMessageDialog(null, "Impossible de lire le document "+fichierAffichage.getName()
+              +" : versions d'Analec incompatibles ",
+              "Erreur d'ouverture de fichier .eccv", JOptionPane.ERROR_MESSAGE);
+      return null;
+    } catch (IOException ex) {
+      JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+      return null;
+    } finally {
+        if (ois!=null) ois.close();
+        
+    return choix;
+    }
+}
+    
+      @SuppressWarnings("unchecked")
+  public static HashMap<String,Object> lireJavaChaine(ObjectInputStream ois) throws IOException, ClassNotFoundException, ClassCastException {
+        HashMap<String,Object> choix = (HashMap<String,Object>) ois.readObject();
+        return choix;
+  }
+  
+    public static boolean enregistrerChaineSous(HashMap<String,Object> Choix) {
+    File fichier;
+    if ((fichier = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier des paramètres", Fichiers.TypeFichier.VUE_CHAINE))==null) return false;
+    return ecrireChaine(Choix, fichier);
+  }
+    
+    private static boolean ecrireChaine(HashMap<String,Object> Choix, File fichier) {
+    XMLEncoder oos = null;       
+    try {
+            // serialisation de l'objet
+            oos = new XMLEncoder(new FileOutputStream(fichier));
+            oos.writeObject(Choix);
+            oos.flush();
+            return true;
+        } finally {
+            // fermeture de l'encodeur
+            oos.close();
+            return false;
+        }
+  }
+  
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersJava.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersTEI.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersTEI.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersTEI.java	(revision 3653)
@@ -0,0 +1,953 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.fichiers;
+
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.xml.parsers.*;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+import visuAnalec.donnees.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.util.Fichiers.*;
+import visuAnalec.util.GMessages.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public abstract class FichiersTEI {
+  public static void convertirCorpusTEI(final Corpus corpus) {
+    final File ficTEI;
+    final File repJava;
+    if ((ficTEI = Fichiers.choisirFichier(Commande.OUVRIR,
+            "Choix du fichier corpus TEI", TypeFichier.TEI))==null)
+      return;
+    if ((repJava = Fichiers.choisirRepertoire("Choix du dossier Java"))==null)
+      return;
+    if (!repJava.exists()) {
+      if (!GMessages.confirmationAction("Le dossier spécifié n'existe pas."
+              +" Voulez-vous le créer ?")) return;
+      if (!repJava.mkdir()) {
+        GMessages.impossibiliteAction("Echec de la création du dossier");
+        return;
+      }
+    }
+    convertir(ficTEI, repJava, corpus);
+  }
+  
+  public static boolean convertir(File ficTEI, File repJava, Corpus corpus) {
+    BufferedInputStream tei = null;
+    String nomTEI = Fichiers.extraireNom(ficTEI)+"-";
+    if (Fichiers.existeDebutFichier(repJava, TypeFichier.DOC_ANALEC, nomTEI))
+      if (!GMessages.confirmationAction("Attention! Certains fichiers du "
+              +"dossier "+repJava.getName()
+              +" risquent d'être écrasés")) return false;
+    try {
+      tei = new BufferedInputStream(
+              new ProgressMonitorInputStream(
+              null, "Conversion du corpus TEI "+nomTEI,
+              new FileInputStream(ficTEI)));
+      SAXParserFactory pf = (SAXParserFactory) SAXParserFactory.newInstance();
+      SAXParser sp = pf.newSAXParser();
+      sp.parse(tei, new TEIHandler(corpus, repJava, nomTEI));
+    } catch (IOException ex) {
+      corpus.fermer();
+      JOptionPane.showMessageDialog(null, ex, "Erreur de lecture de fichier", JOptionPane.ERROR_MESSAGE);
+      return false;
+    } catch (ParserConfigurationException ex) {
+      corpus.fermer();
+      JOptionPane.showMessageDialog(null, ex, "Erreur de format de fichier", JOptionPane.ERROR_MESSAGE);
+      return false;
+    } catch (SAXException ex) {
+      corpus.fermer();
+      JOptionPane.showMessageDialog(null, ex, "Erreur de format de fichier", JOptionPane.ERROR_MESSAGE);
+      return false;
+    } finally {
+      try {
+        if (tei!=null) tei.close();
+      } catch (IOException ex) {
+        JOptionPane.showMessageDialog(null, ex, "Erreur de fermeture du fichier lu", JOptionPane.ERROR_MESSAGE);
+      }
+    }
+    return true;
+  }
+
+  static class TEIHandler extends DefaultHandler {
+    File repJava;
+    String nomTEI;
+    Corpus corpus;
+    int noDoc;
+    String texte;
+    ArrayList<Integer> finParagraphes = new ArrayList<Integer>();
+    Balise etatCourant;
+    String typeCourant;
+    HashMap<String, Integer> ancres = new HashMap<String, Integer>();
+    HashMap<Unite, String[]> posUnites = new HashMap<Unite, String[]>();
+    HashMap<String, Element> idElements = new HashMap<String, Element>();
+    HashMap<Relation, String[]> eltsRelations = new HashMap<Relation, String[]>();
+    HashMap<Schema, String[]> eltsSchemas = new HashMap<Schema, String[]>();
+    HashMap<Element, String> propsElements = new HashMap<Element, String>();
+    HashMap<String, HashMap<String, String>> valsprops =
+            new HashMap<String, HashMap<String, String>>();
+    String idPropsEltCourant;
+    String champCourant;
+    String valCourant;
+
+    enum Balise {
+      TEICORPUS, TEIHEADER, TEIHEADER_CORPUS, TEI, TEXT, BODY, P, ANCHOR,
+      BACK, SPANGRP, SPAN, JOINGRP, JOIN, JOINGRP_REL, JOIN_REL,
+      JOINGRP_SCH, JOIN_SCH, FVLIB, FS, F, STRING, DEBUT_DOC, FIN_DOC,
+      AUTRE
+    };
+    static Balise balise(String nomBalise) {
+      try {
+        return Balise.valueOf(nomBalise.replaceAll("\\W", "").toUpperCase());
+      } catch (IllegalArgumentException e) {
+        return Balise.AUTRE;
+      }
+    }
+    TEIHandler(Corpus corpus, File repJava, String nomTEI) {
+      super();
+      this.corpus = corpus;
+      this.repJava = repJava;
+      this.nomTEI = nomTEI;
+    }
+    @Override
+    public void startDocument() {
+      noDoc = 0;
+      etatCourant = Balise.DEBUT_DOC;
+    }
+    @Override
+    public void endDocument() throws SAXNotSupportedException {
+      if (etatCourant!=Balise.FIN_DOC)
+        throw new SAXNotSupportedException("Fin de fichier inattendue");
+    }
+    @Override
+    public void startElement(String uri, String local, String nomBalise,
+            Attributes attributs) throws SAXException {
+      switch (balise(nomBalise)) {
+        case TEICORPUS:
+          if (etatCourant==Balise.DEBUT_DOC) etatCourant = Balise.TEICORPUS;
+          else
+            throw new SAXNotSupportedException("Balise <teiCorpus> mal placée");
+          break;
+        case TEIHEADER:
+          if (etatCourant==Balise.TEICORPUS)
+            etatCourant = Balise.TEIHEADER_CORPUS;
+          else if (etatCourant==Balise.TEI) etatCourant = Balise.TEIHEADER;
+          else
+            throw new SAXNotSupportedException("Balise <teiHeader> mal placée");
+
+          break;
+        case TEI:
+          if (etatCourant==Balise.TEICORPUS) {
+            noDoc++;
+            initCorpus();
+            etatCourant = Balise.TEI;
+          } else
+            throw new SAXNotSupportedException("Balise <tei> mal placée");
+          break;
+        case TEXT:
+          if (etatCourant==Balise.TEI) {
+            etatCourant = Balise.TEXT;
+          } else
+            throw new SAXNotSupportedException("Balise <text> mal placée");
+          break;
+        case BODY:
+          if (etatCourant==Balise.TEXT) {
+            etatCourant = Balise.BODY;
+          } else
+            throw new SAXNotSupportedException("Balise <body> mal placée");
+          break;
+        case P:
+          if (etatCourant==Balise.BODY) {
+            etatCourant = Balise.P;
+          } else
+            throw new SAXNotSupportedException("Balise <p> mal placée");
+          break;
+        case ANCHOR:
+          if ("AnalecDelimiter".equals(attributs.getValue("type"))) {
+            if (etatCourant==Balise.BODY||etatCourant==Balise.P) {
+              ancres.put(attributs.getValue("xml:id"), texte.length());
+            } else
+              throw new SAXNotSupportedException("Balise <anchor> de type "
+                      +"\"AnalecDelimiter\" mal placée");
+          }
+          break;
+        case BACK:
+          if (etatCourant==Balise.TEXT) {
+            etatCourant = Balise.BACK;
+          } else
+            throw new SAXNotSupportedException("Balise <back> mal placée");
+          break;
+        case SPANGRP:
+          if ("AnalecUnit".equals(attributs.getValue("type"))) {
+            if (etatCourant==Balise.BACK) {
+              typeCourant = decodeId(attributs.getValue("n"));
+              if (typeCourant.isEmpty())
+                throw new SAXNotSupportedException("Attribut \"n\" d'une balise "
+                        +"<spanGrp> de type \"AnalecUnit\" manquant");
+              etatCourant = Balise.SPANGRP;
+            } else
+              throw new SAXNotSupportedException("Balise <spanGrp> "
+                      +"de type \"AnalecUnit\" mal placée");
+          }
+          break;
+        case SPAN:
+          if (etatCourant==Balise.SPANGRP) {
+            Unite unit = new Unite();
+            unit.setType(typeCourant);
+            posUnites.put(unit, new String[]{
+                      xmlId(attributs.getValue("from")),
+                      xmlId(attributs.getValue("to"))});
+            idElements.put(attributs.getValue("xml:id"), unit);
+            propsElements.put(unit, xmlId(attributs.getValue("ana")));
+            etatCourant = Balise.SPAN;
+          }
+          break;
+        case JOINGRP:
+          if ("AnalecRelation".equals(attributs.getValue("type"))) {
+            if (etatCourant==Balise.BACK) {
+              typeCourant = decodeId(attributs.getValue("n"));
+              if (typeCourant.isEmpty())
+                throw new SAXNotSupportedException("Attribut \"n\" d'une balise "
+                        +"<joinGrp> de type \"AnalecRelation\" manquant");
+              etatCourant = Balise.JOINGRP_REL;
+            } else
+              throw new SAXNotSupportedException("Balise <joinGrp> "
+                      +"de type \"AnalecRelation\" mal placée");
+          } else if ("AnalecSchema".equals(attributs.getValue("type"))) {
+            if (etatCourant==Balise.BACK) {
+              typeCourant = decodeId(attributs.getValue("n"));
+              if (typeCourant.isEmpty())
+                throw new SAXNotSupportedException("Attribut \"n\" d'une balise "
+                        +"<joinGrp> de type \"AnalecSchema\" manquant");
+              etatCourant = Balise.JOINGRP_SCH;
+            } else
+              throw new SAXNotSupportedException("Balise <joinGrp> "
+                      +"de type \"AnalecSchema\" mal placée");
+          }
+
+          break;
+        case JOIN:
+          if (etatCourant==Balise.JOINGRP_REL) {
+            Relation rel = new Relation();
+            rel.setType(typeCourant);
+            eltsRelations.put(rel, splitIds(attributs.getValue("target")));
+            idElements.put(attributs.getValue("xml:id"), rel);
+            propsElements.put(rel, xmlId(attributs.getValue("ana")));
+            etatCourant = Balise.JOIN_REL;
+          } else if (etatCourant==Balise.JOINGRP_SCH) {
+            Schema sch = new Schema();
+            sch.setType(typeCourant);
+            eltsSchemas.put(sch, splitIds(attributs.getValue("target")));
+            idElements.put(attributs.getValue("xml:id"), sch);
+            propsElements.put(sch, xmlId(attributs.getValue("ana")));
+            etatCourant = Balise.JOIN_SCH;
+          }
+          break;
+        case FVLIB:
+          if ("AnalecElementProperties".equals(attributs.getValue("n"))) {
+            if (etatCourant==Balise.BACK) {
+              etatCourant = Balise.FVLIB;
+            } else
+              throw new SAXNotSupportedException("Balise <fvLib> "
+                      +"de type \"AnalecElementProperties\" mal placée");
+          }
+          break;
+        case FS:
+          if (etatCourant==Balise.FVLIB) {
+            idPropsEltCourant = attributs.getValue("xml:id");
+            valsprops.put(idPropsEltCourant, new HashMap<String, String>());
+            etatCourant = Balise.FS;
+          }
+          break;
+        case F:
+          if (etatCourant==Balise.FS) {
+            champCourant = decodeId(attributs.getValue("name"));
+            if (champCourant.isEmpty())
+              throw new SAXNotSupportedException("Attribut \"name\" "
+                      + "d'une balise <f> dans le <fvLib> de type"
+                      + " \"AnalecElementProperties\" manquant");
+
+            etatCourant = Balise.F;
+          }
+          break;
+        case STRING:
+          if (etatCourant==Balise.F) {
+            valCourant = "";
+            etatCourant = Balise.STRING;
+          }
+          break;
+      }
+    }
+    private String xmlId(String id) {
+      if (id==null||id.isEmpty()||id.charAt(0)!='#') return null;
+      return id.substring(1);
+    }
+    private String[] splitIds(String ids) {
+      if(ids.isEmpty()) return new String[0];
+      String[] idsplit = ids.split("\\s+");
+      for (int i = 0; i<idsplit.length; i++) {
+        idsplit[i] = xmlId(idsplit[i]);
+      }
+      return idsplit;
+    }
+    @Override
+    public void endElement(String uri, String local, String nomBalise) throws SAXException {
+      String type = "";
+      switch (balise(nomBalise)) {
+        case TEICORPUS:
+          if (etatCourant==Balise.TEICORPUS) etatCourant = Balise.FIN_DOC;
+          else
+            throw new SAXNotSupportedException("Balise </teiCorpus> mal placée");
+          break;
+        case TEIHEADER:
+          if (etatCourant==Balise.TEIHEADER_CORPUS)
+            etatCourant = Balise.TEICORPUS;
+          else if (etatCourant==Balise.TEIHEADER) etatCourant = Balise.TEI;
+          else
+            throw new SAXNotSupportedException("Balise </teiHeader> mal placée");
+          break;
+        case TEI:
+          if (etatCourant==Balise.TEI) {
+            remplirCorpus();
+            if (!ecrireFichier()) throw new SAXException("Erreur d'écriture "
+                      +"du fichier "+nomTEI+noDoc+".ec");
+            etatCourant = Balise.TEICORPUS;
+          } else
+            throw new SAXNotSupportedException("Balise </tei> mal placée");
+          break;
+        case TEXT:
+          if (etatCourant==Balise.TEXT) etatCourant = Balise.TEI;
+          else
+            throw new SAXNotSupportedException("Balise </text> mal placée");
+          break;
+        case BODY:
+          if (etatCourant==Balise.BODY) {
+            corpus.setTexte(texte);
+            corpus.setFinParagraphes(finParagraphes);
+            etatCourant = Balise.TEXT;
+          } else
+            throw new SAXNotSupportedException("Balise </body> mal placée");
+          break;
+        case P:
+          if (etatCourant==Balise.P) {
+            finParagraphes.add(texte.length());
+            etatCourant = Balise.BODY;
+          }
+          break;
+        case BACK:
+          if (etatCourant==Balise.BACK) etatCourant = Balise.TEXT;
+          else
+            throw new SAXNotSupportedException("Balise </back> mal placée");
+          break;
+        case SPANGRP:
+          if (etatCourant==Balise.SPANGRP) etatCourant = Balise.BACK;
+          break;
+        case SPAN:
+          if (etatCourant==Balise.SPAN) etatCourant = Balise.SPANGRP;
+          break;
+        case JOINGRP:
+          if (etatCourant==Balise.JOINGRP_REL||etatCourant==Balise.JOINGRP_SCH)
+            etatCourant = Balise.BACK;
+          break;
+        case JOIN:
+          if (etatCourant==Balise.JOIN_REL) etatCourant = Balise.JOINGRP_REL;
+          else if (etatCourant==Balise.JOIN_SCH)
+            etatCourant = Balise.JOINGRP_SCH;
+          break;
+        case FVLIB:
+          if (etatCourant==Balise.FVLIB) etatCourant = Balise.BACK;
+          break;
+        case FS:
+          if (etatCourant==Balise.FS) etatCourant = Balise.FVLIB;
+          break;
+        case F:
+          if (etatCourant==Balise.F) etatCourant = Balise.FS;
+          break;
+        case STRING:
+          if (etatCourant==Balise.STRING) {
+            valsprops.get(idPropsEltCourant).put(champCourant, valCourant);
+            etatCourant = Balise.F;
+          }
+          break;
+      }
+    }
+    @Override
+    public void characters(char[] ch, int start, int taille) throws SAXException {
+      if (etatCourant==Balise.P)
+        texte += decodeTexte(new String(ch, start, taille));
+      if (etatCourant==Balise.STRING)
+        valCourant += decodeTexte(new String(ch, start, taille));
+    }
+    private static String decodeTexte(String ch) {
+      return ch.replaceAll("&amp;", "&").replaceAll("&lt;", "<").
+              replaceAll("&gt;", ">").replaceAll("&quot;", "\"").
+              replaceAll("&apos;", "\'").replaceAll("[\\t\\n\\r\\f]", "");
+    }
+    private static String decodeId(String ch) {
+      if (ch==null||ch.isEmpty()) return "";
+      String id = ch.charAt(0)=='_' ? ch.substring(1) : ch;
+      return id.replaceAll("_", " ");
+    }
+    private void initCorpus() {
+      corpus.clearAll();
+      texte = "";
+      finParagraphes.clear();
+      ancres.clear();
+      posUnites.clear();
+      eltsRelations.clear();
+      eltsSchemas.clear();
+      idElements.clear();
+      propsElements.clear();
+      valsprops.clear();
+    }
+    private void remplirCorpus() throws SAXNotSupportedException {
+      for (Unite unit : posUnites.keySet()) {
+        String[] pos = posUnites.get(unit);
+        if (pos[0]==null||!ancres.containsKey(pos[0])
+                ||pos[1]==null||!ancres.containsKey(pos[1]))
+          throw new SAXNotSupportedException("Pas trouvé d'ancrage pour "
+                  +"une unité de type "+unit.getType());
+        unit.setDeb(ancres.get(pos[0]));
+        unit.setFin(ancres.get(pos[1]));
+        String idProps = propsElements.get(unit);
+        if (idProps==null||!valsprops.containsKey(idProps))
+          throw new SAXNotSupportedException("Pas trouvé de propriétés pour "
+                  +"une unité de type "+unit.getType());
+        HashMap<String, String> props = valsprops.get(idProps);
+        for (String champ : props.keySet())
+          unit.putProp(champ, props.get(champ));
+        corpus.addUniteLue(unit);
+      }
+      for (Relation rel : eltsRelations.keySet()) {
+        String[] idElts = eltsRelations.get(rel);
+        if (idElts.length!=2) {
+          throw new SAXNotSupportedException("Une relation de type "
+                  +rel.getType()+" n'a pas deux termes");
+        }
+        if (idElts[0]==null||!idElements.containsKey(idElts[0])
+                ||idElts[1]==null||!idElements.containsKey(idElts[1])) {
+          throw new SAXNotSupportedException("Errreur d'identification de termes "
+                  +" pour une relation de type "+rel.getType());
+        }
+        rel.setElt1(idElements.get(idElts[0]));
+        rel.setElt2(idElements.get(idElts[1]));
+        String idProps = propsElements.get(rel);
+        if (idProps==null||!valsprops.containsKey(idProps))
+          throw new SAXNotSupportedException("Pas trouvé de propriétés pour "
+                  +"une relation de type "+rel.getType());
+        HashMap<String, String> props = valsprops.get(idProps);
+        for (String champ : props.keySet())
+          rel.putProp(champ, props.get(champ));
+        corpus.addRelationLue(rel);
+      }
+      for (Schema sch : eltsSchemas.keySet()) {
+        String[] idElts = eltsSchemas.get(sch);
+        for (String idElt : idElts) {
+          if (idElt==null||!idElements.containsKey(idElt)) {
+            throw new SAXNotSupportedException("Errreur d'identification de termes "
+                    +" pour un schema de type "+sch.getType());
+          }
+          sch.ajouter(idElements.get(idElt));
+        }
+        String idProps = propsElements.get(sch);
+        if (idProps==null||!valsprops.containsKey(idProps))
+          throw new SAXNotSupportedException("Pas trouvé de propriétés pour "
+                  +"un schéma de type "+sch.getType());
+        HashMap<String, String> props = valsprops.get(idProps);
+        for (String champ : props.keySet())
+          sch.putProp(champ, props.get(champ));
+        corpus.addSchemaLu(sch);
+      }
+    }
+    private boolean ecrireFichier() {
+      return FichiersJava.enregistrerCorpus(corpus, Fichiers.creerFichier(
+              repJava, TypeFichier.DOC_ANALEC, nomTEI+noDoc));
+    }
+  }
+  public final static String TYPE_INFOS_META_DOCUMENTS = "Titre";
+  public final static String CHAMP_NON_RENSEIGNE = "non renseigné";
+  public final static String DEFAUT_TITRE_CORPUS = "";
+  public final static String DEFAUT_ANNOTATEURS = "";
+  public final static String DEFAUT_EDITEUR = "";
+  public final static String DEFAUT_SOURCE_CORPUS = "";
+  public static boolean exporterCorpusTEI(final Corpus corpus) {
+    File repJava;
+    final File ficTEI;
+    final File[] fics = Fichiers.choisirCorpus("Choix du dossier Java",
+            TypeFichier.CORPUS_ANALEC);
+    if (fics.length==0) return false; ;
+    final HashMap<String, String> infosCorpus = new HashMap<String, String>();
+    saisirInfosCorpus(infosCorpus);
+    if ((ficTEI = Fichiers.choisirFichier(Commande.ENREGISTRER,
+            "Nom du fichier TEI", Fichiers.TypeFichier.TEI))==null) return false;
+    final PrintWriter teiWriter;
+    try {
+      teiWriter = new PrintWriter(ficTEI, "UTF-8");
+    } catch (FileNotFoundException ex) {
+      GMessages.impossibiliteAction("Pas de fichier TEI ? ");
+
+      return false;
+    } catch (UnsupportedEncodingException ex) {
+      GMessages.impossibiliteAction("Pas de codage UTF8 ?");
+      return false;
+    }
+    final TEIPrinter teiPrinter = new TEIPrinter(corpus, teiWriter);
+    final GMessages.GProgression progression =
+            new GMessages.GProgression(fics.length, "Conversion", "fichiers");
+    Thread traitement = new Thread() {
+      @Override
+      public void run() {
+        try {
+          teiPrinter.ecrireEnteteCorpus(infosCorpus);
+          for (int i = 0; i<fics.length; i++) {
+            if (progression.isCanceled()) break;
+            progression.setNbTraites(i+1);
+            File ficJava = fics[i];
+            if (FichiersJava.ouvrirCorpus(corpus, ficJava, true))
+              teiPrinter.ecrireDocument(Fichiers.extraireNom(ficJava));
+          }
+          corpus.fermer();
+          teiPrinter.ecrireFinCorpus();
+          teiWriter.close();
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    };
+    traitement.start();
+    try {
+		traitement.join();
+	} catch (InterruptedException e) {
+		GMessages.erreurFatale(e);
+		return false;
+	}
+    return true;
+  }
+  private static boolean saisirInfosCorpus(HashMap<String, String> infosCorpus) {
+    final boolean[] pvalide = new boolean[1];
+    SaisieInfos fenetre = new SaisieInfos(pvalide, infosCorpus);
+    return pvalide[0];
+  }
+
+  private static class SaisieInfos extends JDialog {
+    private SaisieInfos(final boolean[] pvalide,
+            final HashMap<String, String> infosCorpus) {
+      super((JFrame) null, "Informations sur le corpus", true);
+      JPanel cadre = new JPanel(new BorderLayout());
+      setContentPane(cadre);
+      Rectangle rmax = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
+      int largeur = Math.min(rmax.width-100, 600);
+      int hauteur = Math.min(rmax.height-100, 400);
+      Point locFenetre = new Point((rmax.x+rmax.width)/2-largeur/2,
+              (rmax.y+rmax.height)/2-hauteur/2);
+      Dimension dimFenetre = new Dimension(largeur, hauteur);
+      setLocation(locFenetre);
+      setSize(dimFenetre);
+      setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
+      int hauteurCars = cadre.getFontMetrics(cadre.getFont()).getHeight()+5;
+      final JTextField champTitre = new JTextField(40);
+      champTitre.setMaximumSize(new Dimension(500, hauteurCars));
+      champTitre.setText(DEFAUT_TITRE_CORPUS);
+      final JTextField champAnnot = new JTextField(40);
+      champAnnot.setMaximumSize(new Dimension(500, hauteurCars));
+      champAnnot.setText(DEFAUT_ANNOTATEURS);
+      final JTextField champEditeur = new JTextField(40);
+      champEditeur.setMaximumSize(new Dimension(500, hauteurCars));
+      champEditeur.setText(DEFAUT_EDITEUR);
+      final JTextField champSource = new JTextField(40);
+      champSource.setMaximumSize(new Dimension(500, hauteurCars));
+      champSource.setText(DEFAUT_SOURCE_CORPUS);
+      Box box = Box.createVerticalBox();
+      box.add(Box.createVerticalGlue());
+      Box boxTitre = Box.createHorizontalBox();
+      boxTitre.add(Box.createHorizontalGlue());
+      boxTitre.add(new JLabel("Titre du corpus"));
+      boxTitre.add(Box.createHorizontalStrut(5));
+      boxTitre.add(champTitre);
+      boxTitre.add(Box.createHorizontalGlue());
+      box.add(boxTitre);
+      box.add(Box.createVerticalGlue());
+      Box boxAnnot = Box.createHorizontalBox();
+      boxAnnot.add(Box.createHorizontalGlue());
+      boxAnnot.add(new JLabel("Annotateurs"));
+      boxAnnot.add(Box.createHorizontalStrut(5));
+      boxAnnot.add(champAnnot);
+      boxAnnot.add(Box.createHorizontalGlue());
+      box.add(boxAnnot);
+      box.add(Box.createVerticalGlue());
+      Box boxEditeur = Box.createHorizontalBox();
+      boxEditeur.add(Box.createHorizontalGlue());
+      boxEditeur.add(new JLabel("Editeur"));
+      boxEditeur.add(Box.createHorizontalStrut(5));
+      boxEditeur.add(champEditeur);
+      boxEditeur.add(Box.createHorizontalGlue());
+      box.add(boxEditeur);
+      box.add(Box.createVerticalGlue());
+      Box boxSource = Box.createHorizontalBox();
+      boxSource.add(Box.createHorizontalGlue());
+      boxSource.add(new JLabel("Description du corpus"));
+      boxSource.add(Box.createHorizontalStrut(5));
+      boxSource.add(champSource);
+      boxSource.add(Box.createHorizontalGlue());
+      box.add(boxSource);
+      box.add(Box.createVerticalGlue());
+      add(box);
+      JButton valideModifs = new JButton(
+              new GAction("Valider") {
+                @Override
+                public void executer() {
+                  pvalide[0] = true;
+                  infosCorpus.put("Titre", champTitre.getText());
+                  infosCorpus.put("Annot", champAnnot.getText());
+                  infosCorpus.put("Editeur", champEditeur.getText());
+                  infosCorpus.put("Source", champSource.getText());
+                  dispose();
+                }
+              ;
+      });
+    JButton annuleModifs = new JButton(
+              new GAction("Annuler") {
+                @Override
+                public void executer() {
+                  pvalide[0] = false;
+                  dispose();
+                }
+              ;
+      });
+     Box boutons = Box.createHorizontalBox();
+      boutons.add(Box.createGlue());
+      boutons.add(valideModifs, Box.CENTER_ALIGNMENT);
+      boutons.add(Box.createHorizontalStrut(5));
+      boutons.add(annuleModifs, Box.CENTER_ALIGNMENT);
+      boutons.add(Box.createGlue());
+      add(boutons, BorderLayout.SOUTH);
+      setVisible(
+              true);
+
+    }
+  }
+
+  static private class TEIPrinter {
+    static private class Delimiteur implements Comparable<Delimiteur> {
+      private String id;
+      private int taille; // signé : négatif pour les délimiteurs de fin
+      private Delimiteur(String id, int taille) {
+        this.id = id;
+        this.taille = taille;
+      }
+      public int compareTo(Delimiteur d) {
+        if (taille!=d.taille) {
+          if (taille<0&&d.taille<0||taille>0&&d.taille>0)
+            return d.taille-taille;
+          else return taille-d.taille;
+        } else return taille>0 ? -d.id.compareTo(id) : d.id.compareTo(id);
+      }
+    }
+    private Corpus corpus;
+    private PrintWriter writer;
+    private String titreCorpus, annot, editeur, sourceCorpus;
+    private HashMap<String, ArrayList<Unite>> unites =
+            new HashMap<String, ArrayList<Unite>>();
+    private HashMap<String, ArrayList<Relation>> relations =
+            new HashMap<String, ArrayList<Relation>>();
+    private HashMap<String, ArrayList<Schema>> schemas =
+            new HashMap<String, ArrayList<Schema>>();
+    private HashMap<Element, String> ids = new HashMap<Element, String>();
+    private HashMap<String, String> encodeName = new HashMap<String, String>();
+    private HashMap<Integer, ArrayList<Delimiteur>> delimiteurs =
+            new HashMap<Integer, ArrayList<Delimiteur>>();
+    TEIPrinter(Corpus corpus, PrintWriter writer) {
+      this.corpus = corpus;
+      this.writer = writer;
+    }
+    private void ecrireEnteteCorpus(HashMap<String, String> infosCorpus) {
+      titreCorpus = traiterSaisie(infosCorpus.get("Titre"));
+      annot = traiterSaisie(infosCorpus.get("Annot"));
+      editeur = traiterSaisie(infosCorpus.get("Editeur"));
+      sourceCorpus = traiterSaisie(infosCorpus.get("Source"));
+      writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
+      writer.println("<teiCorpus xmlns=\"http://www.tei-c.org/ns/1.0\">");
+      writer.println(" <teiHeader>");
+      writer.println("<fileDesc>");
+      writer.println("<titleStmt>");
+      writer.println("<title>"+titreCorpus+"</title>");
+      writer.println("<respStmt>");
+      writer.println("<resp>annotated by</resp>");
+      writer.println("<name>"+annot+"</name>");
+      writer.println("</respStmt>");
+      writer.println("</titleStmt>");
+      writer.println("<publicationStmt>");
+      writer.println("<publisher>"+editeur+"</publisher>");
+      writer.println("</publicationStmt>");
+      writer.println("<sourceDesc>");
+      writer.println("<bibl>"+sourceCorpus+"</bibl>");
+      writer.println("</sourceDesc>");
+      writer.println("</fileDesc>");
+      writer.println("</teiHeader>");
+    }
+    private void ecrireFinCorpus() {
+      writer.println("</teiCorpus>");
+    }
+    private void preparerDonnees() {
+      unites.clear();
+      relations.clear();
+      schemas.clear();
+      ids.clear();
+      encodeName.clear();
+      delimiteurs.clear();
+      String codeType = "";
+      for (String type : corpus.getStructure().getTypes(Unite.class)) {
+        Unite[] units = corpus.getUnites(type).toArray(new Unite[0]);
+        Arrays.sort(units);
+        if (units.length>0) {
+          unites.put(type, new ArrayList<Unite>());
+          codeType = encodeId(type);
+          encodeName.put(type, codeType);
+          for (String prop : corpus.getStructure().getNomsProps(Unite.class, type))
+            encodeName.put(prop, encodeId(prop));
+        }
+        for (int no = 0; no<units.length; no++) {
+          Unite unit = units[no];
+          String id = "u-"+codeType+"-"+(no+1);
+          ids.put(unit, id);
+          unites.get(type).add(unit);
+          int taille = unit.getFin()-unit.getDeb();
+          Delimiteur del = new Delimiteur(id, taille);
+          addDel(unit.getDeb(), del);
+          if (taille>0) {
+            del = new Delimiteur(id, -taille);
+            addDel(unit.getFin(), del);
+          }
+        }
+      }
+      for (String type : corpus.getStructure().getTypes(Relation.class)) {
+        Relation[] rels = corpus.getRelations(type).toArray(new Relation[0]);
+        Arrays.sort(rels);
+        if (rels.length>0) {
+          relations.put(type, new ArrayList<Relation>());
+          codeType = encodeId(type);
+          encodeName.put(type, codeType);
+          for (String prop : corpus.getStructure().getNomsProps(Relation.class, type))
+            encodeName.put(prop, encodeId(prop));
+
+        }
+        for (int no = 0; no<rels.length; no++) {
+          Relation rel = rels[no];
+          String id = "r-"+codeType+"-"+(no+1);
+          ids.put(rel, id);
+          relations.get(type).add(rel);
+        }
+      }
+      for (String type : corpus.getStructure().getTypes(Schema.class)) {
+        Schema[] schs = corpus.getSchemas(type).toArray(new Schema[0]);
+        Arrays.sort(schs);
+        if (schs.length>0) {
+          schemas.put(type, new ArrayList<Schema>());
+          codeType = encodeId(type);
+          encodeName.put(type, codeType);
+          for (String prop : corpus.getStructure().getNomsProps(Schema.class, type))
+            encodeName.put(prop, encodeId(prop));
+        }
+        for (int no = 0; no<schs.length; no++) {
+          Schema sch = schs[no];
+          String id = "s-"+codeType+"-"+(no+1);
+          ids.put(sch, id);
+          schemas.get(type).add(sch);
+        }
+      }
+      int deb = 0;
+      for (int fin : corpus.getFinParagraphes()) {
+        int taille = fin-deb;
+        Delimiteur del = new Delimiteur("p", taille);
+        addDel(deb, del);
+        if (taille>0) {
+          del = new Delimiteur("p", -taille);
+          addDel(fin, del);
+        }
+        deb = fin;
+      }
+    }
+    private void addDel(int pos, Delimiteur del) {
+      if (!delimiteurs.containsKey(pos))
+        delimiteurs.put(pos, new ArrayList<Delimiteur>());
+      delimiteurs.get(pos).add(del);
+    }
+    private void ecrireDocument(String nomfic) {
+      preparerDonnees();
+      writer.println("<TEI>");
+      ecrireEntete(nomfic);
+      writer.println("<text>");
+      ecrireTexte();
+      ecrireAnnot();
+      writer.println("</text>");
+      writer.println("</TEI>");
+    }
+    private void ecrireEntete(String nomfic) {
+      String titre = "";
+      String auteur = "";
+      String source = "";
+      if (!corpus.getUnites(TYPE_INFOS_META_DOCUMENTS).isEmpty()) {
+        Unite infos = corpus.getUnites(TYPE_INFOS_META_DOCUMENTS).get(0);
+        titre = encodeTexte(infos.getProp("titre"));
+        auteur = encodeTexte(infos.getProp("auteur"));
+        source = encodeTexte(infos.getProp("source"));
+      }
+      if (titre.isEmpty()) titre = nomfic;
+      if (auteur.isEmpty()) auteur = CHAMP_NON_RENSEIGNE;
+      if (source.isEmpty()) source = CHAMP_NON_RENSEIGNE;
+      writer.println("<teiHeader>");
+      writer.println("<fileDesc>");
+      writer.println("<titleStmt>");
+      writer.println("<title>"+titre+"</title>");
+      writer.println("<author>"+auteur+"</author>");
+      writer.println("<respStmt>");
+      writer.println("<resp>annotated by</resp>");
+      writer.println("<name>"+annot+"</name>");
+      writer.println("</respStmt>");
+      writer.println("</titleStmt>");
+      writer.println("<publicationStmt>");
+      writer.println("<publisher>"+editeur+"</publisher>");
+      writer.println("</publicationStmt>");
+      writer.println("<sourceDesc>");
+      writer.println("<bibl>"+source+"</bibl>");
+      writer.println("</sourceDesc>");
+      writer.println("</fileDesc>");
+      writer.println("</teiHeader>");
+    }
+    private void ecrireTexte() {
+      writer.println("<body>");
+      Integer[] pos = delimiteurs.keySet().toArray(new Integer[0]);
+      Arrays.sort(pos);
+      ecrireDel(delimiteurs.get(0));
+      int deb = 0;
+      for (int i = 1; i<pos.length; i++) {
+        int fin = pos[i];
+        writer.print(encodeTexte(corpus.getTexte().substring(deb, fin)));
+        ecrireDel(delimiteurs.get(fin));
+        deb = fin;
+      }
+      writer.println("</body>");
+    }
+    private void ecrireDel(ArrayList<Delimiteur> delims) {
+      Delimiteur[] dels = delims.toArray(new Delimiteur[0]);
+      Arrays.sort(dels);
+      for (Delimiteur del : dels) {
+        if (del.id.equals("p")) {
+          if (del.taille>0)
+            writer.println("<p>");
+          else {
+            writer.println();
+            if (del.taille<0) writer.println("</p>");
+            else writer.println("<p/>");
+          }
+        } else {
+          String ancre1 = "<anchor xml:id=\""+del.id;
+          String ancre2 = "\" type=\"AnalecDelimiter\" subtype=\"Unit";
+          if (del.taille>0)
+            writer.print(ancre1+"-start"+ancre2+"Start\"/>");
+          else if (del.taille<0)
+            writer.print(ancre1+"-end"+ancre2+"End\"/>");
+          else {  // ne devrait pas se produire : une unité de taille nulle
+            writer.print(ancre1+"-start"+ancre2+"Start\"/>");
+            writer.print(ancre1+"-end"+ancre2+"End\"/>");
+          }
+        }
+      }
+    }
+    private void ecrireAnnot() {
+      writer.println("<back>");
+      for (String type : unites.keySet()) {
+        writer.println("<spanGrp type=\"AnalecUnit\""
+                +" n=\""+encodeName.get(type)+"\">");
+        for (Unite unit : unites.get(type)) ecrireUnite(unit);
+        writer.println("</spanGrp>");
+      }
+      for (String type : relations.keySet()) {
+        writer.println("<joinGrp type=\"AnalecRelation\""
+                +" n=\""+encodeName.get(type)+"\">");
+        for (Relation rel : relations.get(type)) ecrireRelation(rel);
+        writer.println("</joinGrp>");
+      }
+      for (String type : schemas.keySet()) {
+        writer.println("<joinGrp type=\"AnalecSchema\""
+                +" n=\""+encodeName.get(type)+"\">");
+        for (Schema sch : schemas.get(type)) ecrireSchema(sch);
+        writer.println("</joinGrp>");
+      }
+      writer.println("<fvLib n=\"AnalecElementProperties\">");
+      for (String type : unites.keySet())
+        for (Unite unit : unites.get(type)) ecrireProps(unit);
+      for (String type : relations.keySet())
+        for (Relation rel : relations.get(type)) ecrireProps(rel);
+      for (String type : schemas.keySet())
+        for (Schema sch : schemas.get(type)) ecrireProps(sch);
+      writer.println("</fvLib>");
+      writer.println("</back>");
+    }
+    private void ecrireUnite(Unite unit) {
+      String id = ids.get(unit);
+      writer.println("<span xml:id=\""+id+"\"");
+      writer.println("from=\"#"+id+"-start\" to=\"#"+id+"-end\"");
+      writer.println("ana=\"#"+id+"-fs\"/>");
+    }
+    private void ecrireRelation(Relation rel) {
+      String id = ids.get(rel);
+      writer.println("<join xml:id=\""+ids.get(rel)+"\"");
+      writer.println("target=\"#"+ids.get(rel.getElt1())
+              +" #"+ids.get(rel.getElt2())+"\"");
+      writer.println("ana=\"#"+id+"-fs\"/>");
+    }
+    private void ecrireSchema(Schema sch) {
+      String id = ids.get(sch);
+      writer.println("<join xml:id=\""+ids.get(sch)+"\"");
+      writer.print("target=\"");
+      for (Element elt : sch.getContenu())
+        writer.print("#"+ids.get(elt)+" ");
+      writer.println("\"");
+      writer.println("ana=\"#"+id+"-fs\"/>");
+    }
+    private void ecrireProps(Element elt) {
+      writer.println("<fs xml:id=\""+ids.get(elt)+"-fs\">");
+      HashMap<String, String> props = elt.getProps();
+      for (String nom : props.keySet()) {
+        if (props.get(nom)!=null)
+          writer.println("<f name=\""+encodeName.get(nom)+"\"><string>"
+                  +encodeTexte(props.get(nom))+"</string></f>");
+      }
+      writer.println("</fs>");
+    }
+    private static String encodeTexte(String ch) {
+      return ch.replaceAll("&", "&amp;").replaceAll("<", "&lt;").
+              replaceAll(">", "&gt;").replaceAll("\"", "&quot;").
+              replaceAll("\'", "&apos;");
+    }
+    final static String interdits = "[!\\\"#\\$%&'\\(\\)\\*+,/;<=>\\?"
+            +"@\\[\\\\\\]\\^`\\{\\|\\}\\~]";
+    private static String encodeId(String ch) {
+      String id = ch.replaceAll("\\s", "_");
+      if (id.matches("[-\\.0-9];*")) id = '_'+id;
+      id = id.replaceAll(interdits, "\u00b7");
+      if (id.substring(0, 3).equalsIgnoreCase("xml")) id = '_'+id;
+      return id;
+    }
+    private static String traiterSaisie(String ch) {
+      if (ch==null) return CHAMP_NON_RENSEIGNE;
+      if (ch.trim().isEmpty()) return CHAMP_NON_RENSEIGNE;
+      return encodeTexte(ch);
+    }
+  }
+  
+
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/fichiers/FichiersTEI.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/Tableaux.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/Tableaux.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/Tableaux.java	(revision 3653)
@@ -0,0 +1,86 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.util;
+
+import java.util.*;
+import visuAnalec.elements.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public abstract class Tableaux {
+  public static int compterValeursVraies(boolean[] bls) {
+    int nb = 0;
+    for(boolean b: bls) if(b) nb++;
+    return nb;
+  }
+  public static String[] insererString(String[] strs, String str) {
+    // renvoie un tableau trié
+    String[] strs1 = insererStringEnTete(strs, str);
+    Arrays.sort(strs1);
+    return strs1;
+  }
+  public static String[] insererStringEnTete(String[] strs, String str) {
+    String[] strs1 = new String[strs.length + 1];
+    System.arraycopy(strs, 0, strs1, 1, strs.length);
+    strs1[0] = str;
+    return strs1;
+  }
+  static String[] oterString(String[] strs, String str) {
+    // strs doit être triée
+    int ind = Arrays.binarySearch(strs, str);
+    if (ind < 0) return strs;
+    return oterString(strs, ind);
+  }
+  public static String[] oterString(String[] strs, int ind) {
+    String[] strs1 = new String[strs.length - 1];
+    System.arraycopy(strs, 0, strs1, 0, ind);
+    System.arraycopy(strs, ind + 1, strs1, ind, strs.length - ind - 1);
+    return strs1;
+  }
+  public static String[] oterStrings(String[] strs, ArrayList<Integer> inds) {
+    //  inds doit être croissant
+    String[] strs1 = new String[strs.length - inds.size()];
+    inds.add(strs.length);
+    System.arraycopy(strs, 0, strs1, 0, inds.get(0));
+    for (int i = 1; i < inds.size(); i++)
+      System.arraycopy(strs, inds.get(i - 1) + 1, strs1, inds.get(i - 1) - i + 1, inds.get(i) - inds.get(i - 1) - 1);
+    return strs1;
+  }
+//  public static String[][] oterStrings(String[][] strs, ArrayList<Integer> inds1, ArrayList<Integer> inds2) {
+//    //  inds1 et inds2 doivent être de même taille
+//    String[] strs1 = new String[strs.length - inds.size()];
+//    inds.add(strs.length);
+//    System.arraycopy(strs, 0, strs1, 0, inds.get(0));
+//    for (int i = 1; i < inds.size(); i++)
+//      System.arraycopy(strs, inds.get(i - 1) + 1, strs1, inds.get(i - 1) - i + 1, inds.get(i) - inds.get(i - 1) - 1);
+//    return strs1;
+//  }
+  public static Element[] insererElementEnTete(Element[] elts, Element elt) {
+    Element[] elts1 = new Element[elts.length + 1];
+    System.arraycopy(elts, 0, elts1, 1, elts.length);
+    elts1[0] = elt;
+    return elts1;
+  }
+  public static Element[] oterElements(Element[] elts, ArrayList<Integer> inds) {
+    //  inds doit être croissant
+    Element[] elts1 = new Element[elts.length - inds.size()];
+    inds.add(elts.length);
+    System.arraycopy(elts, 0, elts1, 0, inds.get(0));
+    for (int i = 1; i < inds.size(); i++)
+      System.arraycopy(elts, inds.get(i - 1) + 1, elts1, inds.get(i - 1) - i + 1, inds.get(i) - inds.get(i - 1) - 1);
+    return elts1;
+  }
+  public static Relation[] oterRelations(Relation[] elts, ArrayList<Integer> inds) {
+    //  inds doit être croissant
+    Relation[] elts1 = new Relation[elts.length - inds.size()];
+    inds.add(elts.length);
+    System.arraycopy(elts, 0, elts1, 0, inds.get(0));
+    for (int i = 1; i < inds.size(); i++)
+      System.arraycopy(elts, inds.get(i - 1) + 1, elts1, inds.get(i - 1) - i + 1, inds.get(i) - inds.get(i - 1) - 1);
+    return elts1;
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/Tableaux.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/Fichiers.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/Fichiers.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/Fichiers.java	(revision 3653)
@@ -0,0 +1,332 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.util;
+
+import java.awt.*;
+import java.beans.*;
+import java.io.*;
+import java.util.*;
+import java.util.prefs.Preferences;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.filechooser.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public abstract class Fichiers {
+  public enum TypeFichier {
+    DOC_ANALEC("Document Analec", "ec"),
+    VUE_CHAINE("Paramètre affiche des schémas Analec", "xml"),
+    CORPUS_ANALEC("Fichiers Analec", "ec"),
+    STRUCTURE("Structure Analec", "ecs"),
+    VUE("Vue Analec", "ecv"),
+    PDF("fichier pdf", "pdf"),    
+    TABLEUR_STATS("Tableur format texte (séparateur : tabulation)", "txt"),
+    GRAPHIQUE_SVG("Graphique vectoriel format svg", "svg"),
+    GRAPHIQUE_EMF("Graphique vectoriel format emf", "emf"),
+    GLOZZ_CORPUS("Corpus Glozz", "ac"),
+    GLOZZ_ANNOT("Annotations Glozz", "aa"),
+    GLOZZ_MODELE("Modèle Glozz", "aam"),
+    SYNTEX("Résultats Syntex", "anasynt"),
+    TABLEUR_ENONCES("Table des énoncés", "txt"),
+    TABLEUR_ANNOT("Table des annotations", "txt"),
+    TEI("Corpus format TEI", "xml"),
+    RHAPS("Corpus Rhapsodie format tabulaire", "tabular"),
+    CONLL("Document format CoNLL", "out"),
+    TEXTE("Texte brut", "txt"),
+    TEXTE_RTF("Texte format RTF", "rtf"),
+    TEXTE_HTML("Texte format HTML", "html"),
+    DONNEES_CSV("Format de base de données", "csv");
+    
+    String ext;
+    String nom;
+    TypeFichier(String nom, String ext) {
+      this.nom = nom;
+      this.ext = ext;
+    }
+    public String getNom() {
+      return nom;
+    }
+    public String getExtension() {
+      return ext;
+    }
+    public boolean importCorpus() {
+      return EnumSet.of(TypeFichier.TEXTE, TypeFichier.GLOZZ_CORPUS, TypeFichier.SYNTEX).contains(this);
+    }
+    public boolean resultats() {
+      return EnumSet.of(TypeFichier.TABLEUR_STATS, TypeFichier.GRAPHIQUE_SVG, TypeFichier.GRAPHIQUE_EMF).contains(this);
+    }
+  }
+
+  public enum Commande {
+    OUVRIR("Ouvrir"),
+    ENREGISTRER("Enregistrer");
+    String label;
+    Commande(String label) {
+      this.label = label;
+    }
+    public String getLabel() {
+      return label;
+    }
+  }
+
+  public static class FiltreExt implements java.io.FileFilter {
+    private TypeFichier type;
+    public FiltreExt(TypeFichier type) {
+      this.type = type;
+    }
+    public boolean accept(File fic) {
+      return type.getExtension().equals(getExtension(fic));
+    }
+  }
+  // Variables de classe
+  private static Preferences pref = Preferences.userNodeForPackage(Fichiers.class);
+  private static File repertoireCourantCorpus = new File(pref.get("repertoire", System.getProperty("user.dir")));
+  private static EnumMap<TypeFichier, File> fichiersCourants = new EnumMap<TypeFichier, File>(TypeFichier.class);
+  static {
+    String nomfic = pref.get("nomCorpus", "");
+    if (!nomfic.isEmpty())
+      fichiersCourants.put(TypeFichier.DOC_ANALEC, new File(repertoireCourantCorpus, nomfic+'.'+TypeFichier.DOC_ANALEC.getExtension()));
+  }
+  public static File trouverFichier(TypeFichier type, String nomFichier) {
+    File fichier = new File(repertoireCourantCorpus, nomFichier);
+    if (!getExtension(fichier).equals(type.getExtension()))
+      fichier = changerExtension(fichier, type.getExtension());
+    if (!fichier.exists()) return null;
+    majFichiersCourants(type, fichier);
+    return fichier;
+  }
+  public static File trouverFichier(TypeFichier type, File oldfichier) {
+    File fichier = changerExtension(oldfichier, type.getExtension());
+    if (!fichier.exists()) return null;
+    majFichiersCourants(type, fichier);
+    return fichier;
+  }
+  public static File creerFichier(File rep, TypeFichier type, File oldfichier) {
+    return ajouterExtension(new File(rep, extraireNom(oldfichier)), type.getExtension());
+  }
+  public static File creerFichier(File rep, TypeFichier type, String nom) {
+    return ajouterExtension(new File(rep, nom), type.getExtension());
+  }
+  public static File getRepertoireCourant(TypeFichier type) {
+    if (fichiersCourants.containsKey(type))
+      return fichiersCourants.get(type).getParentFile();
+    return repertoireCourantCorpus;
+  }
+  public static File getFichierCourant(TypeFichier type) {
+    if (fichiersCourants.containsKey(type)) return fichiersCourants.get(type);
+    return null;
+  }
+  public static String getNomFichierCourant(TypeFichier type) {
+    if (fichiersCourants.containsKey(type))
+      return extraireNom(fichiersCourants.get(type));
+    return "";
+  }
+  public static void removeFichierCourant(TypeFichier type) {
+    fichiersCourants.remove(type);
+  }
+  private static void majFichiersCourants(TypeFichier type, File fichier) {
+    fichiersCourants.put(type, fichier);
+    if (type==TypeFichier.GLOZZ_CORPUS) {
+      fichiersCourants.put(TypeFichier.GLOZZ_ANNOT, changerExtension(fichier, TypeFichier.GLOZZ_ANNOT.ext));
+      fichiersCourants.put(TypeFichier.GLOZZ_MODELE, changerExtension(fichier, TypeFichier.GLOZZ_MODELE.ext));
+    }
+    if (type==TypeFichier.DOC_ANALEC) {
+      repertoireCourantCorpus = fichier.getParentFile();
+      pref.put("repertoire", repertoireCourantCorpus.getPath());
+      pref.put("nomCorpus", extraireNom(fichier));
+    }
+
+  }
+  // Utilitaires de manipulation de noms de fichiers
+  private static File ajouterExtension(File fichier, String extension) {
+    String nom = fichier.getName();
+    return new File(fichier.getParentFile(), nom+"."+extension);
+  }
+  private static File changerExtension(File fichier, String extension) {
+    String nom = fichier.getName();
+    int ind = nom.lastIndexOf('.');
+    if (ind>=0) nom = nom.substring(0, ind);
+    return new File(fichier.getParentFile(), nom+"."+extension);
+  }
+  public static String extraireNom(File fichier) {
+    if (fichier==null) return null;
+    String nom = fichier.getName();
+    int ind = nom.lastIndexOf('.');
+    if (ind<0) return nom;
+    else return nom.substring(0, ind);
+  }
+  private static String getExtension(File fichier) {
+    String nom = fichier.getName();
+    int ind = nom.lastIndexOf('.');
+    if (ind>=0) return nom.substring(ind+1);
+    return "";
+  }
+  public static File[] listerFichiers(File rep, TypeFichier type) {
+    return rep.listFiles(new FiltreExt(type));
+  }
+  public static boolean existeDebutFichier(File rep, TypeFichier type, 
+          String debut) {
+    File[] fics = listerFichiers(rep, type);
+    if (fics == null) return false;
+    for (int i = 0; i<fics.length; i++) 
+      if(extraireNom(fics[i]).startsWith(debut)) return true;
+    return false;
+  }
+  // Choix des fichiers
+  public static File choisirFichier(Commande commande, String titre, TypeFichier type) {
+    return choisirFichier(commande, titre, type, null);
+  }
+  public static File choisirFichier(Commande commande, String titre, TypeFichier type, JComponent complement) {
+    JFileChooser choixFichier = new JFileChooser();
+    choixFichier.resetChoosableFileFilters();
+    choixFichier.setFileFilter(new FileNameExtensionFilter(type.getNom(), type.getExtension()));
+    choixFichier.setDialogTitle(titre);
+    if (complement!=null) choixFichier.setAccessory(complement);
+    choixFichier.setCurrentDirectory(getRepertoireCourant(type));
+    File fichierPropose;
+    if (type.resultats()) {
+      String nom = extraireNom(getFichierCourant(TypeFichier.DOC_ANALEC));
+      if (nom==null) fichierPropose = null;
+      else fichierPropose = new File(getRepertoireCourant(type), nom+"_res");
+    } else {
+      fichierPropose = getFichierCourant(type);
+    }
+    if (fichierPropose!=null) {
+      if (commande==Commande.OUVRIR&&!fichierPropose.exists()) {
+        fichierPropose = new File(getRepertoireCourant(type), "*."+type.getExtension());
+      }
+      choixFichier.setSelectedFile(fichierPropose);
+    }
+    int reponse = choixFichier.showDialog(null, commande.getLabel());
+    if (reponse!=JFileChooser.APPROVE_OPTION) return null;
+    File fichierChoisi = choixFichier.getSelectedFile();
+    if (commande==Commande.ENREGISTRER) {
+      if (!getExtension(fichierChoisi).equals(type.getExtension()))
+        fichierChoisi = ajouterExtension(fichierChoisi, type.getExtension());
+      if (fichierChoisi.exists()) {
+        int rep = JOptionPane.showOptionDialog(null, "Remplacer "+fichierChoisi.getName()+" ?",
+                "Fichier existant", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+                null, new Object[]{"Remplacer", "Annuler"}, "Remplacer");
+        if (rep==1) return null;
+      }
+    }
+    majFichiersCourants(type, fichierChoisi);
+    if (commande==Commande.OUVRIR&&type.importCorpus())
+      fichiersCourants.remove(TypeFichier.DOC_ANALEC);
+    return fichierChoisi;
+  }
+  public static File choisirRepertoire(String titre) {
+    JFileChooser choixRep = new JFileChooser();
+    choixRep.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+    choixRep.setAcceptAllFileFilterUsed(false);
+    choixRep.setFileFilter(new FileNameExtensionFilter("Répertoire", "*"));
+    choixRep.setDialogTitle(titre);
+    choixRep.setCurrentDirectory(repertoireCourantCorpus);
+    int reponse = choixRep.showDialog(null, "Sélectionner");
+    if (reponse!=JFileChooser.APPROVE_OPTION) return null;
+    return choixRep.getSelectedFile();
+  }
+  public static File[] choisirCorpus(String titre, TypeFichier type) {
+    JFileChooser choixFichier = new JFileChooser();
+    FilesystemFilter filtre = new FilesystemFilter(type.getExtension(), "", false);
+    choixFichier.addPropertyChangeListener(new SelectFics(choixFichier, filtre));
+    choixFichier.resetChoosableFileFilters();
+    choixFichier.setFileFilter(new FileNameExtensionFilter(
+            type.getNom(), type.getExtension()));
+    choixFichier.setDialogTitle(titre);
+    choixFichier.setMultiSelectionEnabled(true);
+    File rep = getRepertoireCourant(type);
+    choixFichier.setCurrentDirectory(rep);
+    int reponse = choixFichier.showDialog(null, "Choisir");
+    if (reponse!=JFileChooser.APPROVE_OPTION) return new File[0];
+    File[] fics = choixFichier.getSelectedFiles();
+    if (fics==null||fics.length==0) return new File[0];
+    majFichiersCourants(TypeFichier.CORPUS_ANALEC, fics[0]);
+    return fics;
+  }
+
+  static class FilesystemFilter extends javax.swing.filechooser.FileFilter
+          implements FilenameFilter {
+    private String[] extensions;
+    private String description;
+    private boolean accepteReps;
+    public FilesystemFilter(String extension, String description,
+            boolean accepteReps) {
+      this(new String[]{extension}, description, accepteReps);
+    }
+    public FilesystemFilter(String[] extensions, String description,
+            final boolean accepteReps) {
+      this.extensions = extensions;
+      this.description = description;
+      this.accepteReps = accepteReps;
+    }
+    public boolean accept(File rep, String nom) {
+      return accept(new File(rep, nom));
+    }
+    public boolean accept(final File fic) {
+      if (fic.isDirectory()&&accepteReps) return true;
+      for (int i = 0; i<this.extensions.length; i++)
+        if (fic.getName().endsWith(this.extensions[i])) return true;
+      return false;
+    }
+    public String getDescription() {
+      return this.description;
+    }
+ }
+ public static class SelectFics implements PropertyChangeListener{
+    JFileChooser choix;
+    FilesystemFilter filtre;
+    SelectFics(JFileChooser choix, FilesystemFilter filtre) {
+      this.choix = choix;
+      this.filtre = filtre;
+    }
+    @Override
+       public void propertyChange(PropertyChangeEvent e) {
+        if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(e.getPropertyName())) {
+           choix.setSelectedFiles(choix.getCurrentDirectory().listFiles(filtre));
+        }
+    }
+  }
+
+  public static class GCodage {
+    JPanel contenant;
+    JComboBox saisieCodage;
+    public GCodage() {
+      saisieCodage = new JComboBox(new String[]{
+                "Microsoft (windows-1252)",
+                "UTF-8 (unicode 8 bits)",
+                "UTF-16 (unicode 16 bits)",
+                "ISO-8859-1 (latin-1)",
+                "<autre (à saisir)>"
+              });
+      saisieCodage.setEditable(true);
+      saisieCodage.setSelectedIndex(0);
+      contenant = new JPanel(new BorderLayout());
+      contenant.setBorder(new TitledBorder("Codage des caractères"));
+      contenant.add(saisieCodage, BorderLayout.NORTH);
+      contenant.add(new JPanel(), BorderLayout.CENTER);
+    }
+    public JComponent getContenant() {
+      return contenant;
+    }
+    public String getCode() {
+      switch (saisieCodage.getSelectedIndex()) {
+        case 0:
+          return "windows-1252";
+        case 1:
+          return "UTF-8";
+        case 2:
+          return "UTF-16";
+        case 3:
+          return "ISO-8859-1";
+        default:
+          return (String) saisieCodage.getSelectedItem();
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/Fichiers.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/GVisu.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/GVisu.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/GVisu.java	(revision 3653)
@@ -0,0 +1,1146 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.util;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.util.ArrayList;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.GMessages.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public abstract class GVisu {
+  public static class TitreBarre extends JLabel {
+    public TitreBarre(String titre) {
+      super(titre);
+    }
+    public TitreBarre(String titre, Color couleur) {
+      super(titre);
+      setOpaque(true);
+      setBackground(couleur);
+    }
+  }
+
+  public static abstract class Boutons {
+    public static void setDefaut(JButton bouton, boolean oui) {
+      ((JFrame) bouton.getTopLevelAncestor()).getRootPane().setDefaultButton(oui ? bouton : null);
+      if (oui) bouton.requestFocusInWindow();
+    }
+  }
+  public static String styleIdPopup(String texte, String id) {
+    if (texte.length()>35)
+      texte = texte.substring(0, 18)+" [...] "+texte.substring(texte.length()-8);
+    return "<html>"+id+" (<span style=\"font-style:italic \">"+texte+"</span>)";
+  }
+  public static String styleIdTooltip(ArrayList<String> textes, ArrayList<String> ids) {
+    String tooltip = "<html>";
+    for (int i = 0; i<textes.size(); i++) {
+      String texte = textes.get(i);
+      if (texte.length()>35)
+        texte = texte.substring(0, 18)+" [...] "+texte.substring(texte.length()-8);
+      tooltip += "<p>"+ids.get(i)+" (<span style=\"font-style:italic \">"+texte+"</span>)";
+    }
+    return tooltip;
+  }
+  public static String styleDef(String nom) {
+    return "<html><span style=\"color:gray\"> &lt <span style=\"font-style:italic \">"
+            +nom+"</span> &gt";
+  }
+  private final static Font STYLE_COMBO = Font.decode("Arial plain 12");
+
+  public enum SensSpinnerBinaire {
+    SUIVANT, PRECEDENT
+  }
+
+  public static class ModeleSpinnerBinaire extends AbstractSpinnerModel {
+    private SensSpinnerBinaire sens;
+    public Object getValue() {
+      return sens;
+    }
+    public void setValue(Object value) {
+      sens = (SensSpinnerBinaire) value;
+      fireStateChanged();
+    }
+    public Object getNextValue() {
+      return SensSpinnerBinaire.PRECEDENT;
+    }
+    public Object getPreviousValue() {
+      return SensSpinnerBinaire.SUIVANT;
+    }
+  }
+  private static Dimension dimZero = new Dimension(20, 20);
+  private static Insets insetsZero = new Insets(0, 0, 0, 0);
+
+  public static class ElementComboBox extends Box implements ActionListener, ChangeListener {
+    private ArrayList<ActionListener> listeCorrespondants = new ArrayList<ActionListener>();
+    public JComboBox combo;
+    private JButton zero;
+    private JSpinner spin;
+    public Element[] elements;  // liste triée
+    public ElementComboBox() {
+      super(BoxLayout.X_AXIS);
+      zero = new JButton(new GAction("0") {
+        public void executer() {
+          effSelection();
+        }
+      });
+      zero.setMargin(insetsZero);
+      zero.setPreferredSize(dimZero);
+      spin = new JSpinner(new ModeleSpinnerBinaire());
+      spin.setEditor(new JLabel());
+      spin.addChangeListener(this);
+      combo = new JComboBox();
+      combo.setEditable(false);
+      combo.setFont(STYLE_COMBO);
+      combo.addActionListener(this);
+      add(combo);
+      add(spin);
+      add(zero);
+      setModeleVide();
+    }
+    public void addActionListener(ActionListener correspondant) {
+      listeCorrespondants.add(correspondant);
+    }
+    public void removeActionListener(ActionListener correspondant) {
+      listeCorrespondants.remove(correspondant);
+    }
+    public void actionPerformed(ActionEvent evt) {
+      try {
+        evt.setSource(this);
+        for (Object corresp : listeCorrespondants.toArray()) {
+          ((ActionListener) corresp).actionPerformed(evt);
+        }
+      } catch (Throwable ex) {
+        GMessages.erreurFatale(ex);
+      }
+    }
+    public void setModeleVide() {
+      combo.setModel(new DefaultComboBoxModel(new String[]{styleDef("identifiant")}));
+      elements = new Element[0];
+      setMaximumSize(getPreferredSize());
+    }
+    public void setModele(Element[] elts, String[] ids) {
+      // elts doit être trié et en correspondance avec ids
+      combo.setModel(new DefaultComboBoxModel(Tableaux.insererStringEnTete(ids, styleDef("identifiant"))));
+      elements = elts;
+      setMaximumSize(getPreferredSize());
+    }
+    public Element[] getElements() {
+      return elements;
+    }
+    public void gotoPrecedent() {
+      int index;
+      if ((index = combo.getSelectedIndex())==0) index = combo.getItemCount();
+      combo.setSelectedIndex(index-1);
+    }
+    public void gotoSuivant() {
+      int index = combo.getSelectedIndex()+1;
+      if (index==combo.getItemCount()) index = 0;
+      combo.setSelectedIndex(index);
+    }
+    public boolean pasdeSelection() {
+      return combo.getSelectedIndex()<1;
+    }
+    public Element getSelection() {
+      if (combo.getSelectedIndex()>0)
+        return elements[combo.getSelectedIndex()-1];
+      return null;
+    }
+    public void effSelection() {
+      combo.setSelectedIndex(0);
+    }
+    public void setSelection(Element elt) {
+      int no = Arrays.binarySearch(elements, elt);
+      if (no<0)
+        throw new ArrayIndexOutOfBoundsException("Element à sélectionner absent");
+      combo.setSelectedIndex(no+1);
+    }
+    public String getIdElement(Element elt) {
+      int no = Arrays.binarySearch(elements, elt);
+      if (no<0)
+        throw new ArrayIndexOutOfBoundsException("Element recherché absent");
+      return ((String) combo.getItemAt(no+1));
+
+    }
+    public void stateChanged(ChangeEvent e) {
+      try {
+        switch ((SensSpinnerBinaire) spin.getValue()) {
+          case SUIVANT:
+            gotoSuivant();
+            return;
+          case PRECEDENT:
+            gotoPrecedent();
+            return;
+        }
+      } catch (Throwable ex) {
+        GMessages.erreurFatale(ex);
+      }
+    }
+  }
+
+  public static class Val0ComboBox extends JComboBox {
+    private String[] vals;
+    private String val0;
+    public Val0ComboBox(String val0) {
+      super();
+      this.val0 = val0;
+      setEditable(false);
+      setFont(STYLE_COMBO);
+      setModeleVide();
+    }
+    public void setModeleVide() {
+      setModel(new DefaultComboBoxModel(new String[]{styleDef(val0)}));
+      vals = new String[0];
+      setMaximumSize(getPreferredSize());
+    }
+    public void setModele(String[] types) {
+      setModel(new DefaultComboBoxModel(Tableaux.insererStringEnTete(types, styleDef(val0))));
+      this.vals = types;
+      setMaximumSize(getPreferredSize());
+    }
+    public boolean pasdeSelection() {
+      return getSelectedIndex()<1;
+    }
+    public int nbItems() {
+      return vals.length;
+    }
+    public String getSelection() {
+      if (getSelectedIndex()>0) return vals[getSelectedIndex()-1];
+      return null;
+    }
+    public void effSelection() {
+      setSelectedIndex(0);
+    }
+    public void setSelection(String type) {
+      setSelectedItem(type);
+    }
+    public void setSelection(int i) {
+      setSelectedIndex(i+1);
+    }
+  }
+  public static String getNomClasse(Class<? extends Element> classe) {
+    if (classe==Element.class) return "élément";
+    else if (classe==Unite.class) return "unité";
+    else if (classe==Relation.class) return "relation";
+    else if (classe==Schema.class) return "schéma";
+    else
+      throw new UnsupportedOperationException("Sous-classe inconnue pour getNomClasse()");
+  }
+  public static String getNomDeClasse(Class<? extends Element> classe) {
+    if (classe==Element.class) return "d'élément";
+    else if (classe==Unite.class) return "d'unité";
+    else if (classe==Relation.class) return "de relation";
+    else if (classe==Schema.class) return "de schéma";
+    else
+      throw new UnsupportedOperationException("Sous-classe inconnue pour getNomTypedeClasse()");
+  }
+  public static String getNomDeLaClasse(Element elt) {
+    Class<? extends Element> classe = elt.getClass();
+    if (classe==Unite.class) return "de l'unité";
+    else if (classe==Relation.class) return "de la relation";
+    else if (classe==Schema.class) return "du schéma";
+    else
+      throw new UnsupportedOperationException("Sous-classe inconnue pour getNomTypedeClasse()");
+  }
+  public static Class<? extends Element> getClasse(String classeType) {
+    if (classeType==null) return null;
+    if (classeType.startsWith("REL-")) return Relation.class;
+    if (classeType.startsWith("SCH-")) return Schema.class;
+    return Unite.class;
+  }
+  public static String getType(String classeType) {
+    if (classeType==null) return null;
+    if (classeType.startsWith("REL-")) return classeType.substring(4);
+    if (classeType.startsWith("SCH-")) return classeType.substring(4);
+    return classeType;
+  }
+  private static String getClasseType(Class<? extends Element> classe, String type) {
+    if (classe==Unite.class) return type;
+    else if (classe==Relation.class) return "REL-"+type;
+    else if (classe==Schema.class) return "SCH-"+type;
+    else
+      throw new UnsupportedOperationException("Sous-classe inconnue pour getClasseType()");
+  }
+  public static String[] getClassesTypes(String[] typesUnit, String[] typesRel, String[] typesSch) {
+    String[] types = Arrays.copyOf(typesUnit, typesUnit.length+typesRel.length+typesSch.length);
+    for (int i = 0; i<typesRel.length; i++)
+      types[i+typesUnit.length] = "REL-"+typesRel[i];
+    for (int i = 0; i<typesSch.length; i++)
+      types[i+typesUnit.length+typesRel.length] = "SCH-"+typesSch[i];
+    return types;
+  }
+
+  public static class TypeComboBox extends Val0ComboBox {
+    private Class<? extends Element> classe;
+    public TypeComboBox(Class<? extends Element> classe) {
+      super("type "+getNomDeClasse(classe));
+      this.classe = classe;
+    }
+    @Override
+    public void setModele(String[] types) {
+      if (this.classe==Element.class)
+        throw new UnsupportedOperationException("pas pour la classe Element");
+      super.setModele(types);
+    }
+    public void setModele(String[] typesUnites, String[] typesRelations, String[] typesSchemas) {
+      if (this.classe!=Element.class)
+        throw new UnsupportedOperationException("uniquement pour la classe Element");
+      super.setModele(getClassesTypes(typesUnites, typesRelations, typesSchemas));
+    }
+    public String getTypeSelection() {
+      String classetype = getSelection();
+      if (classetype==null) return null;
+      if (classe==Element.class) return getType(classetype);
+      return classetype;
+    }
+    public Class<? extends Element> getClasseSelection() {
+      String classetype = getSelection();
+      if (classetype==null) return null;
+      if (classe==Element.class) return getClasse(classetype);
+      return classe;
+    }
+    public void setSelection(Class<? extends Element> classe, String type) {
+      if (this.classe!=Element.class)
+        throw new UnsupportedOperationException("uniquement pour la classe Element");
+      super.setSelection(getClasseType(classe, type));
+    }
+    @Override
+    public void setSelection(String type) {
+      if (this.classe==Element.class)
+        throw new UnsupportedOperationException("pas pour la classe Element");
+      super.setSelection(type);
+    }
+  }
+  private final static Color[] couleursEtNoirEtBlanc = new Color[]{Color.BLACK, Color.WHITE, Color.YELLOW,
+    Color.RED, Color.BLUE, Color.ORANGE, Color.GREEN, Color.CYAN, Color.MAGENTA, Color.PINK
+  };
+  private final static Color[] couleurs = new Color[]{Color.YELLOW, Color.RED, Color.BLUE,
+    Color.ORANGE, Color.GREEN, Color.CYAN, Color.MAGENTA, Color.PINK
+  };
+  public static Color[] getCouleursEtNoirEtBlanc() {
+    return couleursEtNoirEtBlanc;
+  }
+  public static Color getCouleur(int i) {
+    Color c = couleurs[i%couleurs.length];
+    for (int n = 0; n<i/couleurs.length; n++) {
+      float[] rgb = c.getRGBColorComponents(null);
+      c = new Color(0.499f+rgb[0]/3, 0.499f+rgb[1]/3, 0.499f+rgb[2]/3);
+    }
+    return c;
+  }
+  public static int getTaille(int i) {
+    int c;
+    c = i + 1;
+    if(c > 4){
+        c = 4;
+    }
+    return c;
+  }
+  public static int getForme(int i) {
+    int c;
+    c = i;
+    return c;
+  }
+  /*@require : i doit être positif et inférieur ou égal 99*/
+  public static String getTexte(int i) {
+    String c;
+    c = "" + ((i - i%10)%100)/10 + i%10;
+    return c;
+  }
+  
+  public static Color getCouleurSansValeur() {
+    return Color.LIGHT_GRAY;
+  }
+  public static int getFormeSansValeur() {
+    return 10;
+  }
+  public static int getTailleSansValeur() {
+    return 4;
+  }
+
+  public static String getTexteSansValeur() {
+    return "99";
+  }
+
+  public static class DisqueCouleurIcone implements Icon {
+    private Color couleur;
+    int rayon;
+    int marge;
+    public DisqueCouleurIcone(Color couleur, int rayon, int marge) {
+      this.couleur = couleur;
+      this.rayon = rayon;
+      this.marge = marge;
+    }
+    public void paintIcon(Component c, Graphics g, int x, int y) {
+      if (couleur==null) {
+        g.setColor(Color.BLACK);
+        g.drawLine(x+3*marge, y+3*marge, x+2*rayon-marge, y+2*rayon-marge);
+        g.drawLine(x+3*marge, y+2*rayon-marge, x+2*rayon-marge, y+3*marge);
+      } else {
+        g.setColor(couleur);
+        g.fillOval(x+marge, y+marge, 2*rayon, 2*rayon);
+        g.setColor(Color.BLACK);
+        g.drawOval(x+marge, y+marge, 2*rayon, 2*rayon);
+      }
+    }
+    public int getIconWidth() {
+      return 2*rayon+2*marge;
+    }
+    public int getIconHeight() {
+      return 2*rayon+2*marge;
+    }
+    public int getRayon(){
+        return rayon;
+    }
+    public int getMarge(){
+        return marge;
+    }
+    public Color getColor(){
+        return couleur;
+    }
+    
+  }
+
+  public static class CarreCouleurIcone implements Icon {
+    private Color couleur;
+    int rayon;
+    int marge;
+    public CarreCouleurIcone(Color couleur, int rayon, int marge) {
+      this.couleur = couleur;
+      this.rayon = rayon;
+      this.marge = marge;
+    }
+    public void paintIcon(Component c, Graphics g, int x, int y) {
+      if (couleur==null) {
+        g.setColor(Color.BLACK);
+        g.drawLine(x+3*marge, y+3*marge, x+2*rayon-marge, y+2*rayon-marge);
+        g.drawLine(x+3*marge, y+2*rayon-marge, x+2*rayon-marge, y+3*marge);
+      } else {
+        g.setColor(couleur);
+        g.fillRect(x+marge, y+marge, 2*rayon, 2*rayon);
+        g.setColor(Color.BLACK);
+        g.drawRect(x+marge, y+marge, 2*rayon, 2*rayon);
+      }
+    }
+    public int getIconWidth() {
+      return 2*rayon+2*marge;
+    }
+    public int getIconHeight() {
+      return 2*rayon+2*marge;
+    }
+    public int getRayon(){
+        return rayon;
+    }
+    public int getMarge(){
+        return marge;
+    }
+    public Color getColor(){
+        return couleur;
+    }
+  }
+  public static class CroixCouleurIcone implements Icon {
+    private Color couleur;
+    int rayon;
+    int marge;
+    public CroixCouleurIcone(Color couleur, int rayon, int marge) {
+      this.couleur = couleur;
+      this.rayon = rayon;
+      this.marge = marge;
+    }
+    public void paintIcon(Component c, Graphics g, int x, int y) {
+      if (couleur==null ) {
+        g.setColor(Color.BLACK);
+        g.drawLine(x+3*marge, y+3*marge, x+2*rayon-marge, y+2*rayon-marge);
+        g.drawLine(x+3*marge, y+2*rayon-marge, x+2*rayon-marge, y+3*marge);
+      } else {
+        g.setColor(couleur);
+        int x1[]=new int[]{x+marge,x+marge+rayon-1,x+marge+rayon-1,x+marge+rayon+1,x+marge+rayon+1
+                , x + marge + 2 * rayon,x + marge + 2 * rayon,x+marge+rayon+1,x+marge+rayon+1 
+                ,x+marge+rayon-1,x+marge+rayon-1,x+marge,x+marge};
+        int y1[]=new int[]{y + marge+rayon-1,y + marge+rayon-1,y + marge,y + marge,y + marge+rayon-1
+                ,y + marge+rayon-1,y + marge+rayon+1,y + marge+rayon+1,y + marge+2*rayon
+                ,y + marge+2*rayon,y + marge+rayon+1,y + marge+rayon+1,y + marge+rayon-1 };
+        g.fillPolygon(x1, y1, 13);
+        g.setColor(Color.BLACK);
+        g.drawPolygon(x1, y1, 13);
+      }
+    }
+    public int getIconWidth() {
+      return 2*rayon+2*marge;
+    }
+    public int getIconHeight() {
+      return 2*rayon+2*marge;
+    }
+    public int getRayon(){
+        return rayon;
+    }
+    public int getMarge(){
+        return marge;
+    }
+    public Color getColor(){
+        return couleur;
+    }
+    
+  }
+  public static class TriangleCouleurIcone implements Icon {
+    private Color couleur;
+    int rayon;
+    int marge;
+    public TriangleCouleurIcone(Color couleur, int rayon, int marge) {
+      this.couleur = couleur;
+      this.rayon = rayon;
+      this.marge = marge;
+    }
+    public void paintIcon(Component c, Graphics g, int x, int y) {
+      if (couleur==null) {
+        g.setColor(Color.BLACK);
+        g.drawLine(x+3*marge, y+3*marge, x+2*rayon-marge, y+2*rayon-marge);
+        g.drawLine(x+3*marge, y+2*rayon-marge, x+2*rayon-marge, y+3*marge);
+      } else {
+        g.setColor(couleur);
+        int x1[]=new int[]{x + marge,x + marge + rayon,x + marge + 2 *rayon,x+marge};
+        int y1[]=new int[]{y + marge+ 2 * rayon,y+marge,y + marge+ 2 * rayon, y + marge+ 2 * rayon};
+        g.fillPolygon(x1,y1,4);
+        g.setColor(Color.BLACK);
+        g.drawPolygon(x1, y1, 4);
+      }
+    }
+    public int getIconWidth() {
+      return 2*rayon+2*marge;
+    }
+    public int getIconHeight() {
+      return 2*rayon+2*marge;
+    }
+    public int getRayon(){
+        return rayon;
+    }
+    public int getMarge(){
+        return marge;
+    }
+    public Color getColor(){
+        return couleur;
+    }
+  }
+  
+    public static class TriangleinverseCouleurIcone implements Icon {
+    private Color couleur;
+    int rayon;
+    int marge;
+    public TriangleinverseCouleurIcone(Color couleur, int rayon, int marge) {
+      this.couleur = couleur;
+      this.rayon = rayon;
+      this.marge = marge;
+    }
+    public void paintIcon(Component c, Graphics g, int x, int y) {
+      if (couleur==null) {
+        g.setColor(Color.BLACK);
+        g.drawLine(x+3*marge, y+3*marge, x+2*rayon-marge, y+2*rayon-marge);
+        g.drawLine(x+3*marge, y+2*rayon-marge, x+2*rayon-marge, y+3*marge);
+      } else {
+        g.setColor(couleur);
+        int x1[]=new int[]{x + marge,x + marge + 2 * rayon,x + marge + rayon,x+marge};
+        int y1[]=new int[]{y + marge,y+marge,y + marge+ 2 * rayon, y + marge};
+        g.fillPolygon(x1,y1,4);
+        g.setColor(Color.BLACK);
+        g.drawPolygon(x1, y1, 4);
+      }
+    }
+    public int getIconWidth() {
+      return 2*rayon+2*marge;
+    }
+    public int getIconHeight() {
+      return 2*rayon+2*marge;
+    }
+    public int getRayon(){
+        return rayon;
+    }
+    public int getMarge(){
+        return marge;
+    }
+    public Color getColor(){
+        return couleur;
+    }
+  }
+  
+  
+  public static class LegendeLabel {
+    String texte;
+    String textelegende;
+    Icon icone;
+    public LegendeLabel(String texte,String textelegende){
+        this.texte = texte;
+        this.textelegende = textelegende;
+    }
+    public LegendeLabel(String texte, Color couleur) {
+      this.texte = texte;
+      this.icone = new DisqueCouleurIcone(couleur, 12, 2);
+    }
+    public LegendeLabel(String texte, Color couleur, int taille, int forme, int rayon , int marge) {
+      this.texte = texte;
+      if(taille!=-1 && forme !=-1){
+              switch(forme){
+            case 0 :
+                this.icone = new DisqueCouleurIcone(couleur, rayon / taille
+                        , marge);
+                break;
+            case 1 :
+                this.icone = new CarreCouleurIcone(couleur, rayon / taille
+                        , marge);
+                break;
+            case 2 :
+                this.icone = new CroixCouleurIcone(couleur, rayon / taille
+                        , marge);
+                break;
+            case 3 :
+                this.icone = new TriangleCouleurIcone(couleur, rayon / taille
+                        , marge);
+                break;
+            default :
+                this.icone = new TriangleinverseCouleurIcone(couleur, rayon / taille
+                        , marge);
+                break;
+        }
+      }
+      else{
+                        switch(forme){
+            case 0 :
+                this.icone = new DisqueCouleurIcone(null, 12
+                        , 2);
+                break;
+            case 1 :
+                this.icone = new CarreCouleurIcone(null, 12
+                        , 2);
+                break;
+            case 2 :
+                this.icone = new CroixCouleurIcone(null, 12
+                        , 2);
+                break;
+            case 3 :
+                this.icone = new TriangleCouleurIcone(null, 12
+                        , 2);
+                break;
+            default :
+                this.icone = new TriangleinverseCouleurIcone(null, 12
+                        , 2);
+                break;
+      }
+    }    
+    }
+  }
+
+  public static class LegendeCellRenderer extends JLabel implements ListCellRenderer {
+    public LegendeCellRenderer() {
+      setIconTextGap(12);
+    }
+    public Component getListCellRendererComponent(JList list, Object value,
+            int index, boolean isSelected, boolean cellHasFocus) {
+      LegendeLabel label = (LegendeLabel) value;
+      setText(label.texte);
+      setIcon(label.icone);
+      return this;
+    }
+  }
+  /*Modèle pour le tableau de la légende avec icone*/
+  public static class LegendeModeleTable extends AbstractTableModel{
+      private Object[][] donnees = new Object[0][0];
+      private String[] entetes = new String[0];
+          	@Override
+	public int getColumnCount() {
+		return entetes.length;
+        }
+        @Override
+	public String getColumnName(int columnIndex) {
+		return entetes[columnIndex];
+	}
+        public LegendeModeleTable(){
+        }
+        public LegendeModeleTable(String[] titres, LegendeLabel[] legende, HashMap<String, Float> freq){
+                        this.entetes = titres;
+            this.donnees = new Object[legende.length][freq==null ? 2 : 3];
+            for(int i = 0;i < legende.length;i++){
+                donnees[i][0] = legende[i].icone;
+                donnees[i][1] = legende[i].texte;
+                if(freq!=null){
+                donnees[i][2] = freq.get(legende[i].texte);
+                }
+            }
+        }        
+        public int getRowCount() {
+		return donnees.length;
+	}
+
+	@Override
+	public Object getValueAt(int rowIndex, int columnIndex) {
+		return donnees[rowIndex][columnIndex];
+	}
+        @Override
+        public Class getColumnClass(int columnIndex){
+            switch(columnIndex){
+                case 0 :
+                    return Icon.class;
+                case 2:
+                    return Float.class;
+                default:
+                    return String.class;
+            }
+        }
+        public void setLegendeModele(String[] titres, LegendeLabel[] legende, HashMap<String, Float> freq){
+            this.entetes = titres;
+            this.donnees = new Object[legende.length][3];
+            for(int i = 0;i < legende.length;i++){
+                donnees[i][0] = legende[i].icone;
+                donnees[i][1] = legende[i].texte;
+                donnees[i][2] = freq.get(legende[i].texte);
+            }
+        }
+  }
+  /*Modèle pour le tableau de la légende sans icone*/
+    public static class LegendeModeleTableTexte extends AbstractTableModel{
+      private Object[][] donnees = new Object[0][0];
+      private String[] entetes = new String[0];
+          	@Override
+	public int getColumnCount() {
+		return entetes.length;
+        }
+        @Override
+	public String getColumnName(int columnIndex) {
+		return entetes[columnIndex];
+	}
+        public LegendeModeleTableTexte(){
+        }
+        public LegendeModeleTableTexte(String[] titres, LegendeLabel[] legende, HashMap<String, Float> freq){
+                        this.entetes = titres;
+            this.donnees = new Object[legende.length][freq==null ? 2 : 3];
+            for(int i = 0;i < legende.length;i++){
+                donnees[i][0] = legende[i].textelegende;
+                donnees[i][1] = legende[i].texte;
+                if(freq!=null){
+                donnees[i][2] = freq.get(legende[i].texte);
+                }
+            }
+        }        
+        public int getRowCount() {
+		return donnees.length;
+	}
+
+	@Override
+	public Object getValueAt(int rowIndex, int columnIndex) {
+		return donnees[rowIndex][columnIndex];
+	}
+        @Override
+        public Class getColumnClass(int columnIndex){
+            switch(columnIndex){
+                case 0 :
+                    return String.class;
+                case 2:
+                    return Float.class;
+                default:
+                    return String.class;
+            }
+        }
+        public void setLegendeModele(String[] titres, LegendeLabel[] legende, HashMap<String, Float> freq){
+            this.entetes = titres;
+            this.donnees = new Object[legende.length][3];
+            for(int i = 0;i < legende.length;i++){
+                donnees[i][0] = legende[i].textelegende;
+                donnees[i][1] = legende[i].texte;
+                donnees[i][2] = freq.get(legende[i].texte);
+            }
+        }
+  }
+  
+  
+  
+
+  public static class RectangleCouleurIcone implements Icon {
+    private Color couleur;
+    private int largeur;
+    private int hauteur;
+    private int marge;
+    private boolean select;
+    public RectangleCouleurIcone(Color couleur, int largeur, int hauteur, int marge, boolean select) {
+      this.couleur = couleur;
+      this.largeur = largeur;
+      this.hauteur = hauteur;
+      this.marge = marge;
+      this.select = select;
+    }
+    void setCouleur(Color c) {
+      couleur = c;
+    }
+    public void paintIcon(Component c, Graphics g, int x, int y) {
+      g.setColor(couleur);
+      g.fillRect(x+marge, y+marge, largeur, hauteur);
+      if (select) {
+        g.setColor(Color.BLACK);
+        g.drawRect(x+marge, y+marge, largeur, hauteur);
+      }
+    }
+    public int getIconWidth() {
+      return largeur+2*marge;
+    }
+    public int getIconHeight() {
+      return hauteur+2*marge;
+    }
+  }
+
+  public static class CouleurCellRenderer extends JLabel implements ListCellRenderer, TableCellRenderer {
+    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
+            boolean cellHasFocus) {
+      if (index==list.getModel().getSize()-1||index<0) {
+        setText(index<0 ? "" : styleDef("autre"));
+        setIcon(null);
+      } else {
+        setText(null);
+        setIcon(new RectangleCouleurIcone((Color) value, 40, 10, 2, isSelected));
+      }
+      return this;
+    }
+    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+      setText(null);
+      setIcon(new RectangleCouleurIcone((Color) value, 80, 10, 2, true));
+      return this;
+    }
+  }
+
+  public static class CouleurComboBoxEditor implements ComboBoxEditor {
+    CouleurComboBox comboBox;
+    RectangleCouleurIcone icone;
+    JLabel editeur;
+    Color couleur;
+    public CouleurComboBoxEditor(CouleurComboBox cb) {
+      comboBox = cb;
+      editeur = new JLabel(icone = new RectangleCouleurIcone(null, 80, 10, 2, true));
+    }
+    public Component getEditorComponent() {
+      return editeur;
+    }
+    private void init(Color couleur) {
+      this.couleur = couleur;
+      icone.setCouleur(couleur);
+    }
+    public void setItem(Object anObject) {
+      if (anObject==null) {
+        Color c = JColorChooser.showDialog(editeur, "Choix de la couleur", couleur);
+        if (c!=null) couleur = c;
+      } else couleur = (Color) anObject;
+      icone.setCouleur(couleur);
+      comboBox.setSelectedItem(couleur);
+    }
+    public Object getItem() {
+      return couleur;
+    }
+    public void selectAll() {
+    }
+    public void addActionListener(ActionListener l) {
+    }
+    public void removeActionListener(ActionListener l) {
+    }
+  }
+
+  public static class CouleurComboBox extends JComboBox {
+    public CouleurComboBox(Color[] couleurs) {
+      super(couleurs);
+      addItem(null);
+      setRenderer(new CouleurCellRenderer());
+      setEditor(new CouleurComboBoxEditor(this));
+      setMaximumRowCount(couleurs.length+1);
+    }
+  }
+
+  public static class CouleurTableEditor extends AbstractCellEditor implements TableCellEditor, ActionListener {
+    private CouleurComboBox comboBox;
+    private Color couleur;
+    public CouleurTableEditor(Color[] couleurs) {
+      comboBox = new CouleurComboBox(couleurs);
+      comboBox.setEditable(true);
+      comboBox.addActionListener(this);
+    }
+    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
+      couleur = (Color) value;
+      comboBox.getEditor().setItem(value);
+      return comboBox;
+    }
+    public Object getCellEditorValue() {
+      return couleur;
+    }
+    public void actionPerformed(ActionEvent e) {
+      couleur = (Color) comboBox.getSelectedItem();
+      fireEditingStopped();
+    }
+  }
+  //fonctiontrès grossière mais si quelqu'un réussit à obtenir un charactère à partir  de son code ascci ou unicode
+  //quelque soit la machine, il devra remplacer cette fonction 
+
+    public static char intToChar(int value){
+        switch(value){
+            case 0:
+                return '0';
+            case 1:
+                return '1';
+            case 2:
+                return '2';
+            case 3:
+                return '3';
+            case 4:
+                return '4';
+            case 5:
+                return '5';
+            case 6: 
+                return '6';
+            case 7:
+                return '7';
+            case 8 :
+                return '8';
+            case 9 :
+                return '9'; 
+            case 10 :
+                return 'a';
+            case 11 :
+                return 'b';
+            case 12 :
+                return 'c';
+            case 13 :
+                return 'd';
+            case 14 :
+                return 'e';
+            case 15 :
+                return 'f';
+            case 16 :
+                return 'g';
+            case 17 :
+                return 'h';
+            case 18 :
+                return 'i';
+            case 19 :
+                return 'j';
+            case 20 :
+                return 'k';
+            case 21 :
+                return 'l';
+            case 22 :
+                return 'm';
+            case 23 :
+                return 'n';
+            case 24 :
+                return 'o';
+            case 25 :
+                return 'p';
+            case 26 :
+                return 'q';
+            case 27 :
+                return 'r';
+            case 28 :
+                return 's';
+            case 29 :
+                return 't';
+            case 30 :
+                return 'u';
+            case 31 :
+                return 'v';
+            case 32 :
+                return 'w';
+            case 33 :
+                return 'x';
+            case 34 :
+                return 'y';
+            case 35 :
+                return 'z';
+            case 36 :
+                return 'A';
+            case 37 : 
+                return 'B';
+            case 38 :
+                return 'C';
+            case 39 :
+                return 'D';           
+            case 40 :
+                return 'E';
+            case 41 :
+                return 'F';              
+            case 42 :
+                return 'G';                
+            case 43 :
+                return 'H';               
+            case 44 :
+                return 'I';
+            case 45 :
+                return 'J';               
+            case 46 :
+                return 'K';               
+            case 47 :
+                return 'L';              
+            case 48 :
+                return 'M';              
+            case 49 :
+                return 'N';                
+            case 50 :
+                return 'O';                
+            case 51 :
+                return 'P';                
+            case 52 :
+                return 'Q';               
+            case 53 :
+                return 'R';               
+            case 54 :
+                return 'S';               
+            case 55 :
+                return 'T';
+            case 56 :
+                return 'U';
+            case 57 :
+                return 'V';                
+            case 58 :
+                return 'W';               
+            case 59 :
+                return 'X';               
+            case 60 :
+                return 'Y';               
+            case 61 :
+                return 'Z';             
+            default : 
+                return '?';
+        }
+        
+    }
+    public static int CharToInt(char value){
+        switch(value){
+            case '0':
+                return 0;
+            case '1':
+                return 1;
+            case '2':
+                return 2;
+            case '3':
+                return 3;
+            case '4':
+                return 4;
+            case '5':
+                return 5;
+            case '6': 
+                return 6;
+            case '7':
+                return 7;
+            case '8' :
+                return 8;
+            case '9' :
+                return 9; 
+            case 'a' :
+                return 10;
+            case 'b' :
+                return 11;
+            case 'c':
+                return 12;
+            case 'd' :
+                return 13;
+            case 'e' :
+                return 14;
+            case 'f' :
+                return 15;
+            case 'g' :
+                return 16;
+            case 'h' :
+                return 17;
+            case 'i' :
+                return 18;
+            case 'j':
+                return 19;
+            case 'k' :
+                return 20;
+            case 'l' :
+                return 21;
+            case 'm' :
+                return 22;
+            case 'n' :
+                return 23;
+            case 'o' :
+                return 24;
+            case 'p' :
+                return 25;
+            case 'q' :
+                return 26;
+            case 'r' :
+                return 27;
+            case 's' :
+                return 28;
+            case 't' :
+                return 29;
+            case 'u' :
+                return 30;
+            case 'v' :
+                return 31;
+            case 'w':
+                return 32;
+            case 'x' :
+                return 33;
+            case 'y' :
+                return 34;
+            case 'z' :
+                return 35;
+            case 'A' :
+                return 36;
+            case 'B' : 
+                return 37;
+            case 'C' :
+                return 38;
+            case 'D' :
+                return 39;           
+            case 'E' :
+                return 40;
+            case 'F' :
+                return 41;              
+            case 'G' :
+                return 42;                
+            case 'H' :
+                return 43;               
+            case 'I' :
+                return 44;
+            case 'J' :
+                return 45;               
+            case 'K' :
+                return 46;               
+            case 'L' :
+                return 47;              
+            case 'M' :
+                return 48;              
+            case 'N' :
+                return 49;                
+            case 'O' :
+                return 50;                
+            case 'P' :
+                return 51;                
+            case 'Q' :
+                return 52;               
+            case 'R' :
+                return 53;               
+            case 'S' :
+                return 54;               
+            case 'T' :
+                return 55;
+            case 'U' :
+                return 56;
+            case 'V' :
+                return 57;                
+            case 'W' :
+                return 58;               
+            case 'X' :
+                return 59;               
+            case 'Y' :
+                return 60;               
+            case 'Z' :
+                return 61;             
+            default : 
+                return -1;
+        }
+        
+    }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/GVisu.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/GMessages.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/GMessages.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/GMessages.java	(revision 3653)
@@ -0,0 +1,116 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.util;
+
+import java.awt.event.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class GMessages {
+	
+	public static boolean confirmationAction(String texte) {
+		return (JOptionPane.showConfirmDialog(null, texte, "Confirmation d'action",
+				JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) != JOptionPane.CANCEL_OPTION);
+	}
+	
+	public static void pasImplemente() {
+		JOptionPane.showMessageDialog(null, "Désolé, cette fonctionnalité n'est pas encore implémentée",
+				"Patience...", JOptionPane.INFORMATION_MESSAGE);
+		return;
+	}
+	
+	public static void impossibiliteAction(String texte) {
+		JOptionPane.showMessageDialog(null, texte,
+				"Désolé...", JOptionPane.INFORMATION_MESSAGE);
+		return;
+	}
+	
+	public static void erreurFatale(Throwable ex) {
+		String message = "<center><b>Désolé pour ce bug... Vous allez devoir relancer Analec.</b></center>"
+				+ "<i><br>Veuillez recopier  le message d'erreur ci-dessous et l'envoyer au concepteur du logiciel"
+				+ " <br>en précisant les conditions dans lequel ce bug s'est produit</i>";
+		String erreur = "<p>" + ex.toString();
+		ex.printStackTrace();
+		for (StackTraceElement tr : ex.getStackTrace())
+			if (tr.getClassName().startsWith("visuAnalec") || tr.getClassName().startsWith("JamaPlus"))
+				erreur += "<br>" + tr.getClassName() + " : " + tr.getMethodName() + " ligne " + tr.getLineNumber();
+		JEditorPane dialogue = new JEditorPane("text/html", message + erreur);
+		JOptionPane.showMessageDialog(null, dialogue, "Oups !", JOptionPane.ERROR_MESSAGE);
+		// System.exit(1);
+	}
+	
+	public abstract static class GAction extends AbstractAction {
+		
+		/**
+		 * 
+		 */
+		private static final long serialVersionUID = 1L;
+		
+		public GAction(String nom) {
+			super(nom);
+		}
+		
+		public GAction(String nom, Icon icone) {
+			super(nom, icone);
+		}
+		
+		public abstract void executer();
+		
+		@Override
+		public void actionPerformed(ActionEvent evt) {
+			try {
+				executer();
+			}
+			catch (Throwable ex) {
+				erreurFatale(ex);
+			}
+		}
+	}
+	
+	public abstract static class GActionClavier extends GAction {
+		
+		public GActionClavier(JComponent composant, String nom, String... touches) {
+			super(nom);
+			for (String touche : touches) {
+				composant.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
+						KeyStroke.getKeyStroke(touche), nom);
+			}
+			composant.getActionMap().put(nom, this);
+		}
+	}
+	
+	public static class GProgression extends ProgressMonitor {
+		
+		private int compteur;
+		
+		private String elementsTraites;
+		
+		public GProgression(int max, String traitement, String elementsTraites) {
+			super(null, traitement + " en cours", "Démarrage", 0, max);
+			this.elementsTraites = elementsTraites;
+			// setMillisToPopup(0);
+			compteur = 0;
+		}
+		
+		public void setNbTraites(int nb) {
+			compteur = nb;
+			SwingUtilities.invokeLater(new MiseAJour());
+		}
+		
+		class MiseAJour implements Runnable {
+			
+			@Override
+			public void run() {
+				setProgress(compteur);
+				setNote(compteur + " " + elementsTraites + " traités");
+			}
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/util/GMessages.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauCommandesRelations.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauCommandesRelations.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauCommandesRelations.java	(revision 3653)
@@ -0,0 +1,756 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.ArrayList;
+import javax.swing.*;
+import visuAnalec.Message.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.elements.*;
+import visuAnalec.texte.*;
+import visuAnalec.texte.PanneauAffTexte.*;
+import visuAnalec.texte.PanneauTexte.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class PanneauCommandesRelations extends PanneauCommandes implements ActionListener {
+  private PanneauChamps panneauChamps;
+  private TypeComboBox saisieTypeRelations;
+  private ElementComboBox saisieRelation;
+  private TypeComboBox saisieTypeElt1;
+  private ElementComboBox saisieElt1;
+  private TypeComboBox saisieTypeElt2;
+  private ElementComboBox saisieElt2;
+  private JButton creeRelation;
+  private JButton supprimeRelation;
+  private JButton creeUniteElt1;
+  private JButton creeUniteElt2;
+  private boolean uniteCreeElt1 = true; // pour la création d'unités en cours de route
+  private int[] bornesSelectTexte;
+  /*
+  
+   * CREATION PAR LE PANNEAU EDITEUR
+   */
+  PanneauCommandesRelations(Vue vue, PanneauAffTexte pTexte, PanneauChamps pChamps) {
+    super(vue, pTexte);
+    JToolBar barre1 = new JToolBar();
+    barre1.setPreferredSize(new Dimension(0, 22));
+    barre1.setAlignmentX(0.0f);
+    //    barre1.setFloatable(false);
+    add(barre1);
+    JToolBar barre2 = new JToolBar();
+//    barre2.setBackground(PanneauTexte.getCouleurFond2());
+    barre2.setPreferredSize(new Dimension(0, 22));
+    barre2.setAlignmentX(0.0f);
+//     barre2.setFloatable(false);
+    add(barre2);
+    JToolBar barre3 = new JToolBar();
+    barre3.setPreferredSize(new Dimension(0, 22));
+    barre3.setAlignmentX(0.0f);
+//    barre3.setBackground(PanneauTexte.getCouleurFond2());
+//     barre3.setFloatable(false);
+    add(barre3);
+
+    panneauChamps = pChamps;
+    saisieTypeRelations = new TypeComboBox(Relation.class);
+    saisieTypeRelations.addActionListener(this);
+    saisieRelation = new ElementComboBox();
+    saisieRelation.addActionListener(this);
+    saisieTypeElt1 = new TypeComboBox(Element.class);
+    saisieTypeElt1.addActionListener(this);
+    saisieElt1 = new ElementComboBox();
+    saisieElt1.addActionListener(this);
+    saisieTypeElt2 = new TypeComboBox(Element.class);
+    saisieTypeElt2.addActionListener(this);
+    saisieElt2 = new ElementComboBox();
+    saisieElt2.addActionListener(this);
+    creeRelation = new JButton(new GAction("Créer") {
+      public void executer() {
+        creerRelation();
+      }
+    });
+    supprimeRelation = new JButton(new GAction("Supprimer") {
+      public void executer() {
+        supprimerRelation();
+      }
+    });
+    creeUniteElt1 = new JButton(new GAction("Créer") {
+      public void executer() {
+        creerUniteElt1();
+      }
+    });
+    creeUniteElt2 = new JButton(new GAction("Créer") {
+      public void executer() {
+        creerUniteElt2();
+      }
+    });
+    barre1.addSeparator();
+    barre1.add(new TitreBarre("  Relation :  ", PanneauTexte.getCouleurFond1()));
+    barre1.addSeparator();
+    barre1.add(saisieTypeRelations);
+    barre1.add(saisieRelation);
+    barre1.addSeparator();
+    barre1.add(creeRelation);
+    barre1.addSeparator();
+    barre1.add(supprimeRelation);
+    barre2.addSeparator();
+    barre2.add(new TitreBarre("Elément 1 : ", PanneauTexte.getCouleurFond2()));
+    barre2.addSeparator();
+    barre2.add(saisieTypeElt1);
+    barre2.add(saisieElt1);
+    barre2.addSeparator();
+    barre2.add(creeUniteElt1);
+    barre3.addSeparator();
+    barre3.add(new TitreBarre("Elément 2 : ", PanneauTexte.getCouleurFond3()));
+    barre3.addSeparator();
+    barre3.add(saisieTypeElt2);
+    barre3.add(saisieElt2);
+    barre3.addSeparator();
+    barre3.add(creeUniteElt2);
+  }
+
+  /*
+   * COMMANDES UTILISEES PAR LE PANNEAU EDITEUR
+   */
+  public void reinitialiser() {
+    // typiquement, appelé par le panneau éditeur à la suite d'une modif de vue ou de structure
+    saisieTypeRelations.removeActionListener(this);
+    saisieTypeRelations.setModele(vue.getTypesRelationsAVoir());
+    saisieTypeRelations.effSelection();
+    saisieTypeRelations.addActionListener(this);
+    saisieTypeElt1.removeActionListener(this);
+    saisieTypeElt1.setModele(vue.getTypes(Unite.class), vue.getTypes(Relation.class), vue.getTypes(Schema.class));
+    saisieTypeElt1.effSelection();
+    saisieTypeElt1.addActionListener(this);
+    saisieTypeElt2.removeActionListener(this);
+    saisieTypeElt2.setModele(vue.getTypes(Unite.class), vue.getTypes(Relation.class), vue.getTypes(Schema.class));
+    saisieTypeElt2.effSelection();
+    saisieTypeElt2.addActionListener(this);
+    initSaisieRelation();
+    initSaisieElt1();
+    initSaisieElt2();
+    etatSelectRien();
+    revalidate();
+    repaint();
+  }
+  public void reafficher() {
+    // potentiellement appelé par le panneau éditeur ?
+    // appelé aussi par  traiterElementEvent
+    if (saisieRelation.pasdeSelection()) {
+      initSaisieRelation();
+      if (saisieElt1.pasdeSelection()) {
+        initSaisieElt1();
+        if (saisieElt2.pasdeSelection()) {
+          initSaisieElt2();
+          etatSelectRien();
+        } else {
+          Element elt2Courant = saisieElt2.getSelection();
+          initSaisieElt2(elt2Courant);
+          etatSelectElt2(elt2Courant);
+        }
+      } else {
+        Element elt1Courant = saisieElt1.getSelection();
+        initSaisieElt1(elt1Courant);
+        if (saisieElt2.pasdeSelection()) {
+          initSaisieElt2();
+          etatSelectElt1(elt1Courant);
+
+        } else {
+          Element elt2Courant = saisieElt2.getSelection();
+          initSaisieElt2(elt2Courant);
+          etatSelectElts(elt1Courant, elt2Courant);
+        }
+      }
+    } else {
+      Relation relCourant = (Relation) saisieRelation.getSelection();
+      initSaisieRelation(relCourant);
+      initSaisieElt1(relCourant.getElt1());
+      initSaisieElt2(relCourant.getElt2());
+      etatSelectRel(relCourant);
+    }
+  }
+  public void elementSuivant(int sens) {
+    if (sens>0) saisieRelation.gotoSuivant();
+    else saisieRelation.gotoPrecedent();
+  }
+ public Element elementSelectionne() {
+    if (saisieRelation.pasdeSelection()) return null;
+    return saisieRelation.getSelection();
+  }
+  public void editerElement(Element elt) {
+    // appelé par le panneauEditeur : elt est forcément une relation
+    if (elt.getClass()!=Relation.class)
+      throw new UnsupportedOperationException("Erreur : classe incorrecte");
+    editerRelation((Relation) elt);
+  }
+  public void traiterElementEvent(ElementEvent evt) {
+    switch (evt.getModif()) {
+      case AJOUT_RELATION:
+        Relation rel = (Relation) evt.getElement();
+        editerRelation(rel);
+        return;
+      case SUP_RELATION:
+        if (evt.getElement()==saisieRelation.getSelection()) {
+          initSaisieRelation();
+          initSaisieElt1();
+          initSaisieElt2();
+          etatSelectRien();
+        } else {
+          reafficher();
+        }
+        return;
+      case AJOUT_UNITE:
+        Unite unit = (Unite) evt.getElement();
+        boolean chgEtat = false;
+        if (!saisieTypeElt1.pasdeSelection()&&saisieTypeElt1.getClasseSelection()==Unite.class
+                &&saisieTypeElt1.getTypeSelection().equals(unit.getType())) {
+          initSaisieElt1(uniteCreeElt1 ? unit : null);
+          chgEtat = true;
+        }
+        if (!saisieTypeElt2.pasdeSelection()&&saisieTypeElt2.getClasseSelection()==Unite.class
+                &&saisieTypeElt2.getTypeSelection().equals(unit.getType())) {
+          initSaisieElt2(uniteCreeElt1 ? null : unit);
+          chgEtat = true;
+        }
+        if (chgEtat) {
+          if (uniteCreeElt1) etatSelectElt1(unit);
+          else etatSelectElt2(unit);
+          uniteCreeElt1 = true;
+        }
+        return;
+      case SUP_UNITE:
+      case BORNES_UNITE:
+      case AJOUT_SCHEMA:
+      case MODIF_SCHEMA:
+      case SUP_SCHEMA:
+      case MODIF_VALEUR:
+        reafficher();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getModif()+" oublié dans un switch");
+    }
+  }
+  public void editerRelation(Relation rel) {
+    // appelé  par traiterElementEvent, 
+    // et aussi directement par le panneau éditeur quand il est sollicité par d'autres fenêtres
+    if (!rel.getType().equals(saisieTypeRelations.getTypeSelection())) {
+      saisieTypeRelations.removeActionListener(this);
+      saisieTypeRelations.setSelection(rel.getType());
+      saisieTypeRelations.addActionListener(this);
+    }
+    initSaisieRelation(rel);
+    saisieRelation.setSelection(rel);
+  }
+  public ArrayList<ElementMarque> trouverElementsVises(Unite uniteVisee, TypeMarquage marqueUniteVisee,
+          boolean avecId) {
+    ArrayList<ElementMarque> eltsMarques = new ArrayList<ElementMarque>();
+    ArrayList<Element> eltsVises;
+    Element eltVise;
+    switch (marqueUniteVisee) {
+      case FOND1:
+        eltsVises = Element.trouverElementsParUniteSousjacente(saisieRelation.getElements(), uniteVisee);
+        for (Element elt : eltsVises)
+          eltsMarques.add(new ElementMarque(
+                  elt, marqueUniteVisee, avecId ? saisieRelation.getIdElement(elt) : null));
+        return eltsMarques;
+      case FOND2:
+        eltsVises = Element.trouverElementsParUniteSousjacente(saisieElt1.getElements(), uniteVisee);
+        for (Element elt : eltsVises)
+          eltsMarques.add(new ElementMarque(
+                  elt, marqueUniteVisee, avecId ? saisieElt1.getIdElement(elt) : null));
+        return eltsMarques;
+      case FOND3:
+        eltsVises = Element.trouverElementsParUniteSousjacente(saisieElt2.getElements(), uniteVisee);
+        for (Element elt : eltsVises)
+          eltsMarques.add(new ElementMarque(
+                  elt, marqueUniteVisee, avecId ? saisieElt2.getIdElement(elt) : null));
+        return eltsMarques;
+      case SELECT2:
+      case SELECT1_2:
+        eltVise = saisieElt1.getSelection();
+        eltsMarques.add(new ElementMarque(
+                eltVise, marqueUniteVisee, avecId ? saisieElt1.getIdElement(eltVise) : null));
+        return eltsMarques;
+      case SELECT3:
+      case SELECT1_3:
+        eltVise = saisieElt2.getSelection();
+        eltsMarques.add(new ElementMarque(
+                eltVise, marqueUniteVisee, avecId ? saisieElt2.getIdElement(eltVise) : null));
+        return eltsMarques;
+      default:
+        throw new UnsupportedOperationException("Marquage non prévu : "+marqueUniteVisee);
+
+    }
+  }
+
+  /*
+   * ACTIONS DE L'UTILISATEUR : CHANGEMENTS D'ETAT
+   */
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource()==saisieTypeRelations) {
+        initSaisieRelation();
+        if (saisieElt1.pasdeSelection()) {
+          if (saisieElt2.pasdeSelection()) etatSelectRien();
+          else etatSelectElt2(saisieElt2.getSelection());
+        } else {
+          if (saisieElt2.pasdeSelection())
+            etatSelectElt1(saisieElt1.getSelection());
+          else
+            checkEtatSelectElts(saisieElt1.getSelection(), saisieElt2.getSelection());
+        }
+        return;
+      }
+      if (evt.getSource()==saisieTypeElt1) {
+        forceEffSelectRel();
+        initSaisieElt1();
+        if (saisieElt2.pasdeSelection()) etatSelectRien();
+        else etatSelectElt2(saisieElt2.getSelection());
+        return;
+      }
+      if (evt.getSource()==saisieTypeElt2) {
+        forceEffSelectRel();
+        initSaisieElt2();
+        if (saisieElt1.pasdeSelection()) etatSelectRien();
+        else etatSelectElt1(saisieElt1.getSelection());
+        return;
+      }
+      if (evt.getSource()==saisieRelation) {
+        if (saisieRelation.pasdeSelection()) {
+          if (saisieElt1.pasdeSelection()) {
+            if (saisieElt2.pasdeSelection()) etatSelectRien();
+            else etatSelectElt2(saisieElt2.getSelection());
+          } else {
+            if (saisieElt2.pasdeSelection())
+              etatSelectElt1(saisieElt1.getSelection());
+            else
+              etatSelectElts(saisieElt1.getSelection(), saisieElt2.getSelection());
+          }
+        } else {
+          forceEtatSelectRel((Relation) saisieRelation.getSelection());
+        }
+        return;
+      }
+      if (evt.getSource()==saisieElt1) {
+        if (!saisieRelation.pasdeSelection()) {
+          saisieRelation.removeActionListener(this);
+          saisieRelation.effSelection();
+          saisieRelation.addActionListener(this);
+          saisieElt2.removeActionListener(this);
+          saisieElt2.effSelection();
+          saisieElt2.addActionListener(this);
+        }
+        if (saisieElt1.pasdeSelection()) {
+          if (saisieElt2.pasdeSelection()) etatSelectRien();
+          else etatSelectElt2(saisieElt2.getSelection());
+        } else {
+          if (saisieElt2.pasdeSelection())
+            etatSelectElt1(saisieElt1.getSelection());
+          else
+            checkEtatSelectElts(saisieElt1.getSelection(), saisieElt2.getSelection());
+        }
+        return;
+      }
+      if (evt.getSource()==saisieElt2) {
+        if (!saisieRelation.pasdeSelection()) {
+          saisieRelation.removeActionListener(this);
+          saisieRelation.effSelection();
+          saisieRelation.addActionListener(this);
+          saisieElt1.removeActionListener(this);
+          saisieElt1.effSelection();
+          saisieElt1.addActionListener(this);
+        }
+        if (saisieElt2.pasdeSelection()) {
+          if (saisieElt1.pasdeSelection()) etatSelectRien();
+          else etatSelectElt1(saisieElt1.getSelection());
+        } else {
+          if (saisieElt1.pasdeSelection())
+            etatSelectElt2(saisieElt2.getSelection());
+          else
+            checkEtatSelectElts(saisieElt1.getSelection(), saisieElt2.getSelection());
+        }
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  @Override
+  public void traiterSourisEvent(SourisEvent evt) {
+    switch (evt.getTypeEvent()) {
+      case SELECT_RIEN:
+        saisieElt1.removeActionListener(this);
+        saisieElt1.effSelection();
+        saisieElt1.addActionListener(this);
+        saisieElt2.removeActionListener(this);
+        saisieElt2.effSelection();
+        saisieElt2.addActionListener(this);
+        saisieRelation.removeActionListener(this);
+        saisieRelation.effSelection();
+        saisieRelation.addActionListener(this);
+        etatSelectRien();
+        return;
+      case SELECT_ELEMENT:
+        switch (evt.getMarquageElementVise()) {
+          case FOND1:
+            saisieRelation.setSelection(evt.getElementVise());
+            return;
+          case FOND2:
+            saisieElt1.setSelection(evt.getElementVise());
+            return;
+          case FOND3:
+            saisieElt2.setSelection(evt.getElementVise());
+            return;
+          case SELECT2:
+          case SELECT1_2:
+            forceEffSelectElt2();
+            return;
+          case SELECT3:
+          case SELECT1_3:
+            forceEffSelectElt1();
+            return;
+        }
+        return;
+      case SELECT_TEXTE:
+        if (!saisieElt1.pasdeSelection()&&!saisieElt2.pasdeSelection()) {
+          saisieElt1.removeActionListener(this);
+          saisieElt1.effSelection();
+          saisieElt1.addActionListener(this);
+          saisieElt2.removeActionListener(this);
+          saisieElt2.effSelection();
+          saisieElt2.addActionListener(this);
+          saisieRelation.removeActionListener(this);
+          saisieRelation.effSelection();
+          saisieRelation.addActionListener(this);
+        }
+        bornesSelectTexte = evt.getBornesSelectionTexte();
+        etatSelectTexte();
+        return;
+    }
+    throw new UnsupportedOperationException("Evénement non prévu : "+evt.getTypeEvent());
+  }
+  /*
+   * ACTIONS DE L'UTILISATEUR : BOUTONS
+   */
+  private void creerRelation() {
+    vue.getCorpus().addRelationSaisie((String) saisieTypeRelations.getTypeSelection(),
+            saisieElt1.getSelection(), saisieElt2.getSelection());
+  }
+  private void supprimerRelation() {
+    if (!GMessages.confirmationAction("Supprimer la relation sélectionnée ?"))
+      return;
+    vue.getCorpus().supRelation((Relation) saisieRelation.getSelection());
+  }
+  private void creerUniteElt1() {
+    if (vue.getCorpus().checkPresenceUnite(saisieTypeElt1.getTypeSelection(), bornesSelectTexte[0], bornesSelectTexte[1])
+            &&!GMessages.confirmationAction("Dupliquer cette unité  ?")) return;
+    uniteCreeElt1 = true;
+    vue.getCorpus().addUniteSaisie(saisieTypeElt1.getTypeSelection(), bornesSelectTexte[0], bornesSelectTexte[1]);
+  }
+  private void creerUniteElt2() {
+    if (vue.getCorpus().checkPresenceUnite(saisieTypeElt2.getTypeSelection(), bornesSelectTexte[0], bornesSelectTexte[1])
+            &&!GMessages.confirmationAction("Dupliquer cette unité  ?")) return;
+    uniteCreeElt1 = false;
+    vue.getCorpus().addUniteSaisie(saisieTypeElt2.getTypeSelection(), bornesSelectTexte[0], bornesSelectTexte[1]);
+  }
+
+  /* 
+   * GESTION INTERNE
+   */
+  private void etatSelectRien() {   // rien n'est sélectionné
+    if (saisieTypeRelations.pasdeSelection()) {
+      if (saisieTypeElt1.pasdeSelection()) {
+        if (saisieTypeElt2.pasdeSelection()) panneauTexte.pasDeMarquage();
+        else
+          panneauTexte.saisir(null,
+                  Element.getUnitesSousjacentes(saisieElt2.getElements()), TypeMarquage.FOND3);
+      } else {
+        if (saisieTypeElt2.pasdeSelection())
+          panneauTexte.saisir(null,
+                  Element.getUnitesSousjacentes(saisieElt1.getElements()), TypeMarquage.FOND2);
+        else
+          panneauTexte.saisir(null,
+                  Element.getUnitesSousjacentes(saisieElt1.getElements()), TypeMarquage.FOND2,
+                  Element.getUnitesSousjacentes(saisieElt2.getElements()), TypeMarquage.FOND3);
+      }
+    } else {
+      if (saisieTypeElt1.pasdeSelection()) {
+        if (saisieTypeElt2.pasdeSelection())
+          panneauTexte.saisir(null,
+                  Element.getUnitesSousjacentes(saisieRelation.getElements()), TypeMarquage.FOND1);
+        else
+          panneauTexte.saisir(null,
+                  Element.getUnitesSousjacentes(filtreElt2((Relation[]) saisieRelation.getElements())), TypeMarquage.FOND1,
+                  Element.getUnitesSousjacentes(saisieElt2.getElements()), TypeMarquage.FOND3);
+      } else {
+        if (saisieTypeElt2.pasdeSelection())
+          panneauTexte.saisir(null,
+                  Element.getUnitesSousjacentes(filtreElt1((Relation[]) saisieRelation.getElements())), TypeMarquage.FOND1,
+                  Element.getUnitesSousjacentes(saisieElt1.getElements()), TypeMarquage.FOND2);
+        else
+          panneauTexte.saisir(null,
+                  Element.getUnitesSousjacentes(filtreElts((Relation[]) saisieRelation.getElements())), TypeMarquage.FOND1,
+                  Element.getUnitesSousjacentes(saisieElt1.getElements()), TypeMarquage.FOND2,
+                  Element.getUnitesSousjacentes(saisieElt2.getElements()), TypeMarquage.FOND3);
+      }
+    }
+    panneauChamps.effacer();
+    creeRelation.setEnabled(false);
+    supprimeRelation.setEnabled(false);
+    creeUniteElt1.setEnabled(false);
+    creeUniteElt2.setEnabled(false);
+  }
+  private void etatSelectTexte() {   // du texte est sélectionné
+    if (saisieElt1.pasdeSelection()) {
+      if (saisieElt2.pasdeSelection()) panneauTexte.pasDeMarquage();
+      else
+        panneauTexte.saisir(null,
+                saisieElt2.getSelection().getUnitesSousjacentes(), TypeMarquage.SELECT3);
+    } else {
+      if (saisieElt2.pasdeSelection())
+        panneauTexte.saisir(null,
+                saisieElt1.getSelection().getUnitesSousjacentes(), TypeMarquage.SELECT2);
+      else // au moins un des 2 elt n'est pas sélectionné
+        throw new UnsupportedOperationException("Cas non prévu");
+    }
+    panneauChamps.effacer();
+    creeRelation.setEnabled(false);
+    supprimeRelation.setEnabled(false);
+    if (!saisieTypeElt1.pasdeSelection()&&saisieTypeElt1.getClasseSelection()==Unite.class
+            &&saisieElt1.pasdeSelection())
+      creeUniteElt1.setEnabled(true);
+    if (!saisieTypeElt2.pasdeSelection()&&saisieTypeElt2.getClasseSelection()==Unite.class
+            &&saisieElt2.pasdeSelection())
+      creeUniteElt2.setEnabled(true);
+  }
+  private void etatSelectElt1(Element elt1) { // seul Elt1 a été choisi
+    if (saisieTypeElt2.pasdeSelection()) {
+      if (saisieTypeRelations.pasdeSelection())
+        panneauTexte.saisir(elt1.getUnite0(), elt1.getUnitesSousjacentes(), TypeMarquage.SELECT2);
+      else
+        panneauTexte.saisir(elt1.getUnite0(), elt1.getUnitesSousjacentes(), TypeMarquage.SELECT2,
+                Element.getUnitesSousjacentes(filtreElt1((Relation[]) saisieRelation.getElements(), elt1)),
+                TypeMarquage.FOND1);
+    } else {
+      if (saisieTypeRelations.pasdeSelection())
+        panneauTexte.saisir(elt1.getUnite0(), elt1.getUnitesSousjacentes(), TypeMarquage.SELECT2,
+                Element.getUnitesSousjacentes(saisieElt2.getElements()), TypeMarquage.FOND3);
+      else
+        panneauTexte.saisir(elt1.getUnite0(), elt1.getUnitesSousjacentes(), TypeMarquage.SELECT2,
+                Element.getUnitesSousjacentes(filtreElt1(filtreElt2((Relation[]) saisieRelation.getElements()), elt1)),
+                TypeMarquage.FOND1,
+                Element.getUnitesSousjacentes(saisieElt2.getElements()), TypeMarquage.FOND3);
+    }
+    panneauChamps.afficher(elt1);
+    creeRelation.setEnabled(false);
+    supprimeRelation.setEnabled(false);
+    creeUniteElt1.setEnabled(false);
+    creeUniteElt2.setEnabled(false);
+  }
+  private void etatSelectElt2(Element elt2) {  // seul Elt2 a été choisi
+    if (saisieTypeElt1.pasdeSelection()) {
+      if (saisieTypeRelations.pasdeSelection())
+        panneauTexte.saisir(elt2.getUnite0(), elt2.getUnitesSousjacentes(), TypeMarquage.SELECT3);
+      else
+        panneauTexte.saisir(elt2.getUnite0(), elt2.getUnitesSousjacentes(), TypeMarquage.SELECT3,
+                Element.getUnitesSousjacentes(filtreElt2((Relation[]) saisieRelation.getElements(), elt2)),
+                TypeMarquage.FOND1);
+    } else {
+      if (saisieTypeRelations.pasdeSelection())
+        panneauTexte.saisir(elt2.getUnite0(), elt2.getUnitesSousjacentes(), TypeMarquage.SELECT3,
+                Element.getUnitesSousjacentes(saisieElt1.getElements()), TypeMarquage.FOND2);
+      else
+        panneauTexte.saisir(elt2.getUnite0(), elt2.getUnitesSousjacentes(), TypeMarquage.SELECT3,
+                Element.getUnitesSousjacentes(filtreElt2(filtreElt1((Relation[]) saisieRelation.getElements()), elt2)),
+                TypeMarquage.FOND1,
+                Element.getUnitesSousjacentes(saisieElt1.getElements()), TypeMarquage.FOND2);
+    }
+    panneauChamps.afficher(elt2);
+    creeRelation.setEnabled(false);
+    supprimeRelation.setEnabled(false);
+    creeUniteElt1.setEnabled(false);
+    creeUniteElt2.setEnabled(false);
+  }
+  private void etatSelectElts(Element elt1, Element elt2) { // Elt1 et Elt2 ont été choisis et ils ne forment pas encore de relation
+    panneauTexte.saisir(elt1.getUnite0(), elt1.getUnitesSousjacentes(), TypeMarquage.SELECT2,
+            elt2.getUnitesSousjacentes(), TypeMarquage.SELECT3);
+    panneauChamps.effacer();
+    if (!saisieTypeRelations.pasdeSelection()) {
+      creeRelation.setEnabled(true);
+//      Boutons.setDefaut(creeRelation, true);
+    }
+    supprimeRelation.setEnabled(false);
+    creeUniteElt1.setEnabled(false);
+    creeUniteElt2.setEnabled(false);
+  }
+  private void etatSelectRel(Relation rel) {  // une relation est sélectionnée
+    panneauTexte.saisir(rel.getElt1().getUnite0(),
+            rel.getElt1().getUnitesSousjacentes(), TypeMarquage.SELECT1_2,
+            rel.getElt2().getUnitesSousjacentes(), TypeMarquage.SELECT1_3);
+//            Element.getUnitesSousjacentes(saisieElt1.getElements()), TypeMarquage.FOND2,
+//            Element.getUnitesSousjacentes(saisieElt2.getElements()), TypeMarquage.FOND3);
+    panneauChamps.afficher(rel);
+    creeRelation.setEnabled(false);
+    supprimeRelation.setEnabled(true);
+    creeUniteElt1.setEnabled(false);
+    creeUniteElt2.setEnabled(false);
+  }
+  private Relation[] filtreElt1(Relation[] relations) {
+    Class classe = saisieTypeElt1.getClasseSelection();
+    String type = saisieTypeElt1.getTypeSelection();
+    ArrayList<Integer> indsAOter = new ArrayList<Integer>();
+    for (int i = 0; i<relations.length; i++) {
+      Element elt1 = relations[i].getElt1();
+      if (elt1.getClass()!=classe||!elt1.getType().equals(type))
+        indsAOter.add(i);
+    }
+    return Tableaux.oterRelations(relations, indsAOter);
+  }
+  private Relation[] filtreElt1(Relation[] relations, Element elt1) {
+    ArrayList<Relation> rels = new ArrayList<Relation>();
+    for (Relation rel : relations) if (elt1==rel.getElt1()) rels.add(rel);
+    return rels.toArray(new Relation[0]);
+  }
+  private Relation[] filtreElt2(Relation[] relations) {
+    Class classe = saisieTypeElt2.getClasseSelection();
+    String type = saisieTypeElt2.getTypeSelection();
+    ArrayList<Integer> indsAOter = new ArrayList<Integer>();
+    for (int i = 0; i<relations.length; i++) {
+      Element elt2 = relations[i].getElt2();
+      if (elt2.getClass()!=classe||!elt2.getType().equals(type))
+        indsAOter.add(i);
+    }
+    return Tableaux.oterRelations(relations, indsAOter);
+  }
+  private Relation[] filtreElt2(Relation[] relations, Element elt2) {
+    ArrayList<Relation> rels = new ArrayList<Relation>();
+    for (Relation rel : relations) if (elt2==rel.getElt2()) rels.add(rel);
+    return rels.toArray(new Relation[0]);
+  }
+  private Relation[] filtreElts(Relation[] relations) {
+    Class classe1 = saisieTypeElt1.getClasseSelection();
+    String type1 = saisieTypeElt1.getTypeSelection();
+    Class classe2 = saisieTypeElt2.getClasseSelection();
+    String type2 = saisieTypeElt2.getTypeSelection();
+    ArrayList<Integer> indsAOter = new ArrayList<Integer>();
+    for (int i = 0; i<relations.length; i++) {
+      Element elt1 = relations[i].getElt1();
+      Element elt2 = relations[i].getElt2();
+      if (elt1.getClass()!=classe1||!elt1.getType().equals(type1)
+              ||elt2.getClass()!=classe2||!elt2.getType().equals(type2))
+        indsAOter.add(i);
+    }
+    return Tableaux.oterRelations(relations, indsAOter);
+  }
+  private void checkEtatSelectElts(Element elt1, Element elt2) {
+    if (!saisieTypeRelations.pasdeSelection())
+      for (Relation rel : (Relation[]) saisieRelation.getElements()) {
+        if (rel.getElt1()==elt1&&rel.getElt2()==elt2) {
+          saisieRelation.setSelection(rel);
+          return;
+        }
+      }
+    etatSelectElts(elt1, elt2);
+  }
+  private void forceEtatSelectRel(Relation rel) {
+    if (saisieTypeElt1.pasdeSelection()||saisieTypeElt1.getClasseSelection()!=rel.getElt1().getClass()
+            ||!saisieTypeElt1.getTypeSelection().equals(rel.getElt1().getType())) {
+      saisieTypeElt1.removeActionListener(this);
+      saisieTypeElt1.setSelection(rel.getElt1().getClass(), rel.getElt1().getType());
+      saisieTypeElt1.addActionListener(this);
+    }
+    initSaisieElt1(rel.getElt1());
+    if (saisieTypeElt2.pasdeSelection()||saisieTypeElt2.getClasseSelection()!=rel.getElt2().getClass()
+            ||!saisieTypeElt2.getTypeSelection().equals(rel.getElt2().getType())) {
+      saisieTypeElt2.removeActionListener(this);
+      saisieTypeElt2.setSelection(rel.getElt2().getClass(), rel.getElt2().getType());
+      saisieTypeElt2.addActionListener(this);
+    }
+    initSaisieElt2(rel.getElt2());
+    etatSelectRel(rel);
+  }
+  private void forceEffSelectElt1() {
+    if (saisieElt1.pasdeSelection()) return;
+    if (!saisieRelation.pasdeSelection()) {
+      saisieRelation.removeActionListener(this);
+      saisieRelation.effSelection();
+      saisieRelation.addActionListener(this);
+    }
+    saisieElt1.effSelection();
+  }
+  private void forceEffSelectElt2() {
+    if (saisieElt2.pasdeSelection()) return;
+    if (!saisieRelation.pasdeSelection()) {
+      saisieRelation.removeActionListener(this);
+      saisieRelation.effSelection();
+      saisieRelation.addActionListener(this);
+    }
+    saisieElt2.effSelection();
+  }
+  private void forceEffSelectRel() {
+    if (saisieRelation.pasdeSelection()) return;
+    saisieRelation.removeActionListener(this);
+    saisieRelation.effSelection();
+    saisieRelation.addActionListener(this);
+  }
+  private void initSaisieRelation(Relation rel) {
+    saisieRelation.removeActionListener(this);
+    if (saisieTypeRelations.pasdeSelection()) saisieRelation.setModeleVide();
+    else {
+      String type0 = saisieTypeRelations.getTypeSelection();
+      Relation[] relations = vue.getRelationsAVoir(type0);
+      saisieRelation.setModele(relations, vue.getIdRelations(type0, relations));
+    }
+    if (rel==null) saisieRelation.effSelection();
+    else saisieRelation.setSelection(rel);
+    saisieRelation.addActionListener(this);
+    saisieRelation.revalidate();
+  }
+  private void initSaisieRelation() {
+    initSaisieRelation(null);
+  }
+  private void initSaisieElt1(Element elt1) {
+    saisieElt1.removeActionListener(this);
+    if (saisieTypeElt1.pasdeSelection()) saisieElt1.setModeleVide();
+    else {
+      Class<? extends Element> classe = saisieTypeElt1.getClasseSelection();
+      String type = saisieTypeElt1.getTypeSelection();
+      saisieElt1.setModele(vue.getElements(classe, type), vue.getIdElements(classe, type));
+    }
+    if (elt1==null) saisieElt1.effSelection();
+    else saisieElt1.setSelection(elt1);
+    saisieElt1.addActionListener(this);
+    saisieElt1.revalidate();
+  }
+  private void initSaisieElt1() {
+    initSaisieElt1(null);
+  }
+  private void initSaisieElt2(Element elt2) {
+    saisieElt2.removeActionListener(this);
+    if (saisieTypeElt2.pasdeSelection()) saisieElt2.setModeleVide();
+    else {
+      Class<? extends Element> classe = saisieTypeElt2.getClasseSelection();
+      String type = saisieTypeElt2.getTypeSelection();
+      saisieElt2.setModele(vue.getElements(classe, type), vue.getIdElements(classe, type));
+    }
+
+    if (elt2==null) saisieElt2.effSelection();
+    else saisieElt2.setSelection(elt2);
+    saisieElt2.addActionListener(this);
+    saisieElt2.revalidate();
+  }
+  private void initSaisieElt2() {
+    initSaisieElt2(null);
+  }
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauCommandesRelations.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/Vue.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/Vue.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/Vue.java	(revision 3653)
@@ -0,0 +1,1256 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.vue;
+
+import JamaPlus.*;
+import java.io.*;
+import java.util.*;
+import java.util.ArrayList;
+import javax.swing.text.SimpleAttributeSet;
+import visuAnalec.*;
+import visuAnalec.util.*;
+import visuAnalec.Message.*;
+import visuAnalec.elements.*;
+import visuAnalec.donnees.*;
+import visuAnalec.donnees.Corpus.*;
+import visuAnalec.texte.PanneauTexte;
+import visuAnalec.texte.PanneauTexte.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class Vue implements CorpusListener {
+  public static interface VueListener extends EventListener {
+    void traiterEvent(Message e);     // relaie les messages de Corpus + envoie ses propres messages (VueEvent)
+  }
+
+  public static class Adresse implements Serializable {
+    ArrayList<Jalon> chemin;
+    String prop;
+    Adresse(Adresse adresse, String prop) {
+      this.prop = prop;
+      this.chemin = new ArrayList<Jalon>(adresse.chemin);
+    }
+    Adresse(Adresse adresse, Jalon jalon) {
+      this.prop = null;
+      ArrayList<Jalon> chemin1 = new ArrayList<Jalon>(adresse.chemin);
+      chemin1.add(jalon);
+      this.chemin = chemin1;
+    }
+    Adresse(Adresse adresse) {
+      this.prop = adresse.prop;
+      this.chemin = new ArrayList<Jalon>();
+      for (Jalon jalon : adresse.chemin) this.chemin.add(new Jalon(jalon));
+    }
+    Adresse(Jalon jalon, String prop) {
+      this.prop = prop;
+      chemin = new ArrayList<Jalon>(Arrays.asList(jalon));
+    }
+    Adresse(Jalon jalon) {
+      this.prop = null;
+      chemin = new ArrayList<Jalon>(Arrays.asList(jalon));
+    }
+    int getLongueur() {
+      return chemin.size();
+    }
+    Jalon getLastJalon() {
+      return chemin.get(chemin.size()-1);
+    }
+    void renommer(Class<? extends Element> classe, String oldType, String newType) {
+      for (Jalon jalon : chemin)
+        if (jalon.classe==classe&&jalon.type.equals(oldType))
+          jalon.type = newType;
+    }
+    boolean contient(Class<? extends Element> classe, String type) {
+      for (Jalon jalon : chemin) {
+        if (jalon.classe==classe&&jalon.type.equals(type)) return true;
+      }
+      return false;
+    }
+    @Override
+    public String toString() {
+      String nom = "";
+      for (Jalon jalon : chemin) {
+        nom += jalon;
+      }
+      nom += ": "+prop;
+      return nom;
+    }
+  }
+
+  public static class Jalon implements Serializable {
+    public enum Origine {
+      ELT_0, ELT_1, ELT_2, REL_SORTANTE, REL_ENTRANTE, SCH_CONTENANT
+    }
+    /**
+     * L'origine d'un jalon indique d'où ce jalon provient :
+     * ELT_0 est  un jalon de classe quelconque qui est toujours le premier jalon d'une adresse complète. 
+     * ELT_1 et ELT_2 sont des jalons de classe quelconque qui proviennent d'un jalon précédent de classe Relation  
+     * REL_S et REL_E sont des jalons de classe Relation qui proviennent d'un jalon précédent de classe quelconque
+     * SCH_C est un jalon de classe Schema qui provient d'un jalon précédent de classe quelconque
+     */
+    public Origine origine;
+    public Class<? extends Element> classe;
+    public String type;
+    Jalon(Origine origine, Class<? extends Element> classe, String type) {
+      this.classe = classe;
+      this.origine = origine;
+      this.type = type;
+    }
+    Jalon(Jalon jalon) {
+      this.classe = jalon.classe;
+      this.origine = jalon.origine;
+      this.type = jalon.type;
+    }
+    @Override
+    public String toString() {
+      switch (origine) {
+        case SCH_CONTENANT:
+          return "{"+type;
+        case REL_ENTRANTE:
+          return "<"+type+"<";
+        case REL_SORTANTE:
+          return ">"+type+">";
+        case ELT_0:
+          return type;
+        case ELT_1:
+          return type;
+        case ELT_2:
+          return type;
+        default:
+          return "ERREUR!!";
+      }
+    }
+  }
+  /** 
+   * Champs de la classe Vue :
+   * Données spécifiant la vue: 
+   *   - typesA voir, champs, adresses, modifiables
+   *   - champsId
+   * (ce sont les seuls champs à sauvegarder et à recharger) 
+   * Le champ unitesAVoir est un raccourci pour éviter de retrier chaque fois les données correspondantes de Corpus
+   */
+  private ArrayList<VueListener> listeCorrespondants = new ArrayList<VueListener>();
+  private Corpus corpus;
+  private boolean modifiee = false;
+  ;
+  // types d'éléments à voir pour chaque classe
+  private HashMap<Class<? extends Element>, String[]> typesAVoir =
+          new HashMap<Class<? extends Element>, String[]>();
+  // champs en ordre (niveau et position) pour chaque type d'éléments à voir pour chaque classe 
+  private HashMap<Class<? extends Element>, HashMap<String, String[][]>> champspos =
+          new HashMap<Class<? extends Element>, HashMap<String, String[][]>>();
+  // adresse pour chaque champ pour chaque  type d'élément à voir pour chaque classe
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Adresse>>> adresses =
+          new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Adresse>>>();
+  // modifiabilité pour chaque champ pour chaque  type d'élément à voir pour chaque classe
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>> modifiables =
+          new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>>();
+  // champ choisi comme identifiant (s'il existe) pour chaque type de chaque classe
+  private HashMap<Class<? extends Element>, HashMap<String, String>> champsId =
+          new HashMap<Class<? extends Element>, HashMap<String, String>>();
+// style pour tout le texte
+  private SimpleAttributeSet styleTexte;
+  // style (s'il existe) pour chaque type de chaque classe
+  private HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>> stylesElements =
+          new HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>>();
+  // style (s'il existe) pour chaque valeur de chaque champ de chaque type de chaque classe
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>> stylesValeursElements =
+          new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>>();
+  // unites par type d'unites à voir
+  private HashMap<String, Unite[]> unitesAVoir = new HashMap<String, Unite[]>();
+  /* Constructeur de la classe Vue */
+  @SuppressWarnings("unchecked")
+  public Vue(Corpus corpus) {
+    this.corpus = corpus;
+    corpus.addEventListener(this);
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      typesAVoir.put(classe, new String[0]);
+      champspos.put(classe, new HashMap<String, String[][]>());
+      adresses.put(classe, new HashMap<String, HashMap<String, Adresse>>());
+      modifiables.put(classe, new HashMap<String, HashMap<String, Boolean>>());
+      champsId.put(classe, new HashMap<String, String>());
+      stylesElements.put(classe, new HashMap<String, SimpleAttributeSet>());
+      stylesValeursElements.put(classe, new HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>());
+    }
+    this.styleTexte = new SimpleAttributeSet(PanneauTexte.STANDARD_DEFAUT);
+  }
+  public void addEventListener(VueListener correspondant) {
+    listeCorrespondants.add(correspondant);
+  }
+  public void removeEventListener(VueListener correspondant) {
+    listeCorrespondants.remove(correspondant);
+  }
+  private void fireMessage(Message evt) {
+    for (Object corresp : listeCorrespondants.toArray()) {
+      ((VueListener) corresp).traiterEvent(evt);
+    }
+  }
+  public boolean isModifiee() {
+    return modifiee;
+  }
+  public void ecrireJava(ObjectOutputStream oos) throws IOException {
+    oos.writeObject(typesAVoir);
+    oos.writeObject(champspos);
+    oos.writeObject(adresses);
+    oos.writeObject(modifiables);
+    oos.writeObject(champsId);
+    oos.writeObject(styleTexte);
+    oos.writeObject(stylesElements);
+    oos.writeObject(stylesValeursElements);
+    modifiee = false;
+  }
+  @SuppressWarnings("unchecked")
+  public boolean lireJava(ObjectInputStream ois) throws IOException, ClassNotFoundException, ClassCastException {
+    HashMap<Class<? extends Element>, String[]> typesAVoirLus =
+            (HashMap<Class<? extends Element>, String[]>) ois.readObject();
+    HashMap<Class<? extends Element>, HashMap<String, String[][]>> champsposLus =
+            (HashMap<Class<? extends Element>, HashMap<String, String[][]>>) ois.readObject();
+    HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Adresse>>> adressesLues =
+            (HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Adresse>>>) ois.readObject();
+    HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>> modifablesLus =
+            (HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>>) ois.readObject();
+    HashMap<Class<? extends Element>, HashMap<String, String>> champsIdLus =
+            (HashMap<Class<? extends Element>, HashMap<String, String>>) ois.readObject();
+    SimpleAttributeSet styleTexteLu = (SimpleAttributeSet) ois.readObject();
+    HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>> stylesElementsLus =
+            (HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>>) ois.readObject();
+    HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>> stylesValeursElementsLus =
+            (HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>>) ois.readObject();
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      for (String type : typesAVoirLus.get(classe)) {
+        if (!corpus.getStructure().getTypes(classe).contains(type))
+          return false;
+      }
+    }
+    // En prévision d'une compatibilité ascendante
+    boolean suite = false;
+    try {
+      suite = ois.readBoolean();
+    } catch (EOFException eOFException) {
+    }
+    if (suite) {
+      System.out.println("Il y a d'autres objets dans le .ecv");
+    }
+    typesAVoir = typesAVoirLus;
+    champspos = champsposLus;
+    adresses = adressesLues;
+    modifiables = modifablesLus;
+    champsId = champsIdLus;
+    styleTexte = styleTexteLu;
+    stylesElements = stylesElementsLus;
+    stylesValeursElements = stylesValeursElementsLus;
+    unitesAVoir.clear();
+    modifiee = false;
+    for (String type : typesAVoir.get(Unite.class)) majUnitesAVoir(type);
+    fireMessage(new VueEvent(this, TypeModifVue.NEW_VUE));
+    return true;
+  }
+  public void traiterEvent(Message evt) { // Messages de corpus
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        initVueParDefaut();
+        fireMessage(evt);
+        return;
+      case CORPUS_SAVED:
+    	  fireMessage(evt);
+          return;
+      case NEW_CORPUS:
+        initVueParDefaut();
+        fireMessage(evt);
+        return;
+      case MODIF_TEXTE:
+        fireMessage(evt);
+        return;
+      case MODIF_ELEMENT:
+        ElementEvent evtE = (ElementEvent) evt;
+        switch (evtE.getModif()) {
+          case AJOUT_UNITE:
+            if (!unitesAVoir.containsKey(evtE.getElement().getType())) return;
+            majUnitesAVoir(evtE.getElement().getType());
+            fireMessage(evt);
+            return;
+          case SUP_UNITE:
+            if (!unitesAVoir.containsKey(evtE.getElement().getType())) return;
+            majUnitesAVoir(evtE.getElement().getType());
+            fireMessage(evt);
+            return;
+          case BORNES_UNITE:
+        	  if (!unitesAVoir.containsKey(evtE.getElement().getType())) return;
+              majUnitesAVoir(evtE.getElement().getType());
+              fireMessage(evt);
+              return;
+          case AJOUT_RELATION:
+          case AJOUT_SCHEMA:
+          case SUP_RELATION:
+          case SUP_SCHEMA:
+          case MODIF_SCHEMA:
+          case MODIF_VALEUR:
+            fireMessage(evt);
+            return;
+          default:
+            throw new UnsupportedOperationException("Cas "+evtE.getModif()+" oublié dans un switch");
+        }
+      case MODIF_STRUCTURE:
+        StructureEvent evtS = (StructureEvent) evt;
+        switch (evtS.getModif()) {
+          case FUSION_TYPE:
+            fusionnerType(evtS.getClasse(), evtS.getArg(0), evtS.getArg(1));
+            fireMessage(evt);
+            return;
+          case RENOM_TYPE:
+            renommerType(evtS.getClasse(), evtS.getArg(0), evtS.getArg(1));
+            fireMessage(evt);
+            return;
+          case AJOUT_TYPE:
+            ajouterType(evtS.getClasse(), evtS.getArg());
+            fireMessage(evt);
+            return;
+          case AJOUT_TYPE_ET_ELEMENTS:
+            ajouterType(evtS.getClasse(), evtS.getArg());
+            if (evtS.getClasse()==Unite.class&&unitesAVoir.containsKey(evtS.getArg()))
+              majUnitesAVoir(evtS.getArg());
+            fireMessage(evt);
+            return;
+          case SUPPR_TYPE:
+            supprimerType(evtS.getClasse(), evtS.getArg());
+            fireMessage(evt);
+            return;
+          case AJOUT_PROP:
+            ajouterProp(evtS.getClasse(), evtS.getArg(0), evtS.getArg(1));
+            fireMessage(evt);
+            return;
+          case AJOUT_FORME_UNITE:
+            ajouterFormeUnite(evtS.getArg(0));
+            fireMessage(evt);
+            return;
+           case FUSION_PROP:
+            fusionnerProp(evtS.getClasse(), evtS.getArg(0), evtS.getArg(1), evtS.getArg(2));
+            fireMessage(evt);
+            return;
+          case RENOM_PROP:
+            renommerProp(evtS.getClasse(), evtS.getArg(0), evtS.getArg(1), evtS.getArg(2));
+            fireMessage(evt);
+            return;
+          case SUPPR_PROP:
+            supprimerProp(evtS.getClasse(), evtS.getArg(0), evtS.getArg(1));
+            fireMessage(evt);
+            return;
+          case RENOM_VALEUR:
+          case FUSION_VALEUR:
+          case SUPPR_VALEUR:
+          case AJOUT_VALEUR:
+            fireMessage(evt);
+            return;
+          case VALEUR_PAR_DEFAUT:
+            fireMessage(evt);
+            return;
+          default:
+            throw new UnsupportedOperationException("Cas "+evtS.getModif()+" oublié dans un switch");
+        }
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+  }
+  @SuppressWarnings("unchecked")
+  private void initVueParDefaut() {
+    unitesAVoir.clear();
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      String[] types = getTypes(classe);
+      Arrays.sort(types);
+      typesAVoir.put(classe, types);
+      champspos.get(classe).clear();
+      adresses.get(classe).clear();
+      champsId.get(classe).clear();
+      styleTexte = new SimpleAttributeSet(PanneauTexte.STANDARD_DEFAUT);
+      stylesElements.get(classe).clear();
+      stylesValeursElements.get(classe).clear();
+      for (String type : typesAVoir.get(classe)) {
+        Jalon jalon0 = new Jalon(Jalon.Origine.ELT_0, classe, type);
+        String[] chps = getNomsProps(new Adresse(jalon0));
+        champspos.get(classe).put(type, new String[1][]);
+        champspos.get(classe).get(type)[0] = chps;
+        adresses.get(classe).put(type, new HashMap<String, Adresse>());
+        modifiables.get(classe).put(type, new HashMap<String, Boolean>());
+        for (String chp : chps) {
+          adresses.get(classe).get(type).put(chp, new Adresse(jalon0, chp));
+          modifiables.get(classe).get(type).put(chp, true);
+        }
+        if (classe==Unite.class) majUnitesAVoir(type);
+      }
+    }
+    modifiee = false;
+    fireMessage(new VueEvent(this, TypeModifVue.VUE_DEFAUT));
+
+  }
+  private void majUnitesAVoir(String typeUnite) {
+    Unite[] unts = corpus.getUnites(typeUnite).toArray(new Unite[0]);
+    Arrays.sort(unts);
+    unitesAVoir.put(typeUnite, unts);
+  }
+  public void retablirVueParDefaut() {
+    initVueParDefaut();
+  }
+  public void setStyleTexte(SimpleAttributeSet att) {
+    styleTexte = att;
+  }
+  public SimpleAttributeSet getStyleTexte() {
+    return styleTexte;
+  }
+  public void modifierVueParSaisie(
+          HashMap<Class<? extends Element>, HashMap<String, Boolean>> newIsTypesAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> newAdressesAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> newChampsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, String>> newChampsId,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>> newModifables,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> newPositionsChamps,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> newNiveauxChamps,
+          HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>> newStylesElements,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>> newStylesValeursElements) {
+    setTypesAVoir(newIsTypesAVoir);
+    setChampsAdresses(newChampsAVoir, newAdressesAVoir, newPositionsChamps, newNiveauxChamps);
+    setChampsModifiables(newChampsAVoir, newModifables);
+    setChampsId(newChampsId);
+    setStylesElements(newStylesElements);
+    setStylesValeursElements(newStylesValeursElements);
+    unitesAVoir.clear();
+    for (String typeUnite : typesAVoir.get(Unite.class))
+      majUnitesAVoir(typeUnite);
+    modifiee = true;
+    fireMessage(new VueEvent(this, TypeModifVue.EXTRACTION));
+  }
+  @SuppressWarnings("unchecked")
+  private void setTypesAVoir(HashMap<Class<? extends Element>, HashMap<String, Boolean>> isAVoir) {
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      ArrayList<String> types = new ArrayList<String>();
+      for (String type : getTypes(classe)) if (isAVoir.get(classe).get(type))
+          types.add(type);
+      typesAVoir.put(classe, types.toArray(new String[0]));
+    }
+  }
+  @SuppressWarnings("unchecked")
+  private void setChampsAdresses(
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adressesAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> positionsChamps,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> niveauxChamps) {
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      adresses.get(classe).clear();
+      for (int i = 0; i<typesAVoir.get(classe).length; i++) {
+        String type = typesAVoir.get(classe)[i];
+        ArrayList<String> chps = champsAVoir.get(classe).get(type);
+        adresses.get(classe).put(type, new HashMap<String, Adresse>());
+        for (int j = 0; j<chps.size(); j++)
+          adresses.get(classe).get(type).put(chps.get(j), adressesAVoir.get(classe).get(type).get(j));
+        champspos.get(classe).put(type, ordonnerChamps(chps, niveauxChamps.get(classe).get(type),
+                positionsChamps.get(classe).get(type)));
+      }
+    }
+  }
+  private String[][] insererChamp(String[][] chpsenordre, String newchp) {
+    if (chpsenordre.length==0) {
+      String[][] chps = new String[1][1];
+      chps[0][0] = newchp;
+      return chps;
+    }
+    String[] chs1 = new String[chpsenordre[0].length+1];
+    chs1[0] = newchp;
+    System.arraycopy(chpsenordre[0], 0, chs1, 1, chpsenordre[0].length);
+    chpsenordre[0] = chs1;
+    return chpsenordre;
+  }
+  private String[][] ordonnerChamps(ArrayList<String> chps, HashMap<String, Integer> nivx, HashMap<String, Integer> poss) {
+    HashMap<Integer, HashMap<Integer, ArrayList<String>>> chpstries =
+            new HashMap<Integer, HashMap<Integer, ArrayList<String>>>();
+    for (String ch : chps) {
+      int niv = nivx.get(ch);
+      if (!chpstries.containsKey(niv))
+        chpstries.put(niv, new HashMap<Integer, ArrayList<String>>());
+      int pos = poss.get(ch);
+      if (!chpstries.get(niv).containsKey(pos))
+        chpstries.get(niv).put(pos, new ArrayList<String>());
+      chpstries.get(niv).get(pos).add(ch);
+    }
+    Integer[] niveaux = chpstries.keySet().toArray(new Integer[0]);
+    Arrays.sort(niveaux);
+    String[][] chpsenordre = new String[niveaux.length][];
+    int niveauenordre = 0;
+    for (int niv : niveaux) {
+      Integer[] positions = chpstries.get(niv).keySet().toArray(new Integer[0]);
+      Arrays.sort(positions);
+      int nbch = 0;
+      for (int pos : positions) nbch += chpstries.get(niv).get(pos).size();
+      chpsenordre[niveauenordre] = new String[nbch];
+      int positionenordre = 0;
+      for (int pos : positions) {
+        String[] chs = chpstries.get(niv).get(pos).toArray(new String[0]);
+        Arrays.sort(chs);
+        for (String ch : chs)
+          chpsenordre[niveauenordre][positionenordre++] = ch;
+      }
+      niveauenordre++;
+    }
+    return chpsenordre;
+  }
+  @SuppressWarnings("unchecked")
+  private void setChampsModifiables(HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> newChampsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>> newModifables) {
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      modifiables.get(classe).clear();
+      for (int i = 0; i<typesAVoir.get(classe).length; i++) {
+        String type = typesAVoir.get(classe)[i];
+        modifiables.get(classe).put(type, new HashMap<String, Boolean>());
+        for (String chp : newChampsAVoir.get(classe).get(type))
+          modifiables.get(classe).get(type).put(chp, newModifables.get(classe).get(type).get(chp));
+      }
+    }
+  }
+  @SuppressWarnings("unchecked")
+  private void setChampsId(HashMap<Class<? extends Element>, HashMap<String, String>> newChampsId) {
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      champsId.get(classe).clear();
+      champsId.get(classe).putAll(newChampsId.get(classe));
+    }
+  }
+  @SuppressWarnings("unchecked")
+  private void setStylesElements(HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>> newStylesElements) {
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      stylesElements.get(classe).clear();
+      stylesElements.get(classe).putAll(newStylesElements.get(classe));
+    }
+  }
+  @SuppressWarnings("unchecked")
+  private void setStylesValeursElements(HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>> newStylesValeursElements) {
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      stylesValeursElements.get(classe).clear();
+      stylesValeursElements.get(classe).putAll(newStylesValeursElements.get(classe));
+    }
+  }
+  public Corpus getCorpus() {
+    return corpus;
+  }
+  public String[] getTypes(Class<? extends Element> classe) {
+    String[] types = corpus.getStructure().getTypes(classe).toArray(new String[0]);
+    Arrays.sort(types);
+    return types;
+  }
+  @SuppressWarnings("unchecked")
+  public HashMap<Class<? extends Element>, HashMap<String, Boolean>> isTypesAVoir() {
+    HashMap<Class<? extends Element>, HashMap<String, Boolean>> isAVoir =
+            new HashMap<Class<? extends Element>, HashMap<String, Boolean>>();
+    for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+      isAVoir.put(classe, new HashMap<String, Boolean>());
+      for (String type : getTypes(classe)) isAVoir.get(classe).put(type, false);
+      for (String type : typesAVoir.get(classe))
+        isAVoir.get(classe).put(type, true);
+    }
+    return isAVoir;
+  }
+  String[] getTypesAVoir(Class<? extends Element> classe) {
+    return typesAVoir.get(classe);
+  }
+  public String[] getTypesUnitesAVoir() {
+    return getTypesAVoir(Unite.class);
+  }
+  public String[] getTypesRelationsAVoir() {
+    return getTypesAVoir(Relation.class);
+  }
+  public String[] getTypesSchemasAVoir() {
+    return getTypesAVoir(Schema.class);
+  }
+  public String getChampId(Class<? extends Element> classe, String type) {
+    return champsId.get(classe).get(type);
+  }
+  public SimpleAttributeSet getStyleElements(Class<? extends Element> classe, String type) {
+    return stylesElements.get(classe).get(type);
+  }
+  public HashMap<String, HashMap<String, SimpleAttributeSet>> getStyleValeursElements(
+          Class<? extends Element> classe, String type) {
+    return stylesValeursElements.get(classe).get(type);
+  }
+  public String[][] getChamps(Class<? extends Element> classe, String type) {
+    if (champspos.get(classe).containsKey(type)) {
+      return champspos.get(classe).get(type);
+    } else {
+      return new String[0][];
+    }
+  }
+  public String[] getNomsChamps(Class<? extends Element> classe, String type) {
+    return getListeChamps(classe, type).toArray(new String[0]);
+  }
+  //la méthode suivante publique pour pouvoir l'utiliser dans une autre classe
+  public ArrayList<String> getListeChamps(Class<? extends Element> classe, String type) {
+    // utilisé aussi par VisuVue
+    ArrayList<String> lchps = new ArrayList<String>();
+    if (champspos.get(classe).containsKey(type))
+      for (String[] champsniveau : champspos.get(classe).get(type))
+        lchps.addAll(Arrays.asList(champsniveau));
+    return lchps;
+  }
+  static String trouveNomChampParDefaut(Adresse ad, ArrayList<String> chps) {
+    String nom;
+    if (ad.chemin.size()==1) {
+      nom = ad.prop;
+      while (chps.contains(nom)) nom += "-0";
+      return nom;
+    }
+    for (int i = 1; true; i++) {
+      nom = ad.prop+"-"+i;
+      if (!chps.contains(nom)) {
+        return nom;
+      }
+    }
+  }
+  String[] getNomsProps(Adresse adresse) {
+    String[] props;
+    Jalon jalon = adresse.getLastJalon();
+    props = corpus.getStructure().getNomsProps(jalon.classe, jalon.type).toArray(new String[0]);
+    Arrays.sort(props);
+    return props;
+  }
+  String[] getValeursProp(Adresse adresse) {
+    String[] vals;
+    Jalon jalon = adresse.getLastJalon();
+    vals = corpus.getStructure().getValeursProp(jalon.classe, jalon.type, adresse.prop).toArray(new String[0]);
+    Arrays.sort(vals);
+    return vals;
+  }
+  @SuppressWarnings("unchecked")
+  Jalon[] getNextJalonsPotentiels(Adresse adresse) {
+    ArrayList<Jalon> nextJalons = new ArrayList<Jalon>();
+    Jalon jalon = adresse.getLastJalon();
+    switch (jalon.origine) {
+      case REL_ENTRANTE:
+        for (Class<? extends Element> cl : new Class[]{Unite.class, Relation.class, Schema.class}) {
+          for (String typeRel : getTypes(cl)) {
+            nextJalons.add(new Jalon(Jalon.Origine.ELT_1, cl, typeRel));
+          }
+        }
+        break;
+      case REL_SORTANTE:
+        for (Class<? extends Element> cl : new Class[]{Unite.class, Relation.class, Schema.class}) {
+          for (String typeRel : getTypes(cl)) {
+            nextJalons.add(new Jalon(Jalon.Origine.ELT_2, cl, typeRel));
+          }
+        }
+        break;
+      default:
+        for (String typeRel : getTypes(Relation.class)) {
+          nextJalons.add(new Jalon(Jalon.Origine.REL_SORTANTE, Relation.class, typeRel));
+        }
+        for (String typeRel : getTypes(Relation.class)) {
+          nextJalons.add(new Jalon(Jalon.Origine.REL_ENTRANTE, Relation.class, typeRel));
+        }
+        for (String typeSch : getTypes(Schema.class)) {
+          nextJalons.add(new Jalon(Jalon.Origine.SCH_CONTENANT, Schema.class, typeSch));
+        }
+        break;
+    }
+    return nextJalons.toArray(new Jalon[0]);
+  }
+  Adresse getAdresseChamps(Class<? extends Element> classe, String type, String nomChamp) {
+    if (adresses.get(classe).containsKey(type)) {
+      return adresses.get(classe).get(type).get(nomChamp);
+    } else {
+      return null;
+    }
+  }
+  public boolean isChampModifiable(Class<? extends Element> classe, String type, String champ) {
+    return modifiables.get(classe).get(type).get(champ);
+  }
+  public HashMap<String, Integer> getPositionsChampsAVoir(Class<? extends Element> classe, String type) {
+    HashMap<String, Integer> positions = new HashMap<String, Integer>();
+    if (champspos.get(classe).containsKey(type)) {
+      for (String[] champsniveau : champspos.get(classe).get(type)) {
+        int i = 0;
+        for (String ch : champsniveau) positions.put(ch, i++);
+      }
+    }
+    return positions;
+  }
+  public HashMap<String, Integer> getNiveauxChampsAVoir(Class<? extends Element> classe, String type) {
+    HashMap<String, Integer> niveaux = new HashMap<String, Integer>();
+    if (champspos.get(classe).containsKey(type)) {
+      int i = 0;
+      for (String[] champsniveau : champspos.get(classe).get(type)) {
+        for (String ch : champsniveau) niveaux.put(ch, i);
+        i++;
+      }
+    }
+    return niveaux;
+  }
+  public String[] getValeursChamp(Class<? extends Element> classe, String type, String champ) {
+    Adresse adresse = getAdresseChamps(classe, type, champ);
+    if (adresse==null) {
+      return new String[0];
+    }
+    return getValeursProp(adresse);
+  }
+  public String getValeurChamp(Element element, String champ) {
+    Adresse adresse = getAdresseChamps(element.getClass(), element.getType(), champ);
+    if (adresse==null) {
+      return "";
+    }
+    Element elt = element;
+    for (Jalon jalon : adresse.chemin) {
+      if ((elt = elt.getElementSuivant(jalon))==null) return "";
+    }
+    return elt.getProp(adresse.prop);
+  }
+  public boolean setValeurChamp(Element element, String champ, String newval) {
+    Adresse adresse = getAdresseChamps(element.getClass(), element.getType(), champ);
+    if (adresse == null) return false;
+    
+    Element elt = element;
+    for (Jalon jalon : adresse.chemin) {
+      elt = elt.getElementSuivant(jalon);
+      if (elt==null) return false;
+    }
+    corpus.setValeurPropElement(elt, adresse.prop, newval);
+    return true;
+  }
+  public void copierValeurs(Element eltSource, Element eltCible) {
+    Class<? extends Element> classe = eltSource.getClass();
+    if (eltCible.getClass()!=classe) return;
+    String type = eltSource.getType();
+    if (!eltCible.getType().equals(type)) return;
+    for (String champ : getListeChamps(classe, type))
+      if (isChampModifiable(classe, type, champ))
+        setValeurChamp(eltCible, champ, getValeurChamp(eltSource, champ));
+  }
+  private void ajouterType(Class<? extends Element> classe, String newType) {
+
+//      ArrayList<String> typs = new ArrayList<String>(Arrays.asList(typesUnitesAVoir));
+//      typs.add(newType);
+//      typesUnitesAVoir = typs.toArray(new String[0]);
+//      Arrays.sort(typesUnitesAVoir);
+    typesAVoir.put(classe, Tableaux.insererString(typesAVoir.get(classe), newType));
+    champspos.get(classe).put(newType, new String[0][]);
+    adresses.get(classe).put(newType, new HashMap<String, Adresse>());
+    if (classe==Unite.class) unitesAVoir.put(newType, new Unite[0]);
+    modifiables.get(classe).put(newType, new HashMap<String, Boolean>());
+  }
+  private void renommerType(Class<? extends Element> classe, String oldType, String newType) {
+    for (Class<? extends Element> cl : adresses.keySet())
+      for (String type : adresses.get(cl).keySet())
+        for (String chp : adresses.get(cl).get(type).keySet()) {
+          adresses.get(cl).get(type).get(chp).renommer(classe, oldType, newType);
+        }
+    int ind = Arrays.binarySearch(typesAVoir.get(classe), oldType);
+    if (ind>=0) {
+      typesAVoir.get(classe)[ind] = newType;
+      Arrays.sort(typesAVoir.get(classe));
+      champspos.get(classe).put(newType, champspos.get(classe).get(oldType));
+      champspos.get(classe).remove(oldType);
+      adresses.get(classe).put(newType, adresses.get(classe).get(oldType));
+      adresses.get(classe).remove(oldType);
+      if (champsId.get(classe).containsKey(oldType)) {
+        champsId.get(classe).put(newType, champsId.get(classe).get(oldType));
+        champsId.get(classe).remove(oldType);
+      }
+      modifiables.get(classe).put(newType, modifiables.get(classe).get(oldType));
+      if (classe==Unite.class) {
+        unitesAVoir.put(newType, unitesAVoir.get(oldType));
+        unitesAVoir.remove(oldType);
+      }
+      if (stylesElements.get(classe).containsKey(oldType)) {
+        stylesElements.get(classe).put(newType, stylesElements.get(classe).get(oldType));
+        stylesElements.get(classe).remove(oldType);
+      }
+      if (stylesValeursElements.get(classe).containsKey(oldType)) {
+        stylesValeursElements.get(classe).put(newType, stylesValeursElements.get(classe).get(oldType));
+        stylesValeursElements.get(classe).remove(oldType);
+      }
+    }
+  }
+  private void fusionnerType(Class<? extends Element> classe, String oldType, String newType) {
+    int indold = Arrays.binarySearch(typesAVoir.get(classe), oldType);
+    if (indold>=0) {
+      int indnew = Arrays.binarySearch(typesAVoir.get(classe), newType);
+      if (indnew>=0) {
+        ArrayList<String> chpsnewtype = getListeChamps(classe, newType);
+        HashMap<String, Integer> nivxnewtype = getNiveauxChampsAVoir(classe, newType);
+        HashMap<String, Integer> possnewtype = getPositionsChampsAVoir(classe, newType);
+        for (String chpoldtype : getListeChamps(classe, oldType)) {
+          Adresse adroldtype = adresses.get(classe).get(oldType).get(chpoldtype);
+          String nomchamp = trouveNomChampParDefaut(adroldtype, chpsnewtype);
+          adresses.get(classe).get(newType).put(nomchamp, adroldtype);
+          chpsnewtype.add(nomchamp);
+          nivxnewtype.put(nomchamp, getNiveauxChampsAVoir(classe, oldType).get(chpoldtype));
+          possnewtype.put(nomchamp, getPositionsChampsAVoir(classe, oldType).get(chpoldtype));
+          modifiables.get(classe).get(newType).put(nomchamp, modifiables.get(classe).get(oldType).get(chpoldtype));
+          if (stylesValeursElements.get(classe).containsKey(oldType)&&stylesValeursElements.get(classe).get(oldType).containsKey(chpoldtype)) {
+            if (!stylesValeursElements.get(classe).containsKey(newType))
+              stylesValeursElements.get(classe).put(newType, new HashMap<String, HashMap<String, SimpleAttributeSet>>());
+            stylesValeursElements.get(classe).get(newType).put(nomchamp,
+                    stylesValeursElements.get(classe).get(oldType).get(chpoldtype));
+          }
+        }
+        champspos.get(classe).put(newType, ordonnerChamps(chpsnewtype, nivxnewtype, possnewtype));
+      }
+      typesAVoir.put(classe, Tableaux.oterString(typesAVoir.get(classe), indold));
+      champspos.get(classe).remove(oldType);
+      adresses.get(classe).remove(oldType);
+      champsId.get(classe).remove(oldType);
+      modifiables.get(classe).remove(oldType);
+      stylesElements.get(classe).remove(oldType);
+      stylesValeursElements.get(classe).remove(oldType);
+      if (classe==Unite.class) {
+        majUnitesAVoir(newType);
+        unitesAVoir.remove(oldType);
+      }
+    }
+    for (Class<? extends Element> cl : typesAVoir.keySet())
+      for (String typ : typesAVoir.get(cl)) {
+        ArrayList<String> chpsASup = new ArrayList<String>();
+        ArrayList<String> chps = getListeChamps(cl, typ);
+        HashMap<String, Integer> nivx = getNiveauxChampsAVoir(cl, typ);
+        HashMap<String, Integer> poss = getPositionsChampsAVoir(cl, typ);
+        for (String ch : chps) {
+          Adresse ad = adresses.get(cl).get(typ).get(ch);
+          if (ad.contient(classe, oldType)) {
+            Adresse ad1 = new Adresse(ad);
+            ad1.renommer(classe, oldType, newType);
+            boolean dejala = false;
+            for (String ch1 : chps)
+              if (adresses.get(cl).get(typ).get(ch1).toString().equals(ad1.toString())) {
+                dejala = true;
+                break;
+              }
+            if (!dejala) adresses.get(cl).get(typ).put(ch, ad1);
+            else {
+              chpsASup.add(ch);
+              if (ch.equals(champsId.get(cl).get(typ)))
+                champsId.get(cl).remove(typ);
+              modifiables.get(cl).get(typ).remove(ch);
+              if (stylesValeursElements.get(cl).containsKey(typ))
+                stylesValeursElements.get(cl).get(typ).remove(ch);
+              nivx.remove(ch);
+              poss.remove(ch);
+            }
+          }
+        }
+        chps.removeAll(chpsASup);
+        for (String ch : chpsASup) adresses.get(cl).get(typ).remove(ch);
+        champspos.get(cl).put(typ, ordonnerChamps(chps, nivx, poss));
+      }
+  }
+  private void supprimerType(Class<? extends Element> classe, String type) {
+    int ind = Arrays.binarySearch(typesAVoir.get(classe), type);
+    if (ind>=0) {
+      typesAVoir.put(classe, Tableaux.oterString(typesAVoir.get(classe), ind));
+      champspos.get(classe).remove(type);
+      adresses.get(classe).remove(type);
+      if (classe==Unite.class) unitesAVoir.remove(type);
+    }
+    champsId.get(classe).remove(type);
+    modifiables.get(classe).remove(type);
+    stylesElements.get(classe).remove(type);
+    stylesValeursElements.get(classe).remove(type);
+    for (Class<? extends Element> cl : typesAVoir.keySet())
+      for (String typ : typesAVoir.get(cl)) {
+        ArrayList<String> chpsASup = new ArrayList<String>();
+        ArrayList<String> chps = getListeChamps(cl, typ);
+        HashMap<String, Integer> nivx = getNiveauxChampsAVoir(cl, typ);
+        HashMap<String, Integer> poss = getPositionsChampsAVoir(cl, typ);
+        for (String ch : chps)
+          if (adresses.get(cl).get(typ).get(ch).contient(classe, type)) {
+            chpsASup.add(ch);
+            adresses.get(cl).get(typ).remove(ch);
+            if (ch.equals(champsId.get(cl).get(typ)))
+              champsId.get(cl).remove(typ);
+            modifiables.get(cl).get(typ).remove(ch);
+            if (stylesValeursElements.get(cl).containsKey(typ))
+              stylesValeursElements.get(cl).get(typ).remove(ch);
+            nivx.remove(ch);
+            poss.remove(ch);
+          }
+        chps.removeAll(chpsASup);
+        champspos.get(cl).put(typ, ordonnerChamps(chps, nivx, poss));
+      }
+  }
+  private void ajouterProp(Class<? extends Element> classe, String type, String prop) {
+    if (Arrays.binarySearch(typesAVoir.get(classe), type)>=0) {
+      Adresse ad = new Adresse(new Jalon(Jalon.Origine.ELT_0, classe, type), prop);
+      String newchp = trouveNomChampParDefaut(ad, getListeChamps(classe, type));
+      champspos.get(classe).put(type, insererChamp(champspos.get(classe).get(type), newchp));
+      adresses.get(classe).get(type).put(newchp, ad);
+      modifiables.get(classe).get(type).put(newchp, true);
+    }
+  }
+  private void ajouterFormeUnite( String type) {
+     if (Arrays.binarySearch(typesAVoir.get(Unite.class), type)>=0) {
+      Adresse ad = new Adresse(new Jalon(Jalon.Origine.ELT_0, Unite.class, type), Structure.FORME);
+      champspos.get(Unite.class).put(type, insererChamp(champspos.get(Unite.class).get(type), Structure.FORME));
+      adresses.get(Unite.class).get(type).put(Structure.FORME, ad);
+      modifiables.get(Unite.class).get(type).put(Structure.FORME, false);
+    }
+  }
+  private void renommerProp(Class<? extends Element> classe, String type, String oldNom, String newNom) {
+    // on ne change que les adresses : on ne renomme les champs que dans certains cas (cf. renommerChamp appelé à la fin)
+    for (Class<? extends Element> cl : adresses.keySet())
+      for (String typ : adresses.get(cl).keySet())
+        for (String chp : adresses.get(cl).get(typ).keySet()) {
+          if (adresses.get(cl).get(typ).get(chp).getLastJalon().classe==classe
+                  &&type.equals(adresses.get(cl).get(typ).get(chp).getLastJalon().type)
+                  &&oldNom.equals(adresses.get(cl).get(typ).get(chp).prop)) {
+            adresses.get(cl).get(typ).get(chp).prop = newNom;
+          }
+        }
+    renommerChamp(classe, type, oldNom, newNom);
+  }
+  private void renommerChamp(Class<? extends Element> classe, String type, String oldNom, String newNom) {
+    // renomme aussi le champ quand la correspondance prop<=>champ est directe (notamment dans la vue par défaut)
+    if (!champspos.get(classe).containsKey(type))
+      throw new IllegalArgumentException();
+    String[][] chps = champspos.get(classe).get(type);
+    if (!adresses.get(classe).get(type).containsKey(oldNom))
+      throw new IllegalArgumentException();
+    if (adresses.get(classe).get(type).get(oldNom).getLongueur()>1) return;
+    if (!adresses.get(classe).get(type).get(oldNom).prop.equals(oldNom)) return;
+    boolean fait = false;
+    for (int niv = 0; niv<chps.length; niv++) {
+      for (int pos = 0; pos<chps[niv].length; pos++)
+        if (chps[niv][pos].equals(oldNom)) {
+          chps[niv][pos] = newNom;
+          fait = true;
+          break;
+        }
+      if (fait) break;
+    }
+    if (!fait) throw new IllegalArgumentException();
+    adresses.get(classe).get(type).put(newNom, adresses.get(classe).get(type).get(oldNom));
+    adresses.get(classe).get(type).remove(oldNom);
+    modifiables.get(classe).get(type).put(newNom, modifiables.get(classe).get(type).get(oldNom));
+    modifiables.get(classe).get(type).remove(oldNom);
+    if (champsId.get(classe).containsKey(type)&&champsId.get(classe).get(type).equals(oldNom))
+      champsId.get(classe).put(type, newNom);
+    if (stylesValeursElements.get(classe).containsKey(type)
+            &&stylesValeursElements.get(classe).get(type).containsKey(oldNom)) {
+      stylesValeursElements.get(classe).get(type).put(newNom,
+              stylesValeursElements.get(classe).get(type).get(oldNom));
+      stylesValeursElements.get(classe).get(type).remove(oldNom);
+    }
+  }
+  private void fusionnerProp(Class<? extends Element> classe, String type, String oldNom, String newNom) {
+    // pour le moment, on se contente de supprimer tous les champs qui utilisent l'ancienne prop
+    // c'est un peu grossier...
+    supprimerProp(classe, type, oldNom);
+  }
+  private void supprimerProp(Class<? extends Element> classe, String type, String prop) {
+    // on parcourt tous les champs et les adresses correspondantes
+    for (Class<? extends Element> cl : typesAVoir.keySet())
+      for (String typ : typesAVoir.get(cl)) {
+        ArrayList<String> chpsASup = new ArrayList<String>();
+        ArrayList<String> chps = getListeChamps(cl, typ);
+        HashMap<String, Integer> nivx = getNiveauxChampsAVoir(cl, typ);
+        HashMap<String, Integer> poss = getPositionsChampsAVoir(cl, typ);
+        for (String ch : chps) {
+          Adresse ad = adresses.get(cl).get(typ).get(ch);
+          if (ad.getLastJalon().classe==classe&&type.equals(ad.getLastJalon().type)&&prop.equals(ad.prop)) {
+            chpsASup.add(ch);
+            adresses.get(cl).get(typ).remove(ch);
+            modifiables.get(cl).get(typ).remove(ch);
+            if (ch.equals(champsId.get(cl).get(typ)))
+              champsId.get(cl).remove(typ);
+            if (stylesValeursElements.get(cl).containsKey(typ))
+              stylesValeursElements.get(cl).get(typ).remove(ch);
+            nivx.remove(ch);
+            poss.remove(ch);
+          }
+        }
+        chps.removeAll(chpsASup);
+        champspos.get(cl).put(typ, ordonnerChamps(chps, nivx, poss));
+      }
+  }
+  public Unite[] getUnites(String type) {
+    Unite[] units = corpus.getUnites(type).toArray(new Unite[0]);
+    Arrays.sort(units);
+    return units;
+  }
+  public Unite[] getUnitesAVoir(String type) {
+    if (unitesAVoir.get(type)==null) {
+      return new Unite[0];
+    }
+    return unitesAVoir.get(type);
+  }
+  public Relation[] getRelations(String type) {
+    Relation[] rels = corpus.getRelations(type).toArray(new Relation[0]);
+    Arrays.sort(rels);
+    return rels;
+  }
+  public Relation[] getRelationsAVoir(String type) {
+    // Pour l'instant, toutes les relations de ce type, mais ça peut changer avec la mise en place des sélections
+    // nécessitera peut-être la mise en place d'une variable relationsAVoir (comme pour les unités) 
+    Relation[] rels = corpus.getRelations(type).toArray(new Relation[0]);
+    Arrays.sort(rels);
+    return rels;
+  }
+  public Schema[] getSchemas(String type) {
+    Schema[] schs = corpus.getSchemas(type).toArray(new Schema[0]);
+    Arrays.sort(schs);
+    return schs;
+  }
+  public Schema[] getSchemasAVoir(String type) {
+    // Pour l'instant, tous les schémas de ce type, mais ça peut changer avec la mise en place des sélections
+    // nécessitera peut-être la mise en place d'une variable schemasAVoir (comme pour les unités) 
+    Schema[] schs = corpus.getSchemas(type).toArray(new Schema[0]);
+    Arrays.sort(schs);
+    return schs;
+  }
+  public Element[] getElements(Class<? extends Element> classe, String type) {
+    if (classe==Unite.class) return getUnites(type);
+    if (classe==Relation.class) return getRelations(type);
+    if (classe==Schema.class) return getSchemas(type);
+    throw new UnsupportedOperationException("sous-classe non traitée");
+  }
+  public Element[] getElementsAVoir(Class<? extends Element> classe, String type) {
+    if (classe==Unite.class) return getUnitesAVoir(type);
+    if (classe==Relation.class) return getRelationsAVoir(type);
+    if (classe==Schema.class) return getSchemasAVoir(type);
+    throw new UnsupportedOperationException("sous-classe non traitée");
+  }
+  public String getTexteUnite(Unite unit) {  // utilisé par ModeleChaines et par ModeleStatsGeometrie - à revoir : pas très efficace
+    return corpus.getTexteUnite(unit);
+  }
+  public String getIdElement(Element elt) {  // utilisé  par PanneauOccurrences
+    String type = elt.getType();
+    Class<? extends Element> classe = elt.getClass();
+    String champId = getChampId(classe, type);
+    String id;
+    if (champId!=null) {
+      id = getValeurChamp(elt, champId);
+      if (!id.isEmpty()) return id;
+    }
+    Element[] listeElts = getElements(classe, type);
+    if (listeElts==null) return "";
+    int no = Arrays.binarySearch(listeElts, elt);
+    if (no<0) return "";
+    return type+"-"+Integer.toString(no+1);
+  }
+  private String[] getIdElements(Class<? extends Element> classe, String type,
+          Element[] eltsCorpus, Element[] eltsATraiter) {
+    // eltsATraiter doit être  trié ; s'il est null, on prend toutes les éléments du corpus de ce type 
+    String champId = getChampId(classe, type);
+    String[] ids = new String[eltsATraiter==null ? eltsCorpus.length : eltsATraiter.length];
+    String id;
+    int i = 0;
+    for (int no = 0; no<eltsCorpus.length; no++) {
+      if (eltsATraiter==null||eltsATraiter[i]==eltsCorpus[no]) {
+        id = champId==null ? "" : getValeurChamp(eltsCorpus[no], champId);
+        ids[i++] = id.isEmpty() ? type+"-"+Integer.toString(no+1) : id;
+      }
+    }
+    return ids;
+  }
+  public String[] getIdUnites(String type) {  // toutes les unités du corpus de ce type 
+    return getIdElements(Unite.class, type, getUnites(type), null);
+  }
+  public String[] getIdUnites(String type, Unite[] unites) {    // unites doit être  trié 
+    return getIdElements(Unite.class, type, getUnites(type), unites);
+  }
+  public String[] getIdRelations(String type) {  // toutes les relations du corpus de ce type 
+    return getIdElements(Relation.class, type, getRelations(type), null);
+  }
+  public String[] getIdRelations(String type, Relation[] relations) {   // relations doit être  trié 
+    return getIdElements(Relation.class, type, getRelations(type), relations);
+  }
+  public String[] getIdSchemas(String type) {  // tous les schémas du corpus de ce type 
+    return getIdElements(Schema.class, type, getSchemas(type), null);
+  }
+  public String[] getIdSchemas(String type, Schema[] schemas) {    // schemas doit être  trié 
+    return getIdElements(Schema.class, type, getSchemas(type), schemas);
+  }
+  public String[] getIdElements(Class<? extends Element> classe, String type) {
+    if (classe==Relation.class) return getIdRelations(type);
+    if (classe==Schema.class) return getIdSchemas(type);
+    return getIdUnites(type);
+  }
+  /**
+   * Fonction pour le coloriage
+   */
+  public UniteColoree[] getUnitesAColorier() {
+    ArrayList<UniteColoree> unites = new ArrayList<UniteColoree>();
+    for (Class<? extends Element> classe : stylesElements.keySet())
+      for (String type : stylesElements.get(classe).keySet()) {
+        for (Unite unit : Element.getUnitesSousjacentes(getElementsAVoir(classe, type)))
+          unites.add(new UniteColoree(unit, stylesElements.get(classe).get(type)));
+      }
+    for (Class<? extends Element> classe : stylesValeursElements.keySet())
+      for (String type : stylesValeursElements.get(classe).keySet())
+        for (String champ : stylesValeursElements.get(classe).get(type).keySet())
+          for (String valeur : stylesValeursElements.get(classe).get(type).get(champ).keySet()) {
+            for (Unite unit : Element.getUnitesSousjacentes(getElementsAVoirValeurChamp(classe, type, champ, valeur)))
+              unites.add(new UniteColoree(unit, stylesValeursElements.get(classe).get(type).get(champ).get(valeur)));
+          }
+    return unites.toArray(new UniteColoree[0]);
+  }
+  public Element[] getElementsAVoirValeurChamp(Class<? extends Element> classe,
+          String type, String champ, String valeur) {
+    ArrayList<Element> elts = new ArrayList<Element>();
+    for (Element elt : getElementsAVoir(classe, type))
+      if (valeur.equals(getValeurChamp(elt, champ))) elts.add(elt);
+    return elts.toArray(new Element[0]);
+  }
+  /**
+   * Fonctions de comptage pour les stats
+   */
+  public int getNbElementsAVoir(Class<? extends Element> classe, String type) {
+    return getElementsAVoir(classe, type).length;
+  }
+  public HashMap<String, Integer> compterOccurrencesFiltrees(Class<? extends Element> classe,
+          String type, String champCible, String champFiltre, String[] valeursChampFiltre) {
+    HashMap<String, Integer> compte = initCompte(classe, type, champCible);
+    for (Element elt : getElementsAVoir(classe, type)) {
+      String valCible = getValeurChamp(elt, champCible);
+      if (champFiltre==null) {
+        compte.put(valCible, compte.get(valCible)+1);
+      } else {
+        String valfiltre = getValeurChamp(elt, champFiltre);
+        for (Object valchfiltre : valeursChampFiltre) {
+          if (valfiltre.equals(valchfiltre)) {
+            compte.put(valCible, compte.get(valCible)+1);
+            break;
+          }
+        }
+      }
+    }
+    return compte;
+  }
+  public HashMap<String, HashMap<String, Integer>> compterOccurrencesCorrelees(
+          Class<? extends Element> classe, String type, String champ1, String champ2) {
+    HashMap<String, HashMap<String, Integer>> compte = new HashMap<String, HashMap<String, Integer>>();
+    for (String val : getValeursChamp(classe, type, champ1)) {
+      compte.put(val, initCompte(classe, type, champ2));
+    }
+    compte.put("", initCompte(classe, type, champ2));
+    for (Element elt : getElementsAVoir(classe, type)) {
+      String val1 = getValeurChamp(elt, champ1);
+      String val2 = getValeurChamp(elt, champ2);
+      compte.get(val1).put(val2, compte.get(val1).get(val2)+1);
+    }
+    return compte;
+  }
+  private HashMap<String, Integer> initCompte(Class<? extends Element> classe, String type, String champ) {
+    HashMap<String, Integer> hm = new HashMap<String, Integer>();
+    for (String val : getValeursChamp(classe, type, champ)) {
+      hm.put(val, 0);
+    }
+    hm.put("", 0);
+    return hm;
+  }
+  public Element[] getDoubleSelectionOccurrences(Class<? extends Element> classe, String type,
+          String champ1, String[] valeurs1, String champ2, String[] valeurs2) {
+    ArrayList<Element> aliste = new ArrayList<Element>();
+    for (Element elt : getElementsAVoir(classe, type)) {
+      if (verifierContrainteFiltre(elt, champ1, valeurs1)&&verifierContrainteFiltre(elt, champ2, valeurs2)) {
+        aliste.add(elt);
+      }
+    }
+    Element[] res = aliste.toArray(new Element[0]);
+    Arrays.sort(res);
+    return res;
+  }
+  private boolean verifierContrainteFiltre(Element elt, String champ, String[] valeurs) {
+    if (champ==null) {
+      return true;
+    }
+    String valeur = getValeurChamp(elt, champ);
+    for (String val : valeurs) {
+      if (val.equals(valeur)) {
+        return true;
+      }
+    }
+    return false;
+  }
+  public Matrix getMatrice(Class<? extends Element> classe, String type, String[] champsSelect, Element[] eltsSelect) {
+    HashMap<String, HashMap<String, Integer>> numeros = new HashMap<String, HashMap<String, Integer>>();
+    int nb = 0;
+    for (String champ : champsSelect) {
+      numeros.put(champ, new HashMap<String, Integer>());
+      numeros.get(champ).put("", nb++);
+      for (String val : getValeursChamp(classe, type, champ)) {
+        numeros.get(champ).put(val, nb++);
+      }
+    }
+    double[][] matrice = new double[eltsSelect.length][nb];
+    for (int i = 0; i<eltsSelect.length; i++) {
+      for (String champ : champsSelect) {
+        matrice[i][numeros.get(champ).get(getValeurChamp(eltsSelect[i], champ))] = 1.;
+      }
+    }
+    return new Matrix(matrice, eltsSelect.length, nb);
+  }
+  public SparseMatrix getMatriceCreuse(Class<? extends Element> classe, String type,
+          String[] champsSelect, Element[] eltsSelect) {
+    HashMap<String, HashMap<String, Integer>> numeros =
+            new HashMap<String, HashMap<String, Integer>>();
+    int nb = 0;
+    for (String champ : champsSelect) {
+      numeros.put(champ, new HashMap<String, Integer>());
+      numeros.get(champ).put("", nb++);
+      for (String val : getValeursChamp(classe, type, champ))
+        numeros.get(champ).put(val, nb++);
+    }
+//    double[][] matrice = new double[eltsSelect.length][nb];
+    ArrayList<Integer> rows = new ArrayList<Integer>();
+    ArrayList<Integer> cols = new ArrayList<Integer>();
+    for (int i = 0; i<eltsSelect.length; i++)
+      for (String champ : champsSelect) {
+        rows.add(i);
+        cols.add(numeros.get(champ).get(getValeurChamp(eltsSelect[i], champ)));
+      }
+    return new SparseMatrix(eltsSelect.length, nb, rows, cols, 1);
+  }
+
+  public static class TripletValTypique {
+    public String champ;
+    public String valeur;
+    public float pourcentage;
+    public TripletValTypique(String champ, String valeur, float pourcentage) {
+      this.champ = champ;
+      this.valeur = valeur;
+      this.pourcentage = pourcentage;
+    }
+  }
+  public TripletValTypique[] getValTypiques(Class<? extends Element> classe,
+          String type, Element[] elts) {
+    ArrayList<String> chps = new ArrayList<String>();
+    ArrayList<String> vals = new ArrayList<String>();
+    ArrayList<Float> pcts = new ArrayList<Float>();
+    HashMap<String, Integer> compte = new HashMap<String, Integer>();
+    int total = elts.length;
+    for (String champ : getListeChamps(classe, type)) {
+      compte.clear();
+      for (Element elt : elts) {
+        String val = getValeurChamp(elt, champ);
+        if (val.isEmpty()) continue;
+        if (compte.containsKey(val)) compte.put(val, compte.get(val)+1);
+        else compte.put(val, 1);
+      }
+      for (String val : compte.keySet()) if (2*compte.get(val)>total) {
+          chps.add(champ);
+          vals.add(val);
+          pcts.add(((float) compte.get(val))/total);
+          break;
+        }
+    }
+    TripletValTypique[] triplets = new TripletValTypique[chps.size()];
+    for (int i = 0; i<chps.size(); i++)
+      triplets[i] = new TripletValTypique(chps.get(i), vals.get(i), pcts.get(i));
+    return triplets;
+  }
+  public String[] getIdListeElements(Class<? extends Element> classe,
+          String type, Element[] elts) {
+    return getIdElements(classe, type, elts, null);
+  }
+  public String[][] getValeursChampsListeElements(String[] champs, Element[] elts) {
+    String[][] valeurs = new String[elts.length][champs.length];
+    for (int i = 0; i<elts.length; i++) for (int j = 0; j<champs.length; j++)
+        valeurs[i][j] = getValeurChamp(elts[i], champs[j]);
+    return valeurs;
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/Vue.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVuePresentation.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVuePresentation.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVuePresentation.java	(revision 3653)
@@ -0,0 +1,163 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.vue;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.table.*;
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class VisuVuePresentation extends JPanel implements ActionListener {
+  private VisuVue visuVue;
+  private Vue vue;
+  private JTable tableauChampsAVoir;
+  private JComboBox saisieChampId;
+  private Class<? extends Element> classeSelected;
+  private String typeSelected;
+  private HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir;
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>> modifiabiliteChampsAVoir;
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> niveauxChampsAVoir;
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> positionsChampsAVoir;
+  private HashMap<Class<? extends Element>, HashMap<String, String>> champsId;
+  VisuVuePresentation(VisuVue visuVue, Vue vue,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, String>> champsId,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>> modifiabiliteChampsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> niveauxChampsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> positionsChampsAVoir) {
+    super(new BorderLayout());
+    this.visuVue = visuVue;
+    this.vue = vue;
+    this.champsAVoir = champsAVoir;
+    this.champsId = champsId;
+    this.modifiabiliteChampsAVoir = modifiabiliteChampsAVoir;
+    this.niveauxChampsAVoir = niveauxChampsAVoir;
+    this.positionsChampsAVoir = positionsChampsAVoir;
+    classeSelected = null;
+    typeSelected = null;
+    // Panneau du champ identifiant
+    saisieChampId = new JComboBox();
+    saisieChampId.setEditable(false);
+    saisieChampId.addActionListener(this);
+    JPanel panneauChampId = new JPanel();
+    panneauChampId.add(new JLabel("Choix d'un champ identifiant"));
+    panneauChampId.add(saisieChampId);
+    add(panneauChampId, BorderLayout.NORTH);
+    // Le tableau des champs à visualiser
+    ModeleTableauChampsAVoir donneesChampsAVoir = new ModeleTableauChampsAVoir();
+    tableauChampsAVoir = new JTable(donneesChampsAVoir);
+    JScrollPane scroll2 = new JScrollPane(tableauChampsAVoir);
+    JPanel panneauChampsAVoir = new JPanel();
+    panneauChampsAVoir.add(scroll2);
+    add(panneauChampsAVoir, BorderLayout.CENTER);
+  }
+  void setTypeSelected(Class<? extends Element> classe, String type) {
+    classeSelected = classe;
+    typeSelected = type;
+    reinitialiser();
+  }
+  void reinitialiser() {
+    ((ModeleTableauChampsAVoir) tableauChampsAVoir.getModel()).fireTableDataChanged();
+    saisieChampId.removeActionListener(this);
+    if (typeSelected==null) saisieChampId.setModel(new DefaultComboBoxModel());
+    else {
+      String[] champs = champsAVoir.get(classeSelected).get(typeSelected).toArray(new String[0]);
+      champs = Tableaux.insererStringEnTete(champs, "<aucun>");
+      saisieChampId.setModel(new DefaultComboBoxModel(champs));
+      if (champsId.get(classeSelected).containsKey(typeSelected))
+        saisieChampId.setSelectedItem(champsId.get(classeSelected).get(typeSelected));
+      else saisieChampId.setSelectedIndex(0);
+    }
+    saisieChampId.addActionListener(this);
+  }
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource()==saisieChampId) {
+        if (saisieChampId.getSelectedIndex()==0)
+          champsId.get(classeSelected).remove(typeSelected);
+        else
+          champsId.get(classeSelected).put(typeSelected, (String) saisieChampId.getSelectedItem());
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  private static final String[] nomsColonnes = new String[]{
+    "<html><span style=\"font-weight:900 \">Champ</span>",
+    "<html><span style=\"font-weight:900 \">Niveau</span>",
+    "<html><span style=\"font-weight:900 \">Position</span>",
+    "<html><span style=\"font-weight:900 \">Modifiable ?</span>"
+  };
+  private static final Class[] classesColonnes = new Class[]{String.class, Integer.class, Integer.class, Boolean.class};
+
+  private class ModeleTableauChampsAVoir extends AbstractTableModel {
+    public int getColumnCount() {
+      return nomsColonnes.length;
+    }
+    public int getRowCount() {
+      return (typeSelected==null||!champsAVoir.get(classeSelected).containsKey(typeSelected)) ? 0 : champsAVoir.get(classeSelected).get(typeSelected).size();
+    }
+    public Object getValueAt(int row, int col) {
+      String champ = champsAVoir.get(classeSelected).get(typeSelected).get(row);
+      switch (col) {
+        case 0:
+          return champ;
+        case 1:
+          return niveauxChampsAVoir.get(classeSelected).get(typeSelected).get(champ);
+        case 2:
+          return positionsChampsAVoir.get(classeSelected).get(typeSelected).get(champ);
+        case 3:
+          return modifiabiliteChampsAVoir.get(classeSelected).get(typeSelected).get(champ);
+        default:
+          throw new IndexOutOfBoundsException();
+      }
+    }
+    @Override
+    public String getColumnName(int col) {
+      return nomsColonnes[col];
+    }
+    @Override
+    public Class getColumnClass(int col) {
+      return classesColonnes[col];
+    }
+    @Override
+    public boolean isCellEditable(int row, int col) {
+      if (col==3&&classeSelected==Unite.class) {
+        String champ = champsAVoir.get(classeSelected).get(typeSelected).get(row);
+        String prop = visuVue.getPropChamp(classeSelected, typeSelected, champ);
+        if (Structure.FORME.equals(prop)) return false;
+      }
+      return col>0;
+    }
+    @Override
+    public void setValueAt(Object aValue, int row, int col) {
+      String champ = champsAVoir.get(classeSelected).get(typeSelected).get(row);
+      switch (col) {
+        case 1:
+          niveauxChampsAVoir.get(classeSelected).get(typeSelected).put(champ, (Integer) aValue);
+          return;
+        case 2:
+          positionsChampsAVoir.get(classeSelected).get(typeSelected).put(champ, (Integer) aValue);
+          return;
+        case 3:
+          modifiabiliteChampsAVoir.get(classeSelected).get(typeSelected).put(champ, (Boolean) aValue);
+          return;
+        default:
+          throw new IndexOutOfBoundsException();
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVuePresentation.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVue.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVue.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVue.java	(revision 3653)
@@ -0,0 +1,436 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.vue;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+import javax.swing.text.SimpleAttributeSet;
+import visuAnalec.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class VisuVue extends JFrame implements VueListener, ListSelectionListener, ChangeListener {
+	static private VisuVue instance = null;
+	private Vue vue;
+	// Les données spécifiant la vue (échangées avec vue à l'initialisation et à la validation)
+	private HashMap<Class<? extends Element>, HashMap<String, Boolean>> isTypesAVoir =
+			new HashMap<Class<? extends Element>, HashMap<String, Boolean>>();
+	private HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adressesAVoir =
+			new HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>>();
+	private HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir =
+			new HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>>();
+	private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> niveauxChampsAVoir =
+			new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>>();
+	private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>> positionsChampsAVoir =
+			new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Integer>>>();
+	private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>> modifiabiliteChampsAVoir =
+			new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, Boolean>>>();
+	private HashMap<Class<? extends Element>, HashMap<String, String>> champsId =
+			new HashMap<Class<? extends Element>, HashMap<String, String>>();
+	private HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>> stylesElements =
+			new HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>>();
+	private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>> stylesValeursElements =
+			new HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>>();  // le tableau des types à voir
+	private JTable tableauTypes;
+	private JTabbedPane panneauTabule;
+	VisuVueExtraction visuVueExtraction;
+	VisuVuePresentation visuVuePresentation;
+	VisuVueColoriage visuVueColoriage;
+
+	static public VisuVue newVisuVue(Container fenetre, Vue vue) {
+		if (instance!=null) instance.fermerFenetre();
+		instance = new VisuVue(fenetre, vue);
+		return instance;
+	}
+
+	@SuppressWarnings("unchecked")
+	private VisuVue(Container fenetre, Vue vue) {
+		super("Gestion de la vue");
+		if (fenetre != null) {
+			Point locFenetre = new Point(fenetre.getX()+20, fenetre.getY()+50);
+			Dimension dimFenetre = new Dimension(fenetre.getWidth(), fenetre.getHeight()-30);
+			setLocation(locFenetre);
+			setSize(dimFenetre);
+		}
+		this.vue = vue;
+		vue.addEventListener(this);
+		// initialisation des données spécifiant la vue
+		for (Class<? extends Element> classe : new Class[]{Unite.class, Relation.class, Schema.class}) {
+			isTypesAVoir.put(classe, new HashMap<String, Boolean>());
+			for (String type : vue.getTypes(classe))
+				isTypesAVoir.get(classe).put(type, false);
+			for (String type : vue.getTypesAVoir(classe))
+				isTypesAVoir.get(classe).put(type, true);
+			champsAVoir.put(classe, new HashMap<String, ArrayList<String>>());
+			adressesAVoir.put(classe, new HashMap<String, ArrayList<Adresse>>());
+			positionsChampsAVoir.put(classe, new HashMap<String, HashMap<String, Integer>>());
+			niveauxChampsAVoir.put(classe, new HashMap<String, HashMap<String, Integer>>());
+			modifiabiliteChampsAVoir.put(classe, new HashMap<String, HashMap<String, Boolean>>());
+			for (String type : vue.getTypes(classe)) {
+				champsAVoir.get(classe).put(type, new ArrayList<String>());
+				adressesAVoir.get(classe).put(type, new ArrayList<Adresse>());
+				niveauxChampsAVoir.get(classe).put(type, new HashMap<String, Integer>());
+				positionsChampsAVoir.get(classe).put(type, new HashMap<String, Integer>());
+				modifiabiliteChampsAVoir.get(classe).put(type, new HashMap<String, Boolean>());
+			}
+			for (String type : vue.getTypesAVoir(classe)) {
+				champsAVoir.get(classe).put(type, vue.getListeChamps(classe, type));
+				for (String nom : vue.getNomsChamps(classe, type))
+					adressesAVoir.get(classe).get(type).add(vue.getAdresseChamps(classe, type, nom));
+			}
+			champsId.put(classe, new HashMap<String, String>());
+			for (String type : vue.getTypesAVoir(classe))
+				if (vue.getChampId(classe, type)!=null)
+					champsId.get(classe).put(type, vue.getChampId(classe, type));
+			for (String type : vue.getTypesAVoir(classe)) {
+				positionsChampsAVoir.get(classe).put(type, vue.getPositionsChampsAVoir(classe, type));
+				niveauxChampsAVoir.get(classe).put(type, vue.getNiveauxChampsAVoir(classe, type));
+				modifiabiliteChampsAVoir.get(classe).put(type, new HashMap<String, Boolean>());
+				for (String champ : vue.getNomsChamps(classe, type))
+					modifiabiliteChampsAVoir.get(classe).get(type).put(champ, vue.isChampModifiable(classe, type, champ));
+			}
+			stylesElements.put(classe, new HashMap<String, SimpleAttributeSet>());
+			for (String type : vue.getTypesAVoir(classe))
+				if (vue.getStyleElements(classe, type)!=null)
+					stylesElements.get(classe).put(type, vue.getStyleElements(classe, type));
+			stylesValeursElements.put(classe, new HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>());
+			for (String type : vue.getTypesAVoir(classe))
+				if (vue.getStyleValeursElements(classe, type)!=null)
+					stylesValeursElements.get(classe).put(type, vue.getStyleValeursElements(classe, type));
+		}
+		// Tableau des types d'éléments à visualiser
+		Box panneauTypes = Box.createVerticalBox();
+
+		panneauTypes.add(Box.createVerticalGlue());
+		ModeleTableauTypes donneesTypes = new ModeleTableauTypes();
+		tableauTypes = new JTable(donneesTypes) {
+			@Override
+			public boolean isCellSelected(int row, int col) {
+				if (col==1) {
+					return false;
+				}
+				String classeType = ((ModeleTableauTypes) getModel()).classesTypes[row];
+				return isRowSelected(row)&&isTypesAVoir.get(GVisu.getClasse(classeType)).get(GVisu.getType(classeType));
+			}
+		};
+
+		tableauTypes.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+		tableauTypes.getSelectionModel().addListSelectionListener(this);
+
+		JScrollPane scroll1 = new JScrollPane(tableauTypes);
+
+		scroll1.setBorder(
+				new TitledBorder("Types d'éléments à visualiser"));
+		panneauTypes.add(scroll1);
+		// les boutons de validation
+
+		panneauTypes.add(Box.createVerticalGlue());
+		JPanel pCommandesValidation = new JPanel(new FlowLayout());
+		JButton valideModifs = new JButton(
+				new GAction("Valider") {
+					public void executer() {
+						validerModifVue();
+					}
+					;
+				});
+
+		JButton annuleModifs = new JButton(
+				new GAction("Annuler") {
+					public void executer() {
+						annulerModifVue();
+					}
+					;
+
+				});
+		pCommandesValidation.add(valideModifs, CENTER_ALIGNMENT);
+
+		pCommandesValidation.add(annuleModifs, CENTER_ALIGNMENT);
+
+		panneauTypes.add(pCommandesValidation);
+		// Les panneaux tabulés Extraction, Sélection, Présentation, Coloriage
+		panneauTabule = new JTabbedPane();
+
+		panneauTabule.addChangeListener(
+				this);
+		visuVueExtraction = new VisuVueExtraction(this, vue, champsAVoir, adressesAVoir);
+
+		panneauTabule.add(
+				"Extraction de propriétés", visuVueExtraction);
+		visuVuePresentation = new VisuVuePresentation(this, vue, champsAVoir, champsId,
+				modifiabiliteChampsAVoir, niveauxChampsAVoir, positionsChampsAVoir);
+
+		panneauTabule.add(
+				"Présentation des champs", visuVuePresentation);
+		visuVueColoriage = new VisuVueColoriage(this, vue, champsAVoir, adressesAVoir,
+				stylesElements, stylesValeursElements);
+
+		panneauTabule.add(
+				"Coloriage d'éléments", visuVueColoriage);
+		// cadre global de la fenêtre
+		JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, panneauTypes, panneauTabule);
+
+		setContentPane(split);
+
+		setVisible(
+				true);
+		split.setDividerLocation(
+				0.25);
+		//    visuVueExtraction.agencerPanneaux();
+		//
+		// initialisation de la sélection d'un premier type à voir (si possible)
+
+
+		for (int i = 0;
+				i<donneesTypes.getRowCount();
+				i++) {
+			if ((Boolean) donneesTypes.getValueAt(i, 1)) {
+				tableauTypes.setRowSelectionInterval(i, i);
+				tableauTypes.setColumnSelectionInterval(0, 0);
+				break;
+			}
+		}
+		// Fermeture de la fenêtre
+
+		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+
+		addWindowListener(
+				new WindowAdapter() {
+					@Override
+					public void windowClosing(WindowEvent evt) {
+						confirmerFermerFenetre();
+					}
+				});
+	}
+
+	public void stateChanged(ChangeEvent evt) {
+		if (((JTabbedPane) evt.getSource())!=panneauTabule) return;
+		try {
+			switch (panneauTabule.getSelectedIndex()) {
+			case 0:
+				return;
+			case 1:
+				visuVuePresentation.reinitialiser();
+				return;
+			case 2:
+				visuVueColoriage.reinitialiser();
+				return;
+			default:
+				throw new IndexOutOfBoundsException();
+			}
+		} catch (Throwable ex) {
+			GMessages.erreurFatale(ex);
+		}
+	}
+
+	private void validerModifVue() {
+		vue.modifierVueParSaisie(isTypesAVoir, adressesAVoir, champsAVoir, champsId, modifiabiliteChampsAVoir,
+				positionsChampsAVoir, niveauxChampsAVoir, stylesElements, stylesValeursElements);
+	}
+
+	private void annulerModifVue() {
+		fermerFenetre();
+	}
+
+	void ajouterChamp(Class<? extends Element> classe, String type, Adresse ad) {
+		String champ = Vue.trouveNomChampParDefaut(ad, champsAVoir.get(classe).get(type));
+		champsAVoir.get(classe).get(type).add(champ);
+		adressesAVoir.get(classe).get(type).add(ad);
+		modifiabiliteChampsAVoir.get(classe).get(type).put(champ, ad.getLongueur()==1);
+		positionsChampsAVoir.get(classe).get(type).put(champ, 0);
+		niveauxChampsAVoir.get(classe).get(type).put(champ, 0);
+	}
+
+	void renommerChamp(Class<? extends Element> classe, String type, int rg, String newNom) {
+		String oldNom = champsAVoir.get(classe).get(type).get(rg);
+		champsAVoir.get(classe).get(type).set(rg, newNom);
+		if (champsId.get(classe).containsKey(type)&&oldNom.equals(champsId.get(classe).get(type))) {
+			champsId.get(classe).put(type, newNom);
+		}
+		modifiabiliteChampsAVoir.get(classe).get(type).put(newNom,
+				modifiabiliteChampsAVoir.get(classe).get(type).get(oldNom));
+		modifiabiliteChampsAVoir.get(classe).get(type).remove(oldNom);
+		positionsChampsAVoir.get(classe).get(type).put(newNom,
+				positionsChampsAVoir.get(classe).get(type).get(oldNom));
+		positionsChampsAVoir.get(classe).get(type).remove(oldNom);
+		niveauxChampsAVoir.get(classe).get(type).put(newNom,
+				niveauxChampsAVoir.get(classe).get(type).get(oldNom));
+		niveauxChampsAVoir.get(classe).get(type).remove(oldNom);
+		if (stylesValeursElements.get(classe).containsKey(type)
+				&&stylesValeursElements.get(classe).get(type).containsKey(oldNom)) {
+			stylesValeursElements.get(classe).get(type).
+			put(newNom, stylesValeursElements.get(classe).get(type).get(oldNom));
+			stylesValeursElements.get(classe).get(type).remove(oldNom);
+		}
+	}
+
+	void supprimerChamp(Class<? extends Element> classe, String type, int rg) {
+		String oldNom = champsAVoir.get(classe).get(type).get(rg);
+		champsAVoir.get(classe).get(type).remove(rg);
+		adressesAVoir.get(classe).get(type).remove(rg);
+		if (champsId.get(classe).containsKey(type)&&oldNom.equals(champsId.get(classe).get(type))) {
+			champsId.get(classe).remove(type);
+			modifiabiliteChampsAVoir.get(classe).get(type).remove(oldNom);
+			positionsChampsAVoir.get(classe).get(type).remove(oldNom);
+			niveauxChampsAVoir.get(classe).get(type).remove(oldNom);
+			if (stylesValeursElements.get(classe).containsKey(type)
+					&&stylesValeursElements.get(classe).get(type).containsKey(oldNom)) {
+				stylesValeursElements.get(classe).get(type).remove(oldNom);
+			}
+		}
+	}
+	String getPropChamp(Class<? extends Element> classe, String type, String champ) {
+		ArrayList<String> champs = champsAVoir.get(classe).get(type);
+		if(champs==null) return "";
+		int ind = champs.indexOf(champ);
+		if(ind<0) return "";
+		String prop = adressesAVoir.get(classe).get(type).get(ind).prop;
+		if(prop==null) return "";
+		return prop;
+
+	}
+
+	public void valueChanged(ListSelectionEvent evt) {
+		if ((ListSelectionModel) evt.getSource()!=tableauTypes.getSelectionModel())
+			return;
+		try {
+			if (evt.getValueIsAdjusting()) {
+				return;
+			}
+			int row = ((ListSelectionModel) evt.getSource()).getMinSelectionIndex();
+			if (row<0) {
+				visuVueExtraction.setTypeSelected(null, null);
+				visuVuePresentation.setTypeSelected(null, null);
+				visuVueColoriage.setTypeSelected(null, null);
+			} else {
+				String classeType = ((ModeleTableauTypes) tableauTypes.getModel()).classesTypes[row];
+				Class<? extends Element> classeSelected = GVisu.getClasse(classeType);
+				String typeSelected = GVisu.getType(classeType);
+				if (isTypesAVoir.get(classeSelected).get(typeSelected)) {
+					visuVueExtraction.setTypeSelected(classeSelected, typeSelected);
+					visuVuePresentation.setTypeSelected(classeSelected, typeSelected);
+					visuVueColoriage.setTypeSelected(classeSelected, typeSelected);
+				} else {
+					visuVueExtraction.setTypeSelected(null, null);
+					visuVuePresentation.setTypeSelected(null, null);
+					visuVueColoriage.setTypeSelected(null, null);
+				}
+			}
+		} catch (Throwable ex) {
+			GMessages.erreurFatale(ex);
+		}
+	}
+
+	public void traiterEvent(Message evt) {
+		switch (evt.getType()) {
+		case CLEAR_CORPUS:
+			fermerFenetre();
+			return;
+		case CORPUS_SAVED:
+			fermerFenetre();
+			return;
+		case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+			throw new UnsupportedOperationException("Fenêtre vue présente lors d'un message NEW_CORPUS ???");
+		case MODIF_TEXTE:
+			return;
+		case MODIF_VUE:
+			fermerFenetre();  // ferme même si la modif vient d'ici
+			return;
+		case MODIF_STRUCTURE:
+			fermerFenetre();
+			return;
+		case MODIF_ELEMENT:
+			return;
+		default:
+			throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+		}
+	}
+
+	private void confirmerFermerFenetre() {
+		try {
+			int rep = JOptionPane.showOptionDialog(this, "Valider les modifications ?",
+					"Fermeture de la fenêtre \"Structure des annotations\"", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
+					null, new Object[]{"Oui", "Non", "Annuler"}, "Non");
+			if (rep==2) {
+				return;
+			}
+			if (rep==0) {
+				validerModifVue();
+			}
+			annulerModifVue();
+		} catch (Throwable ex) {
+			GMessages.erreurFatale(ex);
+		}
+	}
+
+	private void fermerFenetre() {
+		vue.removeEventListener(this);
+		dispose();
+
+
+	}
+
+	private class ModeleTableauTypes extends AbstractTableModel {
+		String[] classesTypes;
+
+		private ModeleTableauTypes() {
+			super();
+			classesTypes = GVisu.getClassesTypes(vue.getTypes(Unite.class), vue.getTypes(Relation.class), vue.getTypes(Schema.class));
+		}
+
+		public int getColumnCount() {
+			return 2;
+		}
+
+		public int getRowCount() {
+			return classesTypes.length;
+		}
+
+		public Object getValueAt(int row, int col) {
+			String classeType = classesTypes[row];
+			return col==0 ? classeType : isTypesAVoir.get(GVisu.getClasse(classeType)).get(GVisu.getType(classeType));
+		}
+
+		@Override
+		public String getColumnName(int col) {
+			return col==0 ? "Types d'éléments" : "à voir";
+		}
+
+		@Override
+		public Class getColumnClass(int col) {
+			return col==0 ? String.class : Boolean.class;
+		}
+
+		@Override
+		public boolean isCellEditable(int row, int col) {
+			return col==1;
+		}
+
+		@Override
+		public void setValueAt(Object aValue, int row, int col) {
+			if (col==1) {
+				String classeType = classesTypes[row];
+				isTypesAVoir.get(GVisu.getClasse(classeType)).put(GVisu.getType(classeType), (Boolean) aValue);
+				tableauTypes.clearSelection();  // important : à faire même quand aValue est vrai
+				// pour que l'événement "ListSelection change" soit émis dans tous les cas
+				if ((Boolean) aValue) {
+					tableauTypes.setRowSelectionInterval(row, row);
+					tableauTypes.setColumnSelectionInterval(0, 0);
+				}
+			}
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVue.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVueExtraction.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVueExtraction.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVueExtraction.java	(revision 3653)
@@ -0,0 +1,243 @@
+package visuAnalec.vue;
+
+import java.awt.BorderLayout;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.TreeExpansionEvent;
+import javax.swing.event.TreeWillExpandListener;
+import javax.swing.table.*;
+import javax.swing.tree.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class VisuVueExtraction extends JPanel implements TreeWillExpandListener {
+  private VisuVue visuVue;
+  private Vue vue;
+  private JTable tableauChampsAVoir;
+  private JTree arbreChampsAExtraire;
+  private JPopupMenuChamp popupMenuChamp;
+  private Class<? extends Element> classeSelected;
+  private String typeSelected;
+  private HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adressesAVoir;
+  private HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir;
+  private JPanel panneauChampsExtraits;
+  private JPanel panneauAExtraire;
+  VisuVueExtraction(VisuVue visuVue, Vue vue,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adressesAVoir) {
+    super(new BorderLayout());
+    this.visuVue = visuVue;
+    this.vue = vue;
+    this.champsAVoir = champsAVoir;
+    this.adressesAVoir = adressesAVoir;
+    classeSelected = null;
+    typeSelected = null;
+//    // Panneau des champs extraits à visualiser
+  panneauChampsExtraits =new JPanel(new BorderLayout());
+    // Le tableau des champs à visualiser
+    ModeleTableauChampsAVoir donneesChampsAVoir = new ModeleTableauChampsAVoir();
+    tableauChampsAVoir = new JTable(donneesChampsAVoir);
+    popupMenuChamp = new JPopupMenuChamp();
+    popupMenuChamp.add(new ActionSupprimerChamp());
+
+    MouseListener popupListener = new MouseAdapter() {
+      @Override
+      public void mousePressed(MouseEvent e) {
+        maybeShowPopup(e);
+      }
+      @Override
+      public void mouseReleased(MouseEvent e) {
+        maybeShowPopup(e);
+      }
+      private void maybeShowPopup(MouseEvent e) {
+        try {
+          if (e.isPopupTrigger()) {
+            popupMenuChamp.rang = tableauChampsAVoir.rowAtPoint(e.getPoint());
+            ((JMenuItem) (popupMenuChamp.getSubElements()[0])).setText("supprimer le champ \"" +
+                    tableauChampsAVoir.getValueAt(popupMenuChamp.rang, 0) + "\"");
+            popupMenuChamp.show(e.getComponent(), e.getX(), e.getY());
+          }
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    };
+    tableauChampsAVoir.addMouseListener(popupListener);
+    tableauChampsAVoir.addKeyListener(new KeyAdapter() {
+      @Override
+      public void keyPressed(KeyEvent e) {
+        try {
+          if (e.getKeyCode() == KeyEvent.VK_DELETE && tableauChampsAVoir.getSelectedRowCount() == 1) {
+            ((ModeleTableauChampsAVoir) tableauChampsAVoir.getModel()).supprimerChamp(tableauChampsAVoir.getSelectedRow());
+          }
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    });
+    JScrollPane scroll2 = new JScrollPane(tableauChampsAVoir);
+    scroll2.setBorder(new TitledBorder("Propriétés à visualiser"));
+    panneauChampsExtraits.add(scroll2, BorderLayout.CENTER);
+
+    // Panneau des champs à extraire
+    panneauAExtraire = new JPanel(new BorderLayout());
+    ModeleArbreChampsAExtraire donneesChampsAExtraire = new ModeleArbreChampsAExtraire(vue);
+    arbreChampsAExtraire = new JTree(donneesChampsAExtraire);
+    arbreChampsAExtraire.addTreeWillExpandListener(this);
+    MouseListener ml2 = new MouseAdapter() {
+      @Override
+      public void mousePressed(MouseEvent e) {
+        try {
+          TreePath selPath = arbreChampsAExtraire.getPathForLocation(e.getX(), e.getY());
+          if (selPath != null && e.getClickCount() == 2) {
+            NoeudChampAExtraire noeud = (NoeudChampAExtraire) selPath.getLastPathComponent();
+            if (noeud.getAllowsChildren()) return;
+            else ajouterChamp(noeud.getAdresse());
+          }
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    };
+    arbreChampsAExtraire.addMouseListener(ml2);
+    JScrollPane scroll3 = new JScrollPane(arbreChampsAExtraire);
+    scroll3.setBorder(new TitledBorder("Extraction de nouvelles propriétés à visualiser"));
+    panneauAExtraire.add(scroll3, BorderLayout.CENTER);
+      // Dimensionnement 
+    add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,panneauChampsExtraits, panneauAExtraire),
+            BorderLayout.CENTER);
+  }
+//  void agencerPanneaux() {
+//        JSplitPane split = (JSplitPane) panneauChampsExtraits.getParent();
+//    split.setDividerLocation(2. / 3);
+//    revalidate();
+//    repaint();
+//  }
+  public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
+    NoeudChampAExtraire noeud = (NoeudChampAExtraire) event.getPath().getLastPathComponent();
+    if(noeud.isLeaf()) {
+      ModeleArbreChampsAExtraire donnees = (ModeleArbreChampsAExtraire) arbreChampsAExtraire.getModel();
+     donnees.setSousArbre(noeud);
+    }
+  }
+  public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
+    return;
+  }
+  void setTypeSelected(Class<? extends Element> classe, String type) {
+    classeSelected = classe;
+    typeSelected = type;
+    ((ModeleTableauChampsAVoir) tableauChampsAVoir.getModel()).fireTableDataChanged();
+    ((ModeleArbreChampsAExtraire) arbreChampsAExtraire.getModel()).setModele(classeSelected, typeSelected);
+  }
+  private void ajouterChamp(Adresse ad) {
+     for (Adresse ad0 : adressesAVoir.get(classeSelected).get(typeSelected)) {
+      if (ad.toString().equals(ad0.toString())) {
+        JOptionPane.showMessageDialog(tableauChampsAVoir.getTopLevelAncestor(),
+                "Ajout impossible : le champ d'adresse  " + ad.toString() + " existe déjà",
+                "Erreur d'ajout de champ", JOptionPane.ERROR_MESSAGE);
+        return;
+      }
+    }
+    visuVue.ajouterChamp(classeSelected, typeSelected, ad);
+    ((ModeleTableauChampsAVoir) tableauChampsAVoir.getModel()).fireTableDataChanged();
+  }
+
+  private class ModeleTableauChampsAVoir extends AbstractTableModel {
+    public int getColumnCount() {
+      return 2;
+    }
+    public int getRowCount() {
+      return (typeSelected == null || !champsAVoir.get(classeSelected).containsKey(typeSelected)) ? 0 : 
+        champsAVoir.get(classeSelected).get(typeSelected).size();
+    }
+    public Object getValueAt(int row, int col) {
+      return col == 0 ? champsAVoir.get(classeSelected).get(typeSelected).get(row) : 
+        adressesAVoir.get(classeSelected).get(typeSelected).get(row).toString();
+    }
+    @Override
+    public String getColumnName(int col) {
+      return col == 0 ? "Noms abrégés des champs" : "Noms complets des propriétés";
+    }
+    @Override
+    public boolean isCellEditable(int row, int col) {
+      return col == 0;
+    }
+    @Override
+    public void setValueAt(Object aValue, int row, int col) {
+      if (col != 0)   throw new IndexOutOfBoundsException();
+    visuVue.renommerChamp(classeSelected, typeSelected, row,  (String) aValue);
+    }
+    void supprimerChamp(int row) {
+      visuVue.supprimerChamp(classeSelected, typeSelected,row);
+      fireTableDataChanged();
+    }
+  }
+
+  private static class JPopupMenuChamp extends JPopupMenu {
+    int rang = -1;
+  }
+
+  private class ActionSupprimerChamp extends AbstractAction {
+    ActionSupprimerChamp() {
+      super("supprimer le champ");
+    }
+    public void actionPerformed(ActionEvent e) {
+      try {
+        int rg = ((JPopupMenuChamp) ((JMenuItem) e.getSource()).getParent()).rang;
+        ((ModeleTableauChampsAVoir) tableauChampsAVoir.getModel()).supprimerChamp(rg);
+      } catch (Throwable ex) {
+        GMessages.erreurFatale(ex);
+      }
+    }
+  }
+
+  private static class ModeleArbreChampsAExtraire extends DefaultTreeModel {
+    Vue vue;
+    ModeleArbreChampsAExtraire(Vue vue) {
+      super(null, true);
+      this.vue = vue;
+    }
+    void setModele(Class<? extends Element> classeRacine, String typeRacine) {
+      if (typeRacine == null) {
+        setRoot(null);
+      } else {
+        NoeudChampAExtraire racine = new NoeudChampAExtraire(
+                new Adresse(new Jalon(Jalon.Origine.ELT_0, classeRacine, typeRacine)));
+        setRoot(racine);
+        setSousArbre(racine);
+      }
+      reload();
+    }
+    void setSousArbre(NoeudChampAExtraire noeud) {
+      Adresse adresse = noeud.getAdresse();
+      for (String prop : vue.getNomsProps(adresse)) {
+        noeud.add(new NoeudChampAExtraire(new Adresse(adresse, prop)));
+      }
+      Jalon[] jalons = vue.getNextJalonsPotentiels(adresse);
+      for (Jalon jalon : jalons) {
+        noeud.add(new NoeudChampAExtraire(new Adresse(adresse, jalon)));
+      }
+    }
+  }
+
+  private static class NoeudChampAExtraire extends DefaultMutableTreeNode {
+    NoeudChampAExtraire(Adresse adresse) {
+      super(adresse, adresse.prop == null);
+    }
+    Adresse getAdresse() {
+      return (Adresse) getUserObject();
+    }
+    @Override
+    public String toString() {
+      if (getAdresse().prop == null) return getAdresse().getLastJalon().toString();
+      return getAdresse().prop;
+    }
+  }
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVueExtraction.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVueColoriage.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVueColoriage.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVueColoriage.java	(revision 3653)
@@ -0,0 +1,434 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.vue;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.util.ArrayList;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.StyleConstants;
+import javax.swing.tree.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class VisuVueColoriage extends JPanel implements TreeWillExpandListener {
+  private VisuVue visuVue;
+  private int indexTab;
+  private Vue vue;
+  private JTable tableauValeursAColorier;
+  private JTree arbreValeursAChoisir;
+  private JPopupMenuValeur popupMenuValeur;
+  private Class<? extends Element> classeSelected;
+  private String typeSelected;
+  private HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir;
+  private HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adressesAVoir;
+  private HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>> stylesElements;
+  private HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>> stylesValeursElements;
+  private JPanel panneauValeursChoisies;
+  private JPanel panneauValeursAChoisir;
+  VisuVueColoriage(VisuVue visuVue, Vue vue,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adressesAVoir,
+          HashMap<Class<? extends Element>, HashMap<String, SimpleAttributeSet>> stylesElements,
+          HashMap<Class<? extends Element>, HashMap<String, HashMap<String, HashMap<String, SimpleAttributeSet>>>> stylesValeursElements) {
+    super(new BorderLayout());
+    this.visuVue = visuVue;
+    this.vue = vue;
+    this.champsAVoir = champsAVoir;
+    this.adressesAVoir = adressesAVoir;
+    this.stylesElements = stylesElements;
+    this.stylesValeursElements = stylesValeursElements;
+    classeSelected = null;
+    typeSelected = null;
+//    // Panneau des valeurs choisies à colorier
+    panneauValeursChoisies = new JPanel();
+    // Le tableau des valeurs à colorier
+    ModeleTableauValeursAColorier donneesValeursAColorier = new ModeleTableauValeursAColorier();
+    tableauValeursAColorier = new JTable(donneesValeursAColorier);
+    GVisu.CouleurTableEditor couleurcombo =
+            new GVisu.CouleurTableEditor(GVisu.getCouleursEtNoirEtBlanc());
+    tableauValeursAColorier.setDefaultEditor(Color.class, couleurcombo);
+    tableauValeursAColorier.setDefaultRenderer(Color.class, new GVisu.CouleurCellRenderer());
+    popupMenuValeur = new JPopupMenuValeur();
+    popupMenuValeur.add(new ActionSupprimerValeur());
+
+    MouseListener popupListener = new MouseAdapter() {
+      @Override
+      public void mousePressed(MouseEvent e) {
+        maybeShowPopup(e);
+      }
+      @Override
+      public void mouseReleased(MouseEvent e) {
+        maybeShowPopup(e);
+      }
+      private void maybeShowPopup(MouseEvent e) {
+        try {
+          if (e.isPopupTrigger()) {
+            int rg = popupMenuValeur.rang;
+            popupMenuValeur.rang = tableauValeursAColorier.rowAtPoint(e.getPoint());
+            ((JMenuItem) (popupMenuValeur.getSubElements()[0])).setText("supprimer ce coloriage");
+            popupMenuValeur.show(e.getComponent(), e.getX(), e.getY());
+          }
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    };
+    tableauValeursAColorier.addMouseListener(popupListener);
+    tableauValeursAColorier.addKeyListener(new KeyAdapter() {
+      @Override
+      public void keyPressed(KeyEvent e) {
+        try {
+          if (e.getKeyCode()==KeyEvent.VK_DELETE&&tableauValeursAColorier.getSelectedRowCount()==1) {
+            ((ModeleTableauValeursAColorier) tableauValeursAColorier.getModel()).supprimerRangee(
+                    tableauValeursAColorier.getSelectedRow());
+          }
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    });
+    JScrollPane scroll2 = new JScrollPane(tableauValeursAColorier);
+    scroll2.setBorder(new TitledBorder("Elements à colorier"));
+    panneauValeursChoisies.add(scroll2, BorderLayout.CENTER);
+    // Panneau des valeurs à choisir
+    panneauValeursAChoisir = new JPanel(new BorderLayout());
+    // L'arbre des champs à extraire
+    ModeleArbreValeursAChoisir donneesValeursAChoisir =
+            new ModeleArbreValeursAChoisir(vue, champsAVoir, adressesAVoir);
+    arbreValeursAChoisir = new JTree(donneesValeursAChoisir);
+    arbreValeursAChoisir.addTreeWillExpandListener(this);
+    MouseListener ml2 = new MouseAdapter() {
+      @Override
+      public void mousePressed(MouseEvent e) {
+        try {
+          TreePath selPath = arbreValeursAChoisir.getPathForLocation(e.getX(), e.getY());
+          if (selPath!=null&&e.getClickCount()==2) {
+            NoeudValeurAChoisir noeud = (NoeudValeurAChoisir) selPath.getLastPathComponent();
+            if (noeud.getAllowsChildren()) return;
+            else ajouterValeur(noeud.champ, noeud.valeur);
+          }
+        } catch (Throwable ex) {
+          GMessages.erreurFatale(ex);
+        }
+      }
+    };
+    arbreValeursAChoisir.addMouseListener(ml2);
+    JScrollPane scroll3 = new JScrollPane(arbreValeursAChoisir);
+    scroll3.setBorder(new TitledBorder("Choix de nouvelles valeurs à colorier"));
+    panneauValeursAChoisir.add(scroll3, BorderLayout.CENTER);
+    // Dimensionnement 
+    add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, panneauValeursChoisies, panneauValeursAChoisir),
+            BorderLayout.CENTER);
+  }
+//    void agencerPanneaux() {
+//        JSplitPane split = (JSplitPane) panneauValeursChoisies.getParent();
+//    split.setDividerLocation(2. / 3);
+//    revalidate();
+//    repaint();
+//    }
+  public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
+    NoeudValeurAChoisir noeud = (NoeudValeurAChoisir) event.getPath().getLastPathComponent();
+    if (noeud.isLeaf()) {
+      ModeleArbreValeursAChoisir donnees = (ModeleArbreValeursAChoisir) arbreValeursAChoisir.getModel();
+      donnees.setSousArbre(noeud);
+    }
+  }
+  public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
+    return;
+  }
+  void setTypeSelected(Class<? extends Element> classe, String type) {
+    classeSelected = classe;
+    typeSelected = type;
+    ((ModeleTableauValeursAColorier) tableauValeursAColorier.getModel()).reinitialiser();
+    ((ModeleArbreValeursAChoisir) arbreValeursAChoisir.getModel()).setModele(classeSelected, typeSelected);
+  }
+  private void ajouterValeur(String champ, String valeur) {
+    if (champ.isEmpty())
+      ((ModeleTableauValeursAColorier) tableauValeursAColorier.getModel()).ajouterTousAColorier();
+    else
+      ((ModeleTableauValeursAColorier) tableauValeursAColorier.getModel()).ajouterValeurAColorier(champ, valeur);
+  }
+  void reinitialiser() {
+    ((ModeleTableauValeursAColorier) tableauValeursAColorier.getModel()).reinitialiser();
+    ((ModeleArbreValeursAChoisir) arbreValeursAChoisir.getModel()).setModele(classeSelected, typeSelected);
+  }
+  private static final String[] nomsColonnes = new String[]{
+    "Champ",
+    "Valeur",
+    "<html><span style=\"font-weight:900 \">Gras</span>",
+    "<html><span style=\"font-style:italic \">Italique</span>",
+    "<html><span style=\"text-decoration:underline \">Souligné</span>",
+    "<html><span style=\"color:red \">Couleur</span>",
+    "<html><span style=\"background-color:yellow \">Fond</span>",};
+  private static final Class[] classesColonnes = new Class[]{
+    String.class, String.class, Boolean.class, Boolean.class, Boolean.class, Color.class, Color.class
+  };
+
+  private class ModeleTableauValeursAColorier extends AbstractTableModel {
+    private ArrayList<String> champs = new ArrayList<String>();
+    private ArrayList<String> valeurs = new ArrayList<String>();
+    private ArrayList<Boolean> gras = new ArrayList<Boolean>();
+    private ArrayList<Boolean> italiques = new ArrayList<Boolean>();
+    private ArrayList<Boolean> soulignes = new ArrayList<Boolean>();
+    private ArrayList<Color> couleurs = new ArrayList<Color>();
+    private ArrayList<Color> fonds = new ArrayList<Color>();
+    private void reinitialiser() {
+      viderTableau();
+      AttributeSet att;
+      if (typeSelected!=null) {
+        if (stylesElements.get(classeSelected).containsKey(typeSelected)) {
+          att = stylesElements.get(classeSelected).get(typeSelected);
+          ajouterRangee("", "", att);
+        }
+        if (stylesValeursElements.get(classeSelected).containsKey(typeSelected))
+          for (String champ : stylesValeursElements.get(classeSelected).get(typeSelected).keySet())
+            for (String valeur : stylesValeursElements.get(classeSelected).get(typeSelected).get(champ).keySet()) {
+              att = stylesValeursElements.get(classeSelected).get(typeSelected).get(champ).get(valeur);
+              ajouterRangee(champ, valeur, att);
+            }
+        fireTableDataChanged();
+      }
+    }
+    private void viderTableau() {
+      champs.clear();
+      valeurs.clear();
+      gras.clear();
+      italiques.clear();
+      soulignes.clear();
+      couleurs.clear();
+      fonds.clear();
+    }
+    private void ajouterTousAColorier() {
+      if (!champs.isEmpty()&&champs.get(0).isEmpty()) return;
+      stylesElements.get(classeSelected).put(typeSelected, new SimpleAttributeSet());
+      insererRangee(0, "", "", vue.getStyleTexte());
+      fireTableDataChanged();
+    }
+    private void ajouterValeurAColorier(String champ, String valeur) {
+      for (int i = 0; i<champs.size(); i++)
+        if (champs.get(i).equals(champ)&&valeurs.get(i).equals(valeur)) return;
+      if (!stylesValeursElements.get(classeSelected).containsKey(typeSelected))
+        stylesValeursElements.get(classeSelected).put(typeSelected, new HashMap<String, HashMap<String, SimpleAttributeSet>>());
+      if (!stylesValeursElements.get(classeSelected).get(typeSelected).containsKey(champ))
+        stylesValeursElements.get(classeSelected).get(typeSelected).put(champ, new HashMap<String, SimpleAttributeSet>());
+      stylesValeursElements.get(classeSelected).get(typeSelected).get(champ).put(valeur, new SimpleAttributeSet());
+      ajouterRangee(champ, valeur, vue.getStyleTexte());
+      fireTableDataChanged();
+    }
+    private void ajouterRangee(String champ, String valeur, AttributeSet att) {
+      insererRangee(champs.size(), champ, valeur, att);
+    }
+    private void insererRangee(int row, String champ, String valeur, AttributeSet att) {
+      SimpleAttributeSet att0 = vue.getStyleTexte();
+      champs.add(row, champ);
+      valeurs.add(row, valeur);
+      if (att.isDefined(StyleConstants.Bold))
+        gras.add(row, StyleConstants.isBold(att));
+      else gras.add(row, StyleConstants.isBold(att0));
+      if (att.isDefined(StyleConstants.Italic))
+        italiques.add(row, StyleConstants.isItalic(att));
+      else italiques.add(row, StyleConstants.isItalic(att0));
+      if (att.isDefined(StyleConstants.Underline))
+        soulignes.add(row, StyleConstants.isUnderline(att));
+      else soulignes.add(row, StyleConstants.isUnderline(att0));
+      if (att.isDefined(StyleConstants.Foreground))
+        couleurs.add(row, StyleConstants.getForeground(att));
+      else couleurs.add(row, StyleConstants.getForeground(att0));
+      if (att.isDefined(StyleConstants.Background))
+        fonds.add(row, StyleConstants.getBackground(att));
+      else fonds.add(row, StyleConstants.getBackground(att0));
+      fireTableDataChanged();
+    }
+    void supprimerRangee(int row) {
+      if (champs.get(row).isEmpty())
+        stylesElements.get(classeSelected).remove(typeSelected);
+      else
+        stylesValeursElements.get(classeSelected).get(typeSelected).get(champs.get(row)).remove(valeurs.get(row));
+      champs.remove(row);
+      valeurs.remove(row);
+      gras.remove(row);
+      italiques.remove(row);
+      soulignes.remove(row);
+      couleurs.remove(row);
+      fonds.remove(row);
+
+      fireTableDataChanged();
+    }
+    public int getColumnCount() {
+      return nomsColonnes.length;
+    }
+    public int getRowCount() {
+      return (valeurs.size());
+    }
+    public Object getValueAt(int row, int col) {
+      switch (col) {
+        case 0:
+          if (champs.get(row).isEmpty()) return GVisu.styleDef("tous");
+          return champs.get(row);
+        case 1:
+          if (champs.get(row).isEmpty()) return GVisu.styleDef("toutes");
+          return valeurs.get(row);
+        case 2:
+          return gras.get(row);
+        case 3:
+          return italiques.get(row);
+        case 4:
+          return soulignes.get(row);
+        case 5:
+          return couleurs.get(row);
+        case 6:
+          return fonds.get(row);
+        default:
+          throw new IndexOutOfBoundsException();
+      }
+    }
+    @Override
+    public String getColumnName(int col) {
+      return nomsColonnes[col];
+    }
+    @Override
+    public Class getColumnClass(int col) {
+      return classesColonnes[col];
+    }
+    @Override
+    public boolean isCellEditable(int row, int col) {
+      return col>1;
+    }
+    @Override
+    public void setValueAt(Object aValue, int row, int col) {
+      Boolean valbool;
+      Color valcoul;
+      SimpleAttributeSet att = champs.get(row).isEmpty() ? stylesElements.get(classeSelected).get(typeSelected) : stylesValeursElements.get(classeSelected).get(typeSelected).get(champs.get(row)).get(valeurs.get(row));
+      SimpleAttributeSet att0 = vue.getStyleTexte();
+      switch (col) {
+        case 2:
+          valbool = (Boolean) aValue;
+          gras.set(row, valbool);
+          if (StyleConstants.isBold(att0)==valbool)
+            att.removeAttribute(StyleConstants.Bold);
+          else StyleConstants.setBold(att, valbool);
+          break;
+        case 3:
+          valbool = (Boolean) aValue;
+          italiques.set(row, valbool);
+          if (StyleConstants.isItalic(att0)==valbool)
+            att.removeAttribute(StyleConstants.Italic);
+          else StyleConstants.setItalic(att, valbool);
+          break;
+        case 4:
+          valbool = (Boolean) aValue;
+          soulignes.set(row, valbool);
+          if (StyleConstants.isUnderline(att0)==valbool)
+            att.removeAttribute(StyleConstants.Underline);
+          else StyleConstants.setUnderline(att, valbool);
+          break;
+        case 5:
+          valcoul = (Color) aValue;
+          couleurs.set(row, valcoul);
+          if (StyleConstants.getForeground(att0)==valcoul)
+            att.removeAttribute(StyleConstants.Foreground);
+          else StyleConstants.setForeground(att, valcoul);
+          break;
+        case 6:
+          valcoul = (Color) aValue;
+          fonds.set(row, valcoul);
+          if (StyleConstants.getBackground(att0)==valcoul)
+            att.removeAttribute(StyleConstants.Background);
+          else StyleConstants.setBackground(att, valcoul);
+          break;
+        default:
+          throw new IndexOutOfBoundsException("col = "+col);
+      }
+      fireTableCellUpdated(row, col);
+    }
+  }
+
+  private static class JPopupMenuValeur extends JPopupMenu {
+    int rang = -1;
+  }
+
+  private class ActionSupprimerValeur extends AbstractAction {
+    ActionSupprimerValeur() {
+      super("supprimer le champ");
+    }
+    public void actionPerformed(ActionEvent e) {
+      try {
+        int rg = ((JPopupMenuValeur) ((JMenuItem) e.getSource()).getParent()).rang;
+        ((ModeleTableauValeursAColorier) tableauValeursAColorier.getModel()).supprimerRangee(rg);
+      } catch (Throwable ex) {
+        GMessages.erreurFatale(ex);
+      }
+    }
+  }
+
+  private static class ModeleArbreValeursAChoisir extends DefaultTreeModel {
+    HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champs;
+    HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adresses;
+    Vue vue;
+    ModeleArbreValeursAChoisir(Vue vue, HashMap<Class<? extends Element>, HashMap<String, ArrayList<String>>> champsAvoir,
+            HashMap<Class<? extends Element>, HashMap<String, ArrayList<Adresse>>> adressesAVoir) {
+      super(null, true);
+      this.champs = champsAvoir;
+      this.adresses = adressesAVoir;
+      this.vue = vue;
+    }
+    void setModele(Class<? extends Element> classeRacine, String typeRacine) {
+      if (typeRacine==null) {
+        setRoot(null);
+      } else {
+        NoeudValeurAChoisir racine = new NoeudValeurAChoisir(
+                classeRacine, typeRacine, null, null);
+        setRoot(racine);
+        setSousArbre(racine);
+      }
+      reload();
+    }
+    void setSousArbre(NoeudValeurAChoisir noeud) {
+      if (noeud.champ==null) {
+        noeud.add(new NoeudValeurAChoisir(noeud.classe, noeud.type, "", GVisu.styleDef("tous les éléments")));
+        for (String champ : champs.get(noeud.classe).get(noeud.type))
+          noeud.add(new NoeudValeurAChoisir(noeud.classe, noeud.type, champ, null));
+      } else {
+        int nochamp = champs.get(noeud.classe).get(noeud.type).indexOf(noeud.champ);
+        for (String valeur : vue.getValeursProp(adresses.get(noeud.classe).get(noeud.type).get(nochamp)))
+          noeud.add(new NoeudValeurAChoisir(noeud.classe, noeud.type, noeud.champ, valeur));
+      }
+    }
+  }
+
+  private static class NoeudValeurAChoisir extends DefaultMutableTreeNode {
+    Class<? extends Element> classe;
+    String type;
+    String champ;
+    String valeur;
+    NoeudValeurAChoisir(Class<? extends Element> classe, String type, String champ, String valeur) {
+      super();
+      this.classe = classe;
+      this.type = type;
+      this.champ = champ;
+      this.valeur = valeur;
+      setAllowsChildren(valeur==null);
+
+    }
+    @Override
+    public String toString() {
+      if (champ==null) return type;
+      if (valeur==null) return champ;
+      return valeur;
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/vue/VisuVueColoriage.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauCommandesSchemas.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauCommandesSchemas.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauCommandesSchemas.java	(revision 3653)
@@ -0,0 +1,524 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.Message.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.elements.*;
+import visuAnalec.texte.*;
+import visuAnalec.texte.PanneauAffTexte.*;
+import visuAnalec.texte.PanneauTexte.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class PanneauCommandesSchemas extends PanneauCommandes implements ActionListener {
+  private PanneauChamps panneauChamps;
+  private TypeComboBox saisieTypeSchemas;
+  private ElementComboBox saisieSchema;
+  private TypeComboBox saisieTypeElt;
+  private ElementComboBox saisieElt;
+  private JButton creeSchema;
+  private JButton supprimeSchema;
+  private JButton ajouteElement;
+  private JButton oteElement;
+  private JButton creeUniteElt;
+  private int[] bornesSelectTexte;
+  /*
+  
+   * CREATION PAR LE PANNEAU EDITEUR
+   */
+  PanneauCommandesSchemas(Vue vue, PanneauAffTexte pTexte, PanneauChamps pChamps) {
+    super(vue, pTexte);
+    JToolBar barre1 = new JToolBar();
+    barre1.setPreferredSize(new Dimension(0, 22));
+//    barre1.setBackground(PanneauTexte.getCouleurFond1());
+    barre1.setAlignmentX(0.0f);
+    //    barre1.setFloatable(false);
+    add(barre1);
+    JToolBar barre2 = new JToolBar();
+    barre2.setPreferredSize(new Dimension(0, 22));
+//    barre2.setBackground(PanneauTexte.getCouleurFond2());
+    barre2.setAlignmentX(0.0f);
+//     barre2.setFloatable(false);
+    add(barre2);
+    panneauChamps = pChamps;
+    saisieTypeSchemas = new TypeComboBox(Schema.class);
+    saisieTypeSchemas.addActionListener(this);
+    saisieSchema = new ElementComboBox();
+    saisieSchema.addActionListener(this);
+    saisieTypeElt = new TypeComboBox(Element.class);
+    saisieTypeElt.addActionListener(this);
+    saisieElt = new ElementComboBox();
+    saisieElt.addActionListener(this);
+    creeSchema = new JButton(new GAction("Créer") {
+      public void executer() {
+        creerSchema();
+      }
+    });
+    supprimeSchema = new JButton(new GAction("Supprimer") {
+      public void executer() {
+        supprimerSchema();
+      }
+    });
+    ajouteElement = new JButton(new GAction("Ajouter") {
+      public void executer() {
+        ajouterElement();
+      }
+    });
+    oteElement = new JButton(new GAction("Oter") {
+      public void executer() {
+        oterElement();
+      }
+    });
+    creeUniteElt = new JButton(new GAction("Créer") {
+      public void executer() {
+        creerUniteElt();
+      }
+    });
+    barre1.addSeparator();
+    barre1.add(new TitreBarre("Schéma : ", PanneauTexte.getCouleurFond1()));
+    barre1.addSeparator();
+    barre1.add(saisieTypeSchemas);
+    barre1.add(saisieSchema);
+    barre1.addSeparator();
+    barre1.add(creeSchema);
+    barre1.addSeparator();
+    barre1.add(supprimeSchema);
+    barre2.addSeparator();
+    barre2.add(new TitreBarre("Elément : ", PanneauTexte.getCouleurFond2()));
+    barre2.addSeparator();
+    barre2.add(saisieTypeElt);
+    barre2.add(saisieElt);
+    barre2.addSeparator();
+    barre2.add(ajouteElement);
+    barre2.add(oteElement);
+    barre2.add(creeUniteElt);
+  }
+
+  /*
+   * COMMANDES UTILISEES PAR LE PANNEAU EDITEUR
+   */
+  public void reinitialiser() {
+    // typiquement, appelé par le panneau éditeur à la suite d'une modif de vue ou de structure
+    saisieTypeSchemas.removeActionListener(this);
+    saisieTypeSchemas.setModele(vue.getTypesSchemasAVoir());
+    saisieTypeSchemas.effSelection();
+    saisieTypeSchemas.addActionListener(this);
+    saisieTypeElt.removeActionListener(this);
+    saisieTypeElt.setModele(vue.getTypes(Unite.class), vue.getTypes(Relation.class), vue.getTypes(Schema.class));
+    saisieTypeElt.effSelection();
+    saisieTypeElt.addActionListener(this);
+    initSaisieSchema();
+    initSaisieElt();
+    etatSelectRien();
+    revalidate();
+    repaint();
+  }
+  public void reafficher() {
+    // potentiellement appelé par le panneau éditeur ?
+    // appelé aussi par  traiterElementEvent
+    if (saisieSchema.pasdeSelection()) {
+      initSaisieSchema();
+      if (saisieElt.pasdeSelection()) {
+        initSaisieElt();
+        etatSelectRien();
+      } else {
+        Element eltCourant = saisieElt.getSelection();
+        initSaisieElt(eltCourant);
+        etatSelectElt(eltCourant);
+      }
+    } else {
+      Schema schCourant = (Schema) saisieSchema.getSelection();
+      initSaisieSchema(schCourant);
+      if (saisieElt.pasdeSelection()) {
+        initSaisieElt();
+        etatSelectSchema(schCourant);
+      } else {
+        Element eltCourant = saisieElt.getSelection();
+        initSaisieElt(eltCourant);
+        etatSelectSchemaElt(schCourant, eltCourant);
+      }
+    }
+  }
+   public void elementSuivant(int sens) {
+    if (sens>0) saisieSchema.gotoSuivant();
+    else saisieSchema.gotoPrecedent();
+  }
+ public Element elementSelectionne() {
+    if (saisieSchema.pasdeSelection()) return null;
+    return saisieSchema.getSelection();
+  }
+  public void editerElement(Element elt) {
+    // appelé par le panneauEditeur : elt est forcément un schéma
+    if (elt.getClass() != Schema.class) throw new UnsupportedOperationException("Erreur : classe incorrecte");
+    editerSchema((Schema) elt);
+  }
+  public void traiterElementEvent(ElementEvent evt) {
+    switch (evt.getModif()) {
+      case AJOUT_SCHEMA:
+      case MODIF_SCHEMA:
+        Schema sch = (Schema) evt.getElement();
+        editerSchema(sch);
+        return;
+      case SUP_SCHEMA:
+        if (evt.getElement() == saisieSchema.getSelection()) {
+          initSaisieSchema();
+          initSaisieElt();
+          etatSelectRien();
+        } else {
+          reafficher();
+        }
+        return;
+      case AJOUT_UNITE:
+        if (saisieTypeElt.getClasseSelection() == Unite.class ||
+                evt.getElement().getType().equals(saisieTypeElt.getTypeSelection())) {
+          initSaisieElt(evt.getElement());
+        }
+        reafficher();
+        return;
+      case SUP_UNITE:
+      case SUP_RELATION:
+      case BORNES_UNITE:
+      case AJOUT_RELATION:
+      case MODIF_VALEUR:
+        reafficher();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas " + evt.getModif() + " oublié dans un switch");
+    }
+  }
+  public void editerSchema(Schema sch) {
+    // appelé  par traiterElementEvent, 
+    // et aussi directement par le panneau éditeur quand il est sollicité par d'autres fenêtres
+    if (!sch.getType().equals(saisieTypeSchemas.getTypeSelection())) {
+      saisieTypeSchemas.removeActionListener(this);
+      saisieTypeSchemas.setSelection(sch.getType());
+      saisieTypeSchemas.addActionListener(this);
+    }
+    initSaisieSchema(sch);
+    saisieSchema.setSelection(sch);
+  }
+  public void editerSchemaElement(Schema sch, Element elt) {
+    // appelé  par le panneau éditeur  sollicité par VisuChaines 
+    if (!sch.getType().equals(saisieTypeSchemas.getTypeSelection())) {
+      saisieTypeSchemas.removeActionListener(this);
+      saisieTypeSchemas.setSelection(sch.getType());
+      saisieTypeSchemas.addActionListener(this);
+    }
+    initSaisieSchema(sch);
+    forceElt(elt);
+  }
+ public void editerElementTypeSchema(Element elt, String typesch) {
+    // appelé  par le panneau éditeur  sollicité par VisuChaines 
+    if (!typesch.equals(saisieTypeSchemas.getTypeSelection())) {
+      saisieTypeSchemas.removeActionListener(this);
+      saisieTypeSchemas.setSelection(typesch);
+      saisieTypeSchemas.addActionListener(this);
+    }
+    initSaisieSchema();
+    forceElt(elt);
+  }
+  public ArrayList<ElementMarque> trouverElementsVises(Unite uniteVisee, TypeMarquage marqueUniteVisee,
+          boolean avecId) {
+    ArrayList<ElementMarque> eltsMarques = new ArrayList<ElementMarque>();
+    ArrayList<Element> eltsVises;
+    Element eltVise;
+    switch (marqueUniteVisee) {
+      case FOND1:
+        eltsVises = Element.trouverElementsParUniteSousjacente(saisieSchema.getElements(), uniteVisee);
+        for (Element elt : eltsVises) eltsMarques.add(new ElementMarque(
+                  elt, marqueUniteVisee, avecId ? saisieSchema.getIdElement(elt) : null));
+        return eltsMarques;
+      case FOND1_2:
+      case FOND2:
+        eltsVises = Element.trouverElementsParUniteSousjacente(saisieElt.getElements(), uniteVisee);
+        for (Element elt : eltsVises) eltsMarques.add(new ElementMarque(
+                  elt, marqueUniteVisee, avecId ? saisieElt.getIdElement(elt) : null));
+        return eltsMarques;
+      case SELECT1:
+        eltVise = saisieSchema.getSelection();
+        eltsMarques.add(new ElementMarque(
+                  eltVise, marqueUniteVisee, avecId ? saisieSchema.getIdElement(eltVise) : null));
+        return eltsMarques;
+      case SELECT1_2:
+      case SELECT2:
+        eltVise = saisieElt.getSelection();
+        eltsMarques.add(new ElementMarque(
+                eltVise, marqueUniteVisee, avecId ? saisieElt.getIdElement(eltVise) : null));
+        return eltsMarques;       
+      default:
+        throw new UnsupportedOperationException("Marquage non prévu : " + marqueUniteVisee);
+
+    }
+  }
+  /*
+   * ACTIONS DE L'UTILISATEUR : CHANGEMENTS D'ETAT
+   */
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource() == saisieTypeSchemas) {
+        initSaisieSchema();
+        if (saisieElt.pasdeSelection()) etatSelectRien();
+        else etatSelectElt(saisieElt.getSelection());
+        return;
+      }
+      if (evt.getSource() == saisieTypeElt) {
+        initSaisieElt();
+        if (saisieSchema.pasdeSelection()) etatSelectRien();
+        else etatSelectSchema((Schema) saisieSchema.getSelection());
+        return;
+      }
+      if (evt.getSource() == saisieSchema) {
+        if (saisieSchema.pasdeSelection()) {
+          if (saisieElt.pasdeSelection()) etatSelectRien();
+          else etatSelectElt(saisieElt.getSelection());
+        } else {
+          if (saisieElt.pasdeSelection()) etatSelectSchema((Schema) saisieSchema.getSelection());
+          else etatSelectSchemaElt((Schema) saisieSchema.getSelection(), saisieElt.getSelection());
+        }
+        return;
+      }
+      if (evt.getSource() == saisieElt) {
+        if (saisieElt.pasdeSelection()) {
+          if (saisieSchema.pasdeSelection()) etatSelectRien();
+          else etatSelectSchema((Schema) saisieSchema.getSelection());
+        } else {
+          if (saisieSchema.pasdeSelection()) etatSelectElt(saisieElt.getSelection());
+          else etatSelectSchemaElt((Schema) saisieSchema.getSelection(), saisieElt.getSelection());
+        }
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : " + evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  @Override
+  public void traiterSourisEvent(SourisEvent evt) {
+    switch (evt.getTypeEvent()) {
+      case SELECT_RIEN:
+        saisieElt.removeActionListener(this);
+        saisieElt.effSelection();
+        saisieElt.addActionListener(this);
+        saisieSchema.effSelection();
+        return;
+      case SELECT_ELEMENT:
+        switch (evt.getMarquageElementVise()) {
+          case SELECT1:
+            forceElt(evt.getElementVise());
+            return;
+          case SELECT2:
+          case SELECT1_2:
+            saisieSchema.effSelection();
+            return;
+          case FOND1:
+            saisieSchema.setSelection(evt.getElementVise());
+            return;
+          case FOND2:
+          case FOND1_2:
+            saisieElt.setSelection(evt.getElementVise());
+            return;
+          default:
+            throw new UnsupportedOperationException("Marquage non prévu : " + evt.getTypeEvent());
+        }
+      case SELECT_TEXTE:
+        saisieElt.removeActionListener(this);
+        saisieElt.effSelection();
+        saisieElt.addActionListener(this);
+        saisieSchema.removeActionListener(this);
+        saisieSchema.effSelection();
+        saisieSchema.addActionListener(this);
+        bornesSelectTexte = evt.getBornesSelectionTexte();
+        etatSelectTexte();
+        return;
+    }
+    throw new UnsupportedOperationException("Evénement non prévu : " + evt.getTypeEvent());
+  }
+
+  /*
+   * ACTIONS DE L'UTILISATEUR : BOUTONS
+   */
+  private void creerSchema() {
+    vue.getCorpus().addSchemaSaisi(saisieTypeSchemas.getTypeSelection(), saisieElt.getSelection());
+  }
+  private void creerUniteElt() {
+    if (vue.getCorpus().checkPresenceUnite(saisieTypeElt.getTypeSelection(), bornesSelectTexte[0], bornesSelectTexte[1]) &&
+            !GMessages.confirmationAction("Dupliquer cette unité  ?")) return;
+    vue.getCorpus().addUniteSaisie(saisieTypeElt.getTypeSelection(),  bornesSelectTexte[0], bornesSelectTexte[1]);
+  }
+  private void supprimerSchema() {
+    if (!GMessages.confirmationAction("Supprimer le schéma sélectionné ?")) return;
+    vue.getCorpus().supSchema((Schema) saisieSchema.getSelection());
+  }
+  private void ajouterElement() {
+    vue.getCorpus().ajouterElementSchemaSaisi(saisieElt.getSelection(), (Schema) saisieSchema.getSelection());
+  }
+  private void oterElement() {
+    vue.getCorpus().oterElementSchema(saisieElt.getSelection(), (Schema) saisieSchema.getSelection());
+  }
+
+  /* 
+   * GESTION INTERNE
+   */
+  private void etatSelectRien() { // ni Sch ni Elt n'ont été saisis
+    if (saisieTypeElt.pasdeSelection()) {
+      if (saisieTypeSchemas.pasdeSelection()) panneauTexte.pasDeMarquage();
+      else panneauTexte.saisir(null,
+                Element.getUnitesSousjacentes(saisieSchema.getElements()), TypeMarquage.FOND1);
+    } else {
+      if (saisieTypeSchemas.pasdeSelection()) panneauTexte.saisir(null,
+                Element.getUnitesSousjacentes(saisieElt.getElements()), TypeMarquage.FOND2);
+      else panneauTexte.saisir(null,
+                Element.getUnitesSousjacentes(saisieSchema.getElements()), TypeMarquage.FOND1,
+                Element.getUnitesSousjacentes(saisieElt.getElements()), TypeMarquage.FOND2);
+    }
+    panneauChamps.effacer();
+    creeSchema.setEnabled(false);
+    supprimeSchema.setEnabled(false);
+    ajouteElement.setEnabled(false);
+    oteElement.setEnabled(false);
+    creeUniteElt.setEnabled(false);
+  }
+  private void etatSelectTexte() { // du texte a été sélectionné
+    if (saisieTypeElt.pasdeSelection()) {
+      if (saisieTypeSchemas.pasdeSelection()) panneauTexte.pasDeMarquage();
+      else panneauTexte.saisir(null,
+                Element.getUnitesSousjacentes(saisieSchema.getElements()), TypeMarquage.FOND1);
+    } else {
+      if (saisieTypeSchemas.pasdeSelection()) panneauTexte.saisir(null,
+                Element.getUnitesSousjacentes(saisieElt.getElements()), TypeMarquage.FOND2);
+      else panneauTexte.saisir(null,
+                Element.getUnitesSousjacentes(saisieSchema.getElements()), TypeMarquage.FOND1,
+                Element.getUnitesSousjacentes(saisieElt.getElements()), TypeMarquage.FOND2);
+    }
+    panneauChamps.effacer();
+    creeSchema.setEnabled(false);
+    supprimeSchema.setEnabled(false);
+    ajouteElement.setEnabled(false);
+    oteElement.setEnabled(false);
+    if (!saisieTypeElt.pasdeSelection() && saisieTypeElt.getClasseSelection() == Unite.class)
+      creeUniteElt.setEnabled(true);
+  }
+  private void etatSelectElt(Element elt) {  // seul Elt a été choisi 
+    if (saisieTypeSchemas.pasdeSelection()) panneauTexte.saisir(elt.getUnite0(),
+              elt.getUnitesSousjacentes(), TypeMarquage.SELECT2);
+    else panneauTexte.saisir(elt.getUnite0(), elt.getUnitesSousjacentes(), TypeMarquage.SELECT2,
+              Element.getUnitesSousjacentes(saisieSchema.getElements()), TypeMarquage.FOND1);
+    panneauChamps.afficher(elt);
+    if (!saisieTypeSchemas.pasdeSelection()) {
+      creeSchema.setEnabled(true);
+      Boutons.setDefaut(creeSchema, true);
+    }
+    supprimeSchema.setEnabled(false);
+    ajouteElement.setEnabled(false);
+    oteElement.setEnabled(false);
+    creeUniteElt.setEnabled(false);
+  }
+  private void etatSelectSchema(Schema sch) { // seul Sch a été choisi
+    if (saisieTypeElt.pasdeSelection()) panneauTexte.saisir(sch.getUnite0(),
+              sch.getUnitesSousjacentes(), TypeMarquage.SELECT1);
+    else panneauTexte.saisir(sch.getUnite0(),
+              sch.getUnitesSousjacentes(), TypeMarquage.SELECT1,
+              Element.getUnitesSousjacentes(filtreSch(saisieElt.getElements(), (Schema[])saisieSchema.getElements())),
+              TypeMarquage.FOND1_2,
+              Element.getUnitesSousjacentes(saisieElt.getElements()), TypeMarquage.FOND2);
+    panneauChamps.afficher(sch);
+    creeSchema.setEnabled(false);
+    supprimeSchema.setEnabled(true);
+    ajouteElement.setEnabled(false);
+    oteElement.setEnabled(false);
+    creeUniteElt.setEnabled(false);
+  }
+  private void etatSelectSchemaElt(Schema sch, Element elt) {
+    if (sch.contient(elt)) etatSelectSchemaEltInterne(sch, elt);
+    else etatSelectSchemaEltExterne(sch, elt);
+  }
+  private void etatSelectSchemaEltInterne(Schema sch, Element elt) {
+    panneauTexte.saisir(elt.getUnite0(),
+            elt.getUnitesSousjacentes(), TypeMarquage.SELECT1_2,
+            sch.getUnitesSousjacentes(), TypeMarquage.SELECT1);
+    panneauChamps.afficher(elt);
+    creeSchema.setEnabled(false);
+    ajouteElement.setEnabled(false);
+    if (sch.getContenu().size() > 1) {
+      oteElement.setEnabled(true);
+      supprimeSchema.setEnabled(false);
+    } else {
+      oteElement.setEnabled(false);
+      supprimeSchema.setEnabled(true);
+    }
+    creeUniteElt.setEnabled(false);
+  }
+  private void etatSelectSchemaEltExterne(Schema sch, Element elt) {
+    panneauTexte.saisir(elt.getUnite0(),
+            sch.getUnitesSousjacentes(), TypeMarquage.SELECT1,
+            elt.getUnitesSousjacentes(), TypeMarquage.SELECT2);
+    panneauChamps.afficher(sch);
+    creeSchema.setEnabled(false);
+    supprimeSchema.setEnabled(false);
+    ajouteElement.setEnabled(true);
+    oteElement.setEnabled(false);
+    creeUniteElt.setEnabled(false);
+  }
+  private void forceElt(Element elt) {
+    if (saisieTypeElt.getClasseSelection() != elt.getClass() || !elt.getType().equals(saisieTypeElt.getTypeSelection())) {
+      saisieTypeElt.removeActionListener(this);
+      saisieTypeElt.setSelection(elt.getClass(), elt.getType());
+      saisieTypeElt.addActionListener(this);
+      initSaisieElt();
+    }
+    saisieElt.setSelection(elt);
+  }
+  private Element[] filtreSch(Element[] elts, Schema[] schs) {
+    ArrayList<Element> elts1 = new ArrayList<Element>();
+    for (Element elt : elts) for(Schema sch: schs) if(sch.getContenu().contains(elt)) {
+      elts1.add(elt);
+      break;
+    }
+    return elts1.toArray(new Element[0]);
+  }
+  private void initSaisieSchema(Schema sch) {
+    saisieSchema.removeActionListener(this);
+    if (saisieTypeSchemas.pasdeSelection()) saisieSchema.setModeleVide();
+    else {
+      String type0 = saisieTypeSchemas.getTypeSelection();
+      Schema[] schemas = vue.getSchemasAVoir(type0);
+      saisieSchema.setModele(schemas, vue.getIdSchemas(type0, schemas));
+    }
+    if (sch == null) saisieSchema.effSelection();
+    else saisieSchema.setSelection(sch);
+    saisieSchema.addActionListener(this);
+    saisieSchema.revalidate();
+  }
+  private void initSaisieSchema() {
+    initSaisieSchema(null);
+  }
+  private void initSaisieElt(Element elt) {
+    saisieElt.removeActionListener(this);
+    if (saisieTypeElt.pasdeSelection()) saisieElt.setModeleVide();
+    else {
+      Class<? extends Element> classe = saisieTypeElt.getClasseSelection();
+      String type = saisieTypeElt.getTypeSelection();
+      saisieElt.setModele(vue.getElements(classe, type), vue.getIdElements(classe, type));
+    }
+    if (elt == null) saisieElt.effSelection();
+    else saisieElt.setSelection(elt);
+    saisieElt.addActionListener(this);
+    saisieElt.revalidate();
+  }
+  private void initSaisieElt() {
+    initSaisieElt(null);
+  }
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauCommandesSchemas.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/GBarres.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/GBarres.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/GBarres.java	(revision 3653)
@@ -0,0 +1,101 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package visuAnalec.statistiques;
+
+import java.awt.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.plaf.*;
+import visuAnalec.util.GMessages;
+
+
+/**
+ *
+ * @author Bernard
+ */
+public class GBarres extends JComponent implements TableModelListener {
+
+  ModeleStatsFrequences modele;
+  BarresPainter painter;
+
+  GBarres(ModeleStatsFrequences modele) {
+    super();
+    setUI(painter = new BarresPainter());
+    this.modele = modele;
+//    System.out.println("---\nCréation : " + getPreferredSize() + " -> " + getSize());
+
+
+  }
+
+  public void tableChanged(TableModelEvent evt) {
+    try {
+      ArrayList<Float> longueurs = new ArrayList<Float>();
+      ArrayList<String> noms = new ArrayList<String>();
+      for (int i = 0; i < modele.getRowCount() - 1; i++) {
+        if ((Integer) modele.getValueAt(i, 1) > 0) {
+          longueurs.add((Float) modele.getValueAt(i, 2));
+          noms.add((String) modele.getValueAt(i, 0));
+        }
+      }
+//    System.out.println(noms + "\n" + getPreferredSize() + " -> " + getSize());
+      painter.setLongueursBarres(longueurs.toArray(new Float[0]));
+      painter.setNomsBarres(noms.toArray(new String[0]));
+      repaint();
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+}
+class BarresPainter extends ComponentUI {
+
+  private String[] nomsBarres = new String[0];
+  private Float[] longueursBarres = new Float[0];
+  static BarresPainter barresUI = new BarresPainter();
+  private Color[] couleurs = new Color[]{Color.BLUE, Color.CYAN, Color.GREEN, Color.MAGENTA,
+    Color.RED, Color.YELLOW, Color.LIGHT_GRAY, Color.ORANGE, Color.PINK
+  };
+  private int margeX = 5;
+  private int interligneY = 5;
+
+  void setLongueursBarres(Float[] longueurs) {
+    longueursBarres = longueurs;
+  }
+
+  void setNomsBarres(String[] noms) {
+    nomsBarres = noms;
+  }
+
+  @Override
+  public void paint(Graphics g, JComponent c) {
+    Dimension dim = c.getSize();
+//    System.out.println(dim);
+    int hauteurMin = g.getFontMetrics().getHeight() + 2;
+    int nbBarres = nomsBarres.length;
+    g.setColor(Color.BLACK);
+    g.drawLine(margeX, interligneY, margeX, 2 * interligneY + (hauteurMin + interligneY) * nbBarres);
+    int largeurMaxTexte = 0;
+    for (int i = 0; i < nbBarres; i++) {
+      largeurMaxTexte = Math.max(largeurMaxTexte,
+              SwingUtilities.computeStringWidth(g.getFontMetrics(), nomsBarres[i]));
+    }
+    for (int i = 0; i < nbBarres; i++) {
+      int y = interligneY + (hauteurMin + interligneY) * i;
+      int longueur = Math.round((dim.width - largeurMaxTexte) * longueursBarres[i] / 100);
+      g.setColor(Color.LIGHT_GRAY); // couleurs[i % couleurs.length]);
+      g.fillRect(margeX, y, longueur, hauteurMin);
+      g.setColor(Color.BLACK);
+      g.drawRect(margeX, y, longueur, hauteurMin);
+      g.drawString(nomsBarres[i], 2 * margeX + longueur, y + hauteurMin);
+    }
+  }
+
+  public static ComponentUI createUI(JComponent c) {
+    return barresUI;
+  }
+}
+
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/GBarres.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/ModeleStatsFrequences.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/ModeleStatsFrequences.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/ModeleStatsFrequences.java	(revision 3653)
@@ -0,0 +1,90 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.statistiques;
+
+//import donnees.*;
+import java.util.*;
+import javax.swing.table.*;
+import visuAnalec.elements.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class ModeleStatsFrequences extends AbstractTableModel {
+  private String[] nomsValeurs;
+  private int[] nbOcc;
+  private String[] nomsColonnes;
+  private int totalOcc;
+ public ModeleStatsFrequences() {
+    super();
+    initialise();
+  }
+private void initialise() {
+    nomsValeurs = new String[0];
+    nbOcc = new int[]{0};
+    nomsColonnes = new String[]{"", "Nb d'occurrences", "Fréquence (%)"};
+    totalOcc = 0;
+  }
+  public int getRowCount() {
+    return nomsValeurs.length + 2;
+  }
+  public int getColumnCount() {
+    return 3;
+  }
+  @Override
+  public String getColumnName(int col) {
+    return nomsColonnes[col];
+  }
+  public Object getValueAt(int row, int col) {
+    switch (col) {
+      case 0:
+        return row == nomsValeurs.length + 1 ? "TOTAL" : row == nomsValeurs.length ? "<aucune valeur>" : nomsValeurs[row];
+      case 1:
+        return row == nomsValeurs.length + 1 ? totalOcc : nbOcc[row];
+      case 2:
+        return row == nomsValeurs.length + 1 ? 100.0f : Math.round(nbOcc[row] * 10000.0f / totalOcc) / 100.0f;
+      default:
+        return null;
+    }
+  }
+  Element[] getListeElementsRowsSelected(int[] rows, Vue vue, Class<? extends Element> classe, String type,
+          String champCible, String champFiltre, String[] valeursChampFiltre) {
+    if (rows.length == 0 || classe==null) return (new Unite[0]);
+    ArrayList<String> vals = new ArrayList<String>();
+    for (int row : rows) {
+      if (row == nomsValeurs.length + 1) {
+        return vue.getDoubleSelectionOccurrences(classe, type, null, vals.toArray(new String[0]), 
+                champFiltre, valeursChampFiltre);
+      }
+      vals.add(row == nomsValeurs.length ? "" : nomsValeurs[row]);
+    }
+    return vue.getDoubleSelectionOccurrences(classe, type, champCible, vals.toArray(new String[0]), 
+            champFiltre, valeursChampFiltre);
+  }
+  private void setModeleVide() {
+    initialise();
+    fireTableDataChanged();
+  }
+  void setModele(Vue vue, Class<? extends Element> classe, String type, String champCible,
+          String champFiltre, String[] valeursChampFiltre) {
+    if (classe==null || champCible == null || vue.getNbElementsAVoir(classe, type) == 0) {
+      setModeleVide();
+      return;
+    }
+    nomsValeurs = vue.getValeursChamp(classe, type, champCible);
+    nbOcc = new int[nomsValeurs.length + 1];
+    HashMap<String, Integer> compte =
+            vue.compterOccurrencesFiltrees(classe, type, champCible, champFiltre, valeursChampFiltre);
+    totalOcc = 0;
+    for (int row = 0; row < nomsValeurs.length + 1; row++) {
+      nbOcc[row] = compte.get(row == nomsValeurs.length ? "" : nomsValeurs[row]);
+      totalOcc += nbOcc[row];
+    }
+    fireTableDataChanged();
+  }
+}
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/ModeleStatsFrequences.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/ModeleStatsGeometrie.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/ModeleStatsGeometrie.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/ModeleStatsGeometrie.java	(revision 3653)
@@ -0,0 +1,188 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.statistiques;
+
+/**
+ *
+ * @author Bernard
+ */
+import JamaPlus.*;
+import java.awt.*;
+import java.util.*;
+import java.util.ArrayList;
+import visuAnalec.elements.*;
+import visuAnalec.vue.*;
+
+public class ModeleStatsGeometrie {
+  public enum TypeEventDonneesGraphe {
+    NEW_DONNEES,
+    MODIF_DONNEES,
+    CLEAR_DONNEES,
+    NEW_COORDS,
+    NEW_COULEURS,
+    NEW_SELECT_PTS
+  }
+
+  public interface DonneesGrapheListener extends EventListener {
+    void traiterEvent(DonneesGrapheEvent e);
+  }
+
+  public class DonneesGrapheEvent extends EventObject {
+    private TypeEventDonneesGraphe type;
+    DonneesGrapheEvent(Object source, TypeEventDonneesGraphe type) {
+      super(source);
+      this.type = type;
+    }
+    public TypeEventDonneesGraphe getType() {
+      return type;
+    }
+  }
+  private ArrayList<DonneesGrapheListener> listeCorrespondants = new ArrayList<DonneesGrapheListener>();
+  void addEventListener(DonneesGrapheListener correspondant) {
+    listeCorrespondants.add(correspondant);
+  }
+  void removeEventListener(DonneesGrapheListener correspondant) {
+    listeCorrespondants.remove(correspondant);
+  }
+  private void fireDonneesGrapheEvent(DonneesGrapheEvent evt) {
+    for (Object corresp : listeCorrespondants.toArray()) {
+      ((DonneesGrapheListener) corresp).traiterEvent(evt);
+    }
+  }
+  private Vue vue;
+  private Class<? extends Element> classe;
+  private String type;
+  private String[] champsPertinents;
+  private Element[] elementsRetenus;
+  private Matrix Pts;
+  private Color[] couleursPts;
+  private ArrayList<Integer> nosPtsChoisis;
+  public Class<? extends Element> getClasseElements() {
+    return classe;
+  }
+  public String getTypeElements() {
+    return type;
+  }
+  public Matrix getPts() {
+    return Pts;
+  }
+  public Color[] getCouleurs() {
+    return couleursPts;
+  }
+  public boolean[] getEtatsChoixtPts() {
+    boolean[] etats = new boolean[elementsRetenus.length];
+    for (int no : nosPtsChoisis) {
+      etats[no] = true;
+    }
+    return etats;
+  }
+  public ArrayList<ArrayList<String>> getTexteIdElements(ArrayList<Integer> nos) {
+    ArrayList<ArrayList<String>> textesIds = new ArrayList<ArrayList<String>>();
+    ArrayList<String> textes = new ArrayList<String>();
+    ArrayList<String> ids = new ArrayList<String>();
+    for (int i = 0; i<nos.size(); i++) {
+      Element elt = elementsRetenus[nos.get(i)];
+      textes.add(vue.getTexteUnite(elt.getUnite0()));
+      ids.add(vue.getIdElement(elt));
+    }
+    textesIds.add(textes);
+    textesIds.add(ids);
+    return textesIds;
+  }
+  public Element[] getListeElementsChoisis() {
+    Element[] liste = new Element[nosPtsChoisis.size()];
+    for (int i = 0; i<liste.length; i++) {
+      liste[i] = elementsRetenus[nosPtsChoisis.get(i)];
+    }
+    Arrays.sort(liste);
+    return liste;
+  }
+//  public Unite getDerniereUniteChoisie() {
+//    if (nosPtsChoisis.isEmpty()) {
+//      return null;
+//    }
+//    return unitesSelectionnees[nosPtsChoisis.get(nosPtsChoisis.size() - 1)];
+//  }
+  void initialise(Vue vue, Class<? extends Element> classe, String type) {
+    this.vue = vue;
+    this.type = type;
+    this.classe = classe;
+    if (classe==null) {
+      champsPertinents = new String[0];
+      elementsRetenus = new Element[0];
+      Pts = null;
+      fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.CLEAR_DONNEES));
+      return;
+    }
+    champsPertinents = vue.getNomsChamps(classe, type);
+    elementsRetenus = vue.getElementsAVoir(classe, type);
+    if (calculerCoord()) {
+      nosPtsChoisis = new ArrayList<Integer>();
+      fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.NEW_DONNEES));
+    } else {
+      Pts = null;
+      fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.CLEAR_DONNEES));
+    }
+  }
+  void majChampsSelect(String[] champsSelect) {
+    champsPertinents = champsSelect;
+    if (champsSelect.length>0&&calculerCoord()) {
+      fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.NEW_COORDS));
+    } else {
+      Pts = null;
+      fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.CLEAR_DONNEES));
+    }
+  }
+  void majChampAffiche(String champAffiche, HashMap<String, Color> couleurValeur) {
+    couleursPts = new Color[elementsRetenus.length];
+    for (int i = 0; i<elementsRetenus.length; i++) {
+      couleursPts[i] = couleurValeur.get(vue.getValeurChamp(elementsRetenus[i], champAffiche));
+    }
+    fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.NEW_COULEURS));
+  }
+  boolean calculerCoord() {
+//    Matrix mat = vue.getMatrice(classe, type, champsPertinents, elementsRetenus);
+    SparseMatrix mat = vue.getMatriceCreuse(classe, type, champsPertinents, elementsRetenus);
+    Matrix CP = mat.afc().getCP();
+    if (CP==null) return false;
+    if (CP.getColumnDimension()<2) {
+      Pts = new Matrix(elementsRetenus.length, 2);
+      if (CP.getColumnDimension()==1)
+        Pts.setMatrix(0, elementsRetenus.length-1, 0, 0, CP);
+    } else {
+      Pts = CP.getMatrix(0, elementsRetenus.length-1, 0, 1);
+    }
+    return true;
+  }
+  void setPtsChoisis(ArrayList<Integer> nos) {
+    nosPtsChoisis = nos;
+    fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.NEW_SELECT_PTS));
+  }
+  void majPtsChoisis(ArrayList<Integer> nos) {
+    for (Integer no : nos) {
+      if (nosPtsChoisis.contains(no)) {
+        nosPtsChoisis.remove(no);
+      } else {
+        nosPtsChoisis.add(no);
+      }
+    }
+    fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.NEW_SELECT_PTS));
+  }
+  void supPtsChoisis() {
+    ArrayList<Element> EltsSelects = new ArrayList<Element>(
+            Arrays.asList(elementsRetenus));
+    for (Integer no : nosPtsChoisis) {
+      EltsSelects.remove(elementsRetenus[no]);
+    }
+    elementsRetenus = EltsSelects.toArray(new Element[0]);
+    if (calculerCoord()) {
+      nosPtsChoisis = new ArrayList<Integer>();
+      fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.MODIF_DONNEES));
+    } else {
+      Pts = null;
+      fireDonneesGrapheEvent(new DonneesGrapheEvent(this, TypeEventDonneesGraphe.CLEAR_DONNEES));
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/ModeleStatsGeometrie.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/VisuStatsFrequences.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/VisuStatsFrequences.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/VisuStatsFrequences.java	(revision 3653)
@@ -0,0 +1,281 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.statistiques;
+
+import visuAnalec.texte.PanneauOccurrences;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import visuAnalec.*;
+import visuAnalec.Message.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.elements.*;
+import visuAnalec.fichiers.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.vue.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class VisuStatsFrequences extends JFrame
+        implements VueListener, ActionListener, ListSelectionListener {
+  private Vue vue;
+  private ModeleStatsFrequences donneesFrequences = new ModeleStatsFrequences();
+  private Class<? extends Element> classe;
+  private String type;
+  private String champEtudie;
+  private String champFiltre;
+  private String[] valeursChampFiltre;
+  private TypeComboBox saisieTypeElements;
+  private JComboBox saisieChampEtudie = new JComboBox();
+  private JComboBox saisieChampFiltre = new JComboBox();
+  private JList saisieValeursChampFiltre = new JList();
+  private JTable tableau;
+  private PanneauOccurrences panneauOccurrences;
+  public VisuStatsFrequences(Container fenetre, Vue vue, PanneauEditeur pEditeur) {
+    super("Fréquences");
+    Point pos = new Point(fenetre.getX()+20, fenetre.getY()+50);
+    Dimension dim = new Dimension(fenetre.getWidth(), fenetre.getHeight()-30);
+    setLocation(pos);
+    setSize(dim);
+    this.vue = vue;
+    vue.addEventListener(this);
+
+    // Panneau des commandes
+    Box panneauCommandes = Box.createVerticalBox();
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieType = new JPanel(new FlowLayout());
+    pSaisieType.setBorder(new TitledBorder("Eléments"));
+    saisieTypeElements = new TypeComboBox(Element.class);
+    saisieTypeElements.setModele(vue.getTypesUnitesAVoir(), vue.getTypesRelationsAVoir(),
+            vue.getTypesSchemasAVoir());
+    saisieTypeElements.setEditable(false);
+    saisieTypeElements.setMaximumRowCount(saisieTypeElements.getModel().getSize());
+    saisieTypeElements.addActionListener(this);
+    pSaisieType.add(saisieTypeElements, CENTER_ALIGNMENT);
+    panneauCommandes.add(pSaisieType);
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieChamp = new JPanel(new FlowLayout());
+    pSaisieChamp.setBorder(new TitledBorder("Champ à analyser"));
+    saisieChampEtudie.setEditable(false);
+    saisieChampEtudie.addActionListener(this);
+    pSaisieChamp.add(saisieChampEtudie, CENTER_ALIGNMENT);
+    panneauCommandes.add(pSaisieChamp);
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieFiltre = new JPanel(new BorderLayout());
+    pSaisieFiltre.setBorder(new TitledBorder("Filtre"));
+    saisieChampFiltre.setEditable(false);
+    saisieChampFiltre.addActionListener(this);
+    pSaisieFiltre.add(saisieChampFiltre, BorderLayout.NORTH);
+    saisieValeursChampFiltre.addListSelectionListener(this);
+    pSaisieFiltre.add(new JScrollPane(saisieValeursChampFiltre), BorderLayout.CENTER);
+    panneauCommandes.add(pSaisieFiltre);
+    panneauCommandes.add(Box.createVerticalGlue());
+    // Panneau du tableau de résultats
+    JPanel panneauAfficheTableau = new JPanel(new BorderLayout());
+    panneauAfficheTableau.setBorder(new TitledBorder("Résultats"));
+    tableau = new JTable(donneesFrequences);
+    tableau.getSelectionModel().addListSelectionListener(this);
+    JScrollPane scrollTableau = new JScrollPane(tableau);
+    panneauAfficheTableau.add(scrollTableau, BorderLayout.CENTER);
+    JPanel pExporterFrequences = new JPanel(new FlowLayout());
+    JButton exporterFrequences = new JButton(new GAction("Exporter le tableau") {
+      public void executer() {
+        FichiersTableur.exporterTable(donneesFrequences);
+      }
+    });
+    pExporterFrequences.add(exporterFrequences, CENTER_ALIGNMENT);
+    panneauAfficheTableau.add(pExporterFrequences, BorderLayout.SOUTH);
+//    panneauAfficheTableau.setPreferredSize(new Dimension(
+//            Math.round((dim.width - panneauCommandes.getPreferredSize().width) / 2),
+//            panneauCommandes.getPreferredSize().height));
+    // Panneau de l'affichage graphique
+    GBarres panneauAfficheBarres = new GBarres(donneesFrequences);
+    JScrollPane scrollPanneauBarres = new JScrollPane(panneauAfficheBarres);
+    scrollPanneauBarres.setBorder(new TitledBorder("Graphique"));
+    scrollPanneauBarres.setPreferredSize(scrollTableau.getPreferredSize());
+    donneesFrequences.addTableModelListener(panneauAfficheBarres);
+    // Panneau de visualisation des occurrences
+    panneauOccurrences = new PanneauOccurrences(vue, pEditeur);
+    JScrollPane scrollPanneauOccurrences = new JScrollPane(panneauOccurrences);
+    scrollPanneauOccurrences.setBorder(
+            new TitledBorder("Visualisation des occurrences"));
+    JButton exporterConcordances = new JButton(
+            new GAction("Exporter les concordances") {
+              public void executer() {
+                FichiersTableur.exporterTable(panneauOccurrences.getModeleTableur());
+              }
+            });
+    JPanel pExporterConcordances = new JPanel(new FlowLayout());
+    pExporterConcordances.add(exporterConcordances, CENTER_ALIGNMENT);
+    // cadre global de la fenêtre
+    JPanel haut = new JPanel(new BorderLayout());
+    haut.add(panneauCommandes, BorderLayout.WEST);
+    haut.add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, panneauAfficheTableau, panneauAfficheBarres),
+            BorderLayout.CENTER);
+    JPanel bas = new JPanel(new BorderLayout());
+    bas.add(scrollPanneauOccurrences, BorderLayout.CENTER);
+    bas.add(pExporterConcordances, BorderLayout.SOUTH);
+    JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, haut, bas);
+    setContentPane(split);
+    setVisible(true);
+    split.setDividerLocation(2./3);
+    // Fermeture de la fenêtre
+    setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+    addWindowListener(new WindowAdapter() {
+      @Override
+      public void windowClosing(WindowEvent evt) {
+        fermerFenetre();
+      }
+    });
+    // Initialisation
+    saisieTypeElements.effSelection();
+    afficherOccurrences();
+  }
+  private void fermerFenetre() {
+    vue.removeEventListener(this);
+    dispose();
+  }
+  private void initSaisieChampEtudie() {
+    saisieChampEtudie.removeActionListener(this);
+    saisieChampEtudie.removeAllItems();
+    if (classe!=null) for (String ch : vue.getNomsChamps(classe, type))
+        saisieChampEtudie.addItem(ch);
+    saisieChampEtudie.setSelectedIndex(-1);
+    champEtudie = null;
+    saisieChampEtudie.addActionListener(this);
+  }
+  private void initSaisieChampFiltre() {
+    saisieChampFiltre.removeActionListener(this);
+    saisieChampFiltre.removeAllItems();
+    saisieChampFiltre.addItem("<pas de filtre>");
+    if (classe!=null) for (String ch : vue.getNomsChamps(classe, type))
+        saisieChampFiltre.addItem(ch);
+    saisieChampFiltre.setSelectedIndex(0);
+    champFiltre = null;
+    saisieChampFiltre.addActionListener(this);
+  }
+  private void initSaisieValeursChampFiltre() {
+    saisieValeursChampFiltre.removeListSelectionListener(this);
+    if (champFiltre==null) {
+      saisieValeursChampFiltre.setListData(new String[0]);
+    } else {
+      saisieValeursChampFiltre.setListData(vue.getValeursChamp(classe, type, champFiltre));
+    }
+    saisieValeursChampFiltre.setSelectedIndex(-1);
+    saisieValeursChampFiltre.addListSelectionListener(this);
+  }
+  void afficherOccurrences() {
+    panneauOccurrences.init(classe, type, donneesFrequences.getListeElementsRowsSelected(tableau.getSelectedRows(), vue, classe,
+            type, champEtudie, champFiltre, valeursChampFiltre));
+  }
+  void changerDonnees() {
+    Object[] vals = saisieValeursChampFiltre.getSelectedValues();
+    valeursChampFiltre = new String[vals.length];
+    for (int i = 0; i<vals.length; i++) {
+      valeursChampFiltre[i] = (String) vals[i];
+    }
+    donneesFrequences.setModele(vue, classe, type, champEtudie, champFiltre, valeursChampFiltre);
+  }
+  public void traiterEvent(Message evt) {
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        fermerFenetre();
+        return;
+      case CORPUS_SAVED:
+          fermerFenetre();
+          return;
+      case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+        throw new UnsupportedOperationException("Fenêtre stat présente lors d'un message NEW_CORPUS ???");
+      case MODIF_TEXTE:
+        afficherOccurrences();
+        return;
+      case MODIF_VUE:
+        fermerFenetre();
+        return;
+      case MODIF_STRUCTURE:
+        switch (((StructureEvent) evt).getModif()) {
+          case AJOUT_VALEUR:
+          case RENOM_VALEUR:
+          case FUSION_VALEUR:
+          case SUPPR_VALEUR:
+          case VALEUR_PAR_DEFAUT:
+          case AJOUT_FORME_UNITE:
+            changerDonnees();
+            return;
+          case AJOUT_TYPE:  // à affiner : trop brutal
+          case AJOUT_TYPE_ET_ELEMENTS:
+          case RENOM_TYPE:
+          case FUSION_TYPE:
+          case SUPPR_TYPE:
+          case AJOUT_PROP:
+          case RENOM_PROP:
+          case FUSION_PROP:
+          case SUPPR_PROP:
+            fermerFenetre();
+            return;
+          default:
+            throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+        }
+      case MODIF_ELEMENT:
+        ElementEvent evtE = (ElementEvent) evt;
+        if (evtE.getModif()!=TypeModifElement.BORNES_UNITE) changerDonnees();
+        else afficherOccurrences();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+  }
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource().equals(saisieTypeElements)) {
+        classe = saisieTypeElements.getClasseSelection();
+        type = saisieTypeElements.getTypeSelection();
+        initSaisieChampEtudie();
+        initSaisieChampFiltre();
+        changerDonnees();
+        return;
+      }
+      if (evt.getSource().equals(saisieChampEtudie)) {
+        champEtudie = (String) saisieChampEtudie.getSelectedItem();
+        changerDonnees();
+        return;
+      }
+      if (evt.getSource().equals(saisieChampFiltre)) {
+        int ind = saisieChampFiltre.getSelectedIndex();
+        if (ind==0) champFiltre = null;
+        else champFiltre = (String) saisieChampFiltre.getSelectedItem();
+        initSaisieValeursChampFiltre();
+        changerDonnees();
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  public void valueChanged(ListSelectionEvent evt) {
+    try {
+      if (evt.getValueIsAdjusting()) return;
+      if (evt.getSource().equals(saisieValeursChampFiltre)) {
+        changerDonnees();
+        return;
+      }
+      if (evt.getSource().equals(tableau.getSelectionModel())) {
+        afficherOccurrences();
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.toString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/VisuStatsFrequences.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/VisuStatsGeometrie.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/VisuStatsGeometrie.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/VisuStatsGeometrie.java	(revision 3653)
@@ -0,0 +1,367 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.statistiques;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.table.*;
+import visuAnalec.*;
+import visuAnalec.Message.*;
+import visuAnalec.elements.*;
+import visuAnalec.fichiers.*;
+import visuAnalec.statistiques.ModeleStatsGeometrie.*;
+import visuAnalec.texte.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.vue.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class VisuStatsGeometrie extends JFrame implements VueListener, ActionListener, DonneesGrapheListener {
+  private Vue vue;
+  private ModeleStatsGeometrie donneesGraphe = new ModeleStatsGeometrie();
+  private GPlanAFC panneauAfficheGraphe;
+  private Class<? extends Element> classe;
+  private String type;
+  private String[] listeChampsSelectionnes;
+  private String champAffiche;
+  private TypeComboBox saisieTypeElements;
+  private JList saisieChampsSelectionnes = new JList();
+  private JComboBox saisieChampAffiche = new JComboBox();
+  private JList legendeChampAffiche = new JList();
+  private PanneauOccurrences panneauOccurrences;
+  public VisuStatsGeometrie(Container fenetre, Vue vue, PanneauEditeur pEditeur) {
+    super("Représentations géométriques");
+    Point pos = new Point(fenetre.getX()+20, fenetre.getY()+20);
+    Dimension dim = new Dimension(fenetre.getWidth(), fenetre.getHeight());
+    setLocation(pos);
+    setSize(dim);
+    this.vue = vue;
+    vue.addEventListener(this);
+
+    // Panneau des commandes
+    Box panneauCommandes = Box.createVerticalBox();
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieType = new JPanel(new FlowLayout());
+    pSaisieType.setBorder(new TitledBorder("Eléments"));
+    saisieTypeElements = new TypeComboBox(Element.class);
+    saisieTypeElements.setModele(vue.getTypesUnitesAVoir(), vue.getTypesRelationsAVoir(),
+            vue.getTypesSchemasAVoir());
+    saisieTypeElements.setEditable(false);
+    saisieTypeElements.addActionListener(this);
+    pSaisieType.add(saisieTypeElements, CENTER_ALIGNMENT);
+    panneauCommandes.add(pSaisieType);
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieSelection = new JPanel(new FlowLayout());
+    pSaisieSelection.setBorder(new TitledBorder("Champs pertinents"));
+    pSaisieSelection.add(saisieChampsSelectionnes, CENTER_ALIGNMENT);
+    panneauCommandes.add(pSaisieSelection);
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pAfficherGraphe = new JPanel(new FlowLayout());
+    JButton afficherGraphe = new JButton(new GAction("Mettre à jour le graphe") {
+      public void executer() {
+        Object[] valSelect = saisieChampsSelectionnes.getSelectedValues();
+        String[] chs = new String[valSelect.length];
+        for (int i = 0; i<valSelect.length; i++) {
+          chs[i] = (String) valSelect[i];
+        }
+        donneesGraphe.majChampsSelect(chs);
+      }
+    });
+    pAfficherGraphe.add(afficherGraphe, CENTER_ALIGNMENT);
+    panneauCommandes.add(pAfficherGraphe);
+    panneauCommandes.add(Box.createVerticalGlue());
+
+    // Panneau du graphe
+    JPanel panneauAfficheGraphique = new JPanel(new BorderLayout());
+    panneauAfficheGraphique.setBorder(new TitledBorder("Graphique"));
+    panneauAfficheGraphique.setPreferredSize(new Dimension(
+            Math.round((getWidth()-panneauCommandes.getPreferredSize().width)/2),
+            panneauCommandes.getPreferredSize().height));
+    panneauAfficheGraphe = new GPlanAFC(donneesGraphe);
+    JScrollPane scroll1 = new JScrollPane(panneauAfficheGraphe);
+    panneauAfficheGraphique.add(scroll1, BorderLayout.CENTER);
+    JPanel pExporterGraphique = new JPanel(new FlowLayout());
+    JButton exporterGraphiqueSVG = new JButton(
+            new GAction("<html> Exporter le graphique<br>en format xml (.svg)") {
+              public void executer() {
+                FichiersGraphique.exporterGraphiqueSVG(panneauAfficheGraphe);
+              }
+            });
+    JButton exporterGraphiqueEMF = new JButton(
+            new GAction("<html> Exporter le graphique<br>vers MS-Office (.emf)") {
+              public void executer() {
+                FichiersGraphique.exporterGraphiqueEMF(panneauAfficheGraphe);
+              }
+            });
+    //  exporterGraphiqueEMF.setText("<htlm> Exporter le graphique<br>vers MS-Office (.emf)");
+    pExporterGraphique.add(exporterGraphiqueSVG, CENTER_ALIGNMENT);
+    pExporterGraphique.add(exporterGraphiqueEMF, CENTER_ALIGNMENT);
+    panneauAfficheGraphique.add(pExporterGraphique, BorderLayout.SOUTH);
+
+    // Panneau champ affiché 
+    Box panneauChampAffiche = Box.createVerticalBox();
+    panneauChampAffiche.add(Box.createVerticalGlue());
+    JPanel pChampAffiche = new JPanel(new BorderLayout());
+    pChampAffiche.setBorder(new TitledBorder("Champ à afficher"));
+    saisieChampAffiche.setEditable(false);
+    saisieChampAffiche.addActionListener(this);
+    pChampAffiche.add(saisieChampAffiche, BorderLayout.NORTH);
+    legendeChampAffiche.setCellRenderer(new LegendeCellRenderer());
+    pChampAffiche.add(legendeChampAffiche, BorderLayout.CENTER);
+    panneauChampAffiche.add(pChampAffiche);
+
+    // Panneau valeurs typiques 
+    JPanel panneauValTypiques = new JPanel(new BorderLayout());
+    panneauValTypiques.setBorder(new TitledBorder("Valeurs typiques"));
+    JLabel affNbElements = new JLabel("", JLabel.CENTER);
+    panneauValTypiques.add(affNbElements, BorderLayout.NORTH);
+    ModeleValTypiques donneesValTypiques =
+            new ModeleValTypiques(vue, donneesGraphe, affNbElements);
+    donneesGraphe.addEventListener(donneesValTypiques);
+    JTable tableauValTypiques = new JTable(donneesValTypiques);
+    JScrollPane scrollChampAffiche = new JScrollPane(tableauValTypiques);
+    panneauValTypiques.add(scrollChampAffiche, BorderLayout.CENTER);
+
+    // Panneau de visualisation des occurrences
+    panneauOccurrences = new PanneauOccurrences(vue, pEditeur);
+    JScrollPane scrollPanneauOccurrences = new JScrollPane(panneauOccurrences);
+    scrollPanneauOccurrences.setBorder(new TitledBorder("Visualisation des occurrences"));
+      JButton exporterConcordances = new JButton(
+            new GAction("Exporter les concordances") {
+      public void executer() {
+       FichiersTableur.exporterTable(panneauOccurrences.getModeleTableur());
+      }
+    });
+    JPanel pExporterConcordances = new JPanel(new FlowLayout());
+    pExporterConcordances.add(exporterConcordances, CENTER_ALIGNMENT); 
+
+    donneesGraphe.addEventListener(this);  // pour lancer afficheOccurrences
+
+    // cadre global de la fenêtre
+    JSplitPane split1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+            panneauChampAffiche, panneauValTypiques);
+    JSplitPane split2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+            panneauAfficheGraphique, split1);
+    JSplitPane split3 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+            panneauCommandes, split2);
+    JPanel bas = new JPanel(new BorderLayout());
+    bas.add(scrollPanneauOccurrences, BorderLayout.CENTER);
+    bas.add(pExporterConcordances, BorderLayout.SOUTH);
+    JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
+            split3, bas);
+    getContentPane().add(split);
+    setVisible(true);
+    split3.setDividerLocation(0.15);
+    split2.setDividerLocation(0.4);
+    split1.setDividerLocation(0.3);
+    split.setDividerLocation(2./3);
+
+    // Fermeture de la fenêtre
+    setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+    addWindowListener(new WindowAdapter() {
+      @Override
+      public void windowClosing(WindowEvent evt) {
+        fermerFenetre();
+      }
+    });
+
+    // Initialisation
+    saisieTypeElements.effSelection();
+  }
+  private void fermerFenetre() {
+    vue.removeEventListener(this);
+    dispose();
+  }
+  void initSaisieChampsSelectionnes() {
+    if (classe==null) {
+      listeChampsSelectionnes = new String[0];
+      saisieChampsSelectionnes.setListData(listeChampsSelectionnes);
+    } else {
+      listeChampsSelectionnes = vue.getNomsChamps(classe, type);
+      saisieChampsSelectionnes.setListData(listeChampsSelectionnes);
+      saisieChampsSelectionnes.addSelectionInterval(0, listeChampsSelectionnes.length-1);
+    }
+  }
+  void initSaisieChampAffiche() {
+    saisieChampAffiche.removeAllItems();
+    if (classe!=null) {
+      for (String ch : vue.getNomsChamps(classe, type)) {
+        saisieChampAffiche.addItem(ch);
+      }
+    }
+    saisieChampAffiche.setSelectedIndex(-1);
+    champAffiche = null;
+    initLegendeChampAffiche();
+  }
+  void initLegendeChampAffiche() {
+    legendeChampAffiche.setListData(new LegendeLabel[0]);
+    HashMap<String, Color> couleurValeur = new HashMap<String, Color>();
+    couleurValeur.put("", GVisu.getCouleurSansValeur());
+    donneesGraphe.majChampAffiche(champAffiche, couleurValeur);
+  }
+  void majCouleursChampAffiche() {
+    String[] vals = classe==null ? new String[0] : vue.getValeursChamp(classe, type, champAffiche);
+    HashMap<String, Color> couleurValeur = new HashMap<String, Color>();
+    LegendeLabel[] legende = new LegendeLabel[vals.length+1];
+    for (int i = 0; i<vals.length; i++) {
+      legende[i] = new LegendeLabel(vals[i], GVisu.getCouleur(i));
+      couleurValeur.put(vals[i], GVisu.getCouleur(i));
+    }
+    legende[vals.length] = new LegendeLabel("<aucune valeur>", GVisu.getCouleurSansValeur());
+    couleurValeur.put("", GVisu.getCouleurSansValeur());
+    legendeChampAffiche.setListData(legende);
+    donneesGraphe.majChampAffiche(champAffiche, couleurValeur);
+  }
+  public void traiterEvent(Message evt) {
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        fermerFenetre();
+        return;
+      case CORPUS_SAVED:
+          fermerFenetre();
+          return;
+      case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+        throw new UnsupportedOperationException("Fenêtre stat présente lors d'un message NEW_CORPUS ???");
+      case MODIF_TEXTE:
+        return;
+      case MODIF_VUE:
+        fermerFenetre();
+        return;
+      case MODIF_STRUCTURE:
+        fermerFenetre();
+        return;
+      case MODIF_ELEMENT:
+        ElementEvent evtE = (ElementEvent) evt;
+        if (evtE.getModif()!=TypeModifElement.BORNES_UNITE) {
+          fermerFenetre();
+        }
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+  }
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource().equals(saisieTypeElements)) {
+        classe = saisieTypeElements.getClasseSelection();
+        type = saisieTypeElements.getTypeSelection();
+        donneesGraphe.initialise(vue, classe, type);
+        initSaisieChampsSelectionnes();
+        initSaisieChampAffiche();
+        return;
+      }
+      if (evt.getSource().equals(saisieChampAffiche)) {
+        champAffiche = (String) saisieChampAffiche.getSelectedItem();
+        majCouleursChampAffiche();
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "
+              +evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  public void traiterEvent(DonneesGrapheEvent evt) {
+    switch (evt.getType()) {
+      case NEW_DONNEES:
+      case CLEAR_DONNEES:
+        panneauOccurrences.initVide();
+        return;
+      case MODIF_DONNEES:
+        panneauOccurrences.initVide();
+        majCouleursChampAffiche();
+        return;
+      case NEW_SELECT_PTS:
+        panneauOccurrences.init(classe, type,
+                donneesGraphe.getListeElementsChoisis());
+        return;
+      case NEW_COORDS:
+      case NEW_COULEURS:
+        return;
+      default:
+        throw new UnsupportedOperationException("cas "+evt.getType()
+                +" non traité dans un switch");
+    }
+  }
+
+  static class ModeleValTypiques extends AbstractTableModel
+          implements DonneesGrapheListener {
+    String[] nomsColonnes;
+    Vue.TripletValTypique[] triplets;
+    ModeleStatsGeometrie donnees;
+    Vue vue;
+    JLabel affNbElts;
+    public ModeleValTypiques(Vue vue, ModeleStatsGeometrie donnees, JLabel affNbElts) {
+      super();
+      this.donnees = donnees;
+      this.vue = vue;
+      this.affNbElts = affNbElts;
+      initialise();
+    }
+    private void initialise() {
+      nomsColonnes = new String[]{"Champ", "Valeur", "Pourcentage"};
+      setModeleVide();
+    }
+    private void setModeleVide() {
+      triplets = new Vue.TripletValTypique[0];
+      affNbElts.setText("Pas d'élément sélectionné");
+      fireTableDataChanged();
+    }
+    private void setModele(Class<? extends Element> classe, String type, Element[] elts) {
+      triplets = vue.getValTypiques(classe, type, elts);
+      affNbElts.setText(elts.length==1 ? "Un seul élément sélectionné"
+              : elts.length+" éléments sélectionnés");
+      fireTableDataChanged();
+    }
+    public int getRowCount() {
+      return triplets.length;
+    }
+    public int getColumnCount() {
+      return 3;
+    }
+    @Override
+    public String getColumnName(int col) {
+      return nomsColonnes[col];
+    }
+    public Object getValueAt(int row, int col) {
+      switch (col) {
+        case 0:
+          return triplets[row].champ;
+        case 1:
+          return triplets[row].valeur;
+        case 2:
+          return Math.round(triplets[row].pourcentage*10000)/100.0f;
+        default:
+          return null;
+      }
+    }
+    public void traiterEvent(DonneesGrapheEvent evt) {
+      switch (evt.getType()) {
+        case NEW_DONNEES:
+        case CLEAR_DONNEES:
+        case MODIF_DONNEES:
+          setModeleVide();
+          return;
+        case NEW_SELECT_PTS:
+          setModele(donnees.getClasseElements(), donnees.getTypeElements(),
+                  donnees.getListeElementsChoisis());
+          return;
+        case NEW_COORDS:
+        case NEW_COULEURS:
+          return;
+        default:
+          throw new UnsupportedOperationException("cas "+evt.getType()+" non traité dans un switch");
+      }
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/VisuStatsGeometrie.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/ModeleStatsCorrelations.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/ModeleStatsCorrelations.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/ModeleStatsCorrelations.java	(revision 3653)
@@ -0,0 +1,148 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.statistiques;
+
+import java.awt.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.table.*;
+import visuAnalec.elements.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class ModeleStatsCorrelations extends AbstractTableModel {
+  private String[] valeursChamp2;
+  private String[] valeursChamp1;
+  private int[][] nbOcc;
+  private int[] totauxChamp1;
+  private int[] totauxChamp2;
+  private int totalTotaux;
+  public ModeleStatsCorrelations() {
+    super();
+    initialise();
+  }
+  private void initialise() {
+    valeursChamp2 = new String[0];
+    valeursChamp1 = new String[0];
+    nbOcc = new int[1][1];
+    totauxChamp1 = new int[1];
+    totauxChamp2 = new int[1];
+    totalTotaux = 0;
+  }
+  public int getRowCount() {
+    return valeursChamp2.length + 2;
+  }
+  public int getColumnCount() {
+    return valeursChamp1.length + 3;
+  }
+  @Override
+  public String getColumnName(int col) {
+    return col == 0 ? "" : col == valeursChamp1.length + 2 ? "TOTAL" : col == valeursChamp1.length + 1 ? "<aucune valeur>" : valeursChamp1[col - 1];
+  }
+  public Object getValueAt(int row, int col) {
+    if (col == 0) {
+      return row == valeursChamp2.length + 1 ? "TOTAL" : row == valeursChamp2.length ? "<aucune valeur>" : valeursChamp2[row];
+    } else if (col == valeursChamp1.length + 2) {
+      return row == valeursChamp2.length + 1 ? totalTotaux : totauxChamp1[row];
+    } else {
+      return row == valeursChamp2.length + 1 ? totauxChamp2[col - 1] : nbOcc[row][col - 1];
+    }
+  }
+  Element[] getListeElementsSelected(Integer[] rows, Integer[] cols, Vue vue, Class<? extends Element> classe, 
+          String type, String champ1, String champ2) {
+    HashSet<Element> liste = new HashSet<Element>();
+    for (int i = 0; i < rows.length; i++) {
+      if(cols[i]==0) continue;
+      if (rows[i] == valeursChamp2.length + 1) {
+        if (cols[i] == valeursChamp1.length + 2) {
+          return vue.getElementsAVoir(classe, type);
+        } else {
+          String[] val1 = cols[i] == valeursChamp1.length + 1 ? new String[]{""} : new String[]{valeursChamp1[cols[i] - 1]};
+          liste.addAll(Arrays.asList(vue.getDoubleSelectionOccurrences(classe, type,champ1, val1, null, null)));
+        }
+      } else {
+        String[] val2 = rows[i] == valeursChamp2.length ? new String[]{""} : new String[]{valeursChamp2[rows[i]]};
+        if (cols[i] == valeursChamp1.length + 2) {
+          liste.addAll(Arrays.asList(vue.getDoubleSelectionOccurrences(classe, type, champ2, val2, null, null)));
+        } else {
+          String[] val1 = cols[i] == valeursChamp1.length + 1 ? new String[]{""} : new String[]{valeursChamp1[cols[i] - 1]};
+          liste.addAll(Arrays.asList(vue.getDoubleSelectionOccurrences(classe, type, champ2, val2, champ1, val1)));
+
+        }
+      }
+    }
+    Element[] tab = liste.toArray(new Element[0]);
+    Arrays.sort(tab);
+    return tab;
+  }
+  void setModele(Vue vue, Class<? extends Element> classe, String type, String champ1, String champ2) {
+    if (classe == null) {
+      setModeleVide();
+      return;
+    }
+    valeursChamp1 = champ1 == null ? new String[0] : vue.getValeursChamp(classe, type, champ1);
+    valeursChamp2 = champ2 == null ? new String[0] : vue.getValeursChamp(classe, type, champ2);
+    nbOcc = new int[valeursChamp2.length + 1][valeursChamp1.length + 1];
+    totauxChamp1 = new int[valeursChamp2.length + 1];
+    totauxChamp2 = new int[valeursChamp1.length + 1];
+    HashMap<String, HashMap<String, Integer>> compte =
+            vue.compterOccurrencesCorrelees(classe, type, champ1, champ2);
+    totalTotaux = 0;
+    for (int col = 0; col < valeursChamp1.length + 1; col++) {
+      HashMap<String, Integer> hm = compte.get(col == valeursChamp1.length ? "" : valeursChamp1[col]);
+      for (int row = 0; row < valeursChamp2.length + 1; row++) {
+        nbOcc[row][col] = hm.get(row == valeursChamp2.length ? "" : valeursChamp2[row]);
+        totauxChamp2[col] += nbOcc[row][col];
+        totauxChamp1[row] += nbOcc[row][col];
+        totalTotaux += nbOcc[row][col];
+      }
+    }
+    fireTableStructureChanged();
+  }
+  private void setModeleVide() {
+    initialise();
+    fireTableDataChanged();
+  }
+}
+
+class CorrelationsRenderer extends DefaultTableCellRenderer {
+  ModeleStatsCorrelations donnees;
+  static Color GRIS_CLAIR = new Color(0.95f, 0.95f, 0.95f);
+  static Color BLEU_CLAIR = new Color(0.9f, 0.9f, 1.0f);
+  public CorrelationsRenderer(ModeleStatsCorrelations donnees) {
+    this.donnees = donnees;
+  }
+  @Override
+  public Component getTableCellRendererComponent(JTable table, Object value,
+          boolean isSelected, boolean hasFocus, int row, int col) {
+    int colTotal = donnees.getColumnCount() - 1;
+    int rowTotal = donnees.getRowCount() - 1;
+    int totalTotaux = (Integer) donnees.getValueAt(rowTotal, colTotal);
+    setBackground(Color.WHITE);
+    setHorizontalTextPosition(JLabel.CENTER);
+    if (col == colTotal || row == rowTotal) {
+      setBackground(BLEU_CLAIR);
+    } else if (col == 0) {
+      setBackground(GRIS_CLAIR);
+      setHorizontalTextPosition(JLabel.LEFT);
+    } else if (totalTotaux > 0) {
+      int c = (Integer) donnees.getValueAt(row, col);
+      float m = ((Integer) donnees.getValueAt(row, colTotal)) * ((Integer) donnees.getValueAt(rowTotal, col)) /
+              totalTotaux * 1.0f;
+      if (c / m > 1.0f) {
+    	  
+        float corr = Math.min(c / m - 1.0f, 2.0f) * 0.4f;
+        System.out.println("c="+c+" m="+m+" corr="+corr);
+        setBackground(new Color(1.0f, 1.0f - corr, 1.0f - corr));
+      }
+    }
+    return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
+  }
+}
+
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/ModeleStatsCorrelations.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/VisuStatsCorrelations.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/VisuStatsCorrelations.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/VisuStatsCorrelations.java	(revision 3653)
@@ -0,0 +1,254 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.statistiques;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import visuAnalec.*;
+import visuAnalec.Message.*;
+import visuAnalec.elements.*;
+import visuAnalec.fichiers.*;
+import visuAnalec.texte.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.vue.*;
+import visuAnalec.vue.Vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class VisuStatsCorrelations extends JFrame
+        implements VueListener, ActionListener, ListSelectionListener {
+  private Vue vue;
+  private ModeleStatsCorrelations donneesCorrelations = new ModeleStatsCorrelations();
+  private Class<? extends Element> classe;
+  private String type;
+  private String champ1;
+  private String champ2;
+  private TypeComboBox saisieTypeElements;
+  private JComboBox saisieChamp1 = new JComboBox();
+  private JComboBox saisieChamp2 = new JComboBox();
+  private JTable tableau;
+  private PanneauOccurrences panneauOccurrences;
+  public VisuStatsCorrelations(Container fenetre, Vue vue, PanneauEditeur pEditeur) {
+    super("Corrélations");
+    Point pos = new Point(fenetre.getX()+20, fenetre.getY()+50);
+    Dimension dim = new Dimension(fenetre.getWidth(), fenetre.getHeight()-30);
+    setLocation(pos);
+    setSize(dim);
+    this.vue = vue;
+    vue.addEventListener(this);
+    // Panneau des commandes
+    Box panneauCommandes = Box.createVerticalBox();
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieType = new JPanel(new FlowLayout());
+    pSaisieType.setBorder(new TitledBorder("Eléments"));
+    saisieTypeElements = new TypeComboBox(Element.class);
+    saisieTypeElements.setModele(vue.getTypesUnitesAVoir(), vue.getTypesRelationsAVoir(),
+            vue.getTypesSchemasAVoir());
+    saisieTypeElements.setMaximumRowCount(saisieTypeElements.getModel().getSize());
+    saisieTypeElements.setEditable(false);
+    saisieTypeElements.addActionListener(this);
+    pSaisieType.add(saisieTypeElements, CENTER_ALIGNMENT);
+    panneauCommandes.add(pSaisieType);
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieChamp1 = new JPanel(new FlowLayout());
+    pSaisieChamp1.setBorder(new TitledBorder("Champ 1 (horizontal)"));
+    saisieChamp1.setEditable(false);
+    saisieChamp1.addActionListener(this);
+    pSaisieChamp1.add(saisieChamp1, CENTER_ALIGNMENT);
+    panneauCommandes.add(pSaisieChamp1);
+    panneauCommandes.add(Box.createVerticalGlue());
+    JPanel pSaisieChamp2 = new JPanel(new FlowLayout());
+    pSaisieChamp2.setBorder(new TitledBorder("Champ 2 (vertical)"));
+    saisieChamp2.setEditable(false);
+    saisieChamp2.addActionListener(this);
+    pSaisieChamp2.add(saisieChamp2, CENTER_ALIGNMENT);
+    panneauCommandes.add(pSaisieChamp2);
+    panneauCommandes.add(Box.createVerticalGlue());
+    // Panneau du tableau de résultats
+    JPanel panneauAfficheTableau = new JPanel(new BorderLayout());
+    panneauAfficheTableau.setBorder(new TitledBorder("Résultats"));
+    tableau = new JTable(donneesCorrelations);
+    tableau.setDefaultRenderer(Number.class, new CorrelationsRenderer(donneesCorrelations));
+    tableau.setDefaultRenderer(Object.class, new CorrelationsRenderer(donneesCorrelations));
+    tableau.setName("tableauCorrelations");
+    tableau.setCellSelectionEnabled(true);
+    tableau.setRowHeight(40);
+    tableau.getTableHeader().setPreferredSize(new Dimension(tableau.getPreferredSize().width, 40));
+    tableau.getSelectionModel().addListSelectionListener(this);
+    JScrollPane scroll1 = new JScrollPane(tableau);
+    panneauAfficheTableau.add(scroll1, BorderLayout.CENTER);
+    JPanel pExporterCorrelations = new JPanel(new FlowLayout());
+    JButton exporterCorrelations = new JButton(new GAction("Exporter le tableau") {
+      public void executer() {
+        FichiersTableur.exporterTable(donneesCorrelations);
+      }
+    });
+    pExporterCorrelations.add(exporterCorrelations, CENTER_ALIGNMENT);
+    panneauAfficheTableau.add(pExporterCorrelations, BorderLayout.SOUTH);
+    panneauAfficheTableau.setPreferredSize(new Dimension(
+            getWidth()-panneauCommandes.getPreferredSize().width,
+            panneauCommandes.getPreferredSize().height));
+    // Panneau de visualisation des occurrences
+    panneauOccurrences = new PanneauOccurrences(vue, pEditeur);
+    JScrollPane scrollPanneauOccurrences = new JScrollPane(panneauOccurrences);
+    scrollPanneauOccurrences.setBorder(new TitledBorder("Visualisation des occurrences"));
+    JButton exporterConcordances = new JButton(
+            new GAction("Exporter les concordances") {
+              public void executer() {
+                FichiersTableur.exporterTable(panneauOccurrences.getModeleTableur());
+              }
+            });
+    JPanel pExporterConcordances = new JPanel(new FlowLayout());
+    pExporterConcordances.add(exporterConcordances, CENTER_ALIGNMENT);
+    // cadre global de la fenêtre
+    JPanel bas = new JPanel(new BorderLayout());
+    bas.add(scrollPanneauOccurrences, BorderLayout.CENTER);
+    bas.add(pExporterConcordances, BorderLayout.SOUTH);
+    JSplitPane haut = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+            panneauCommandes, panneauAfficheTableau);
+    JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, haut, bas);
+    getContentPane().add(split);
+    setVisible(true);
+    split.setDividerLocation(2./3);
+    // Fermeture de la fenêtre
+    setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+    addWindowListener(new WindowAdapter() {
+      @Override
+      public void windowClosing(WindowEvent evt) {
+        fermerFenetre();
+      }
+    });
+    // Initialisation
+    saisieTypeElements.effSelection();
+    afficherOccurrences();
+  }
+  private void fermerFenetre() {
+    vue.removeEventListener(this);
+    dispose();
+  }
+  private void initSaisieChamps() {
+    for (JComboBox saisieChamp : new JComboBox[]{saisieChamp1, saisieChamp2}) {
+      saisieChamp.removeActionListener(this);
+      saisieChamp.removeAllItems();
+      if (classe!=null) for (String ch : vue.getNomsChamps(classe, type))
+          saisieChamp.addItem(ch);
+      saisieChamp.setSelectedIndex(-1);
+      saisieChamp.addActionListener(this);
+    }
+    champ1 = champ2 = null;
+  }
+  void afficherOccurrences() {
+    ArrayList<Integer> rows = new ArrayList<Integer>();
+    ArrayList<Integer> cols = new ArrayList<Integer>();
+    for (int row : tableau.getSelectedRows()) {
+      for (int col : tableau.getSelectedColumns()) {
+        if (tableau.isCellSelected(row, col)) {
+          rows.add(row);
+          cols.add(col);
+        }
+      }
+    }
+    panneauOccurrences.init(classe, type,
+            donneesCorrelations.getListeElementsSelected(rows.toArray(new Integer[0]),
+            cols.toArray(new Integer[0]), vue, classe, type, champ1, champ2));
+  }
+  void changerDonnees() {
+    donneesCorrelations.setModele(vue, classe, type, champ1, champ2);
+  }
+  public void traiterEvent(Message evt) {
+    switch (evt.getType()) {
+      case CLEAR_CORPUS:
+        fermerFenetre();
+        return;
+      case CORPUS_SAVED:
+          fermerFenetre();
+          return;
+      case NEW_CORPUS:  // impossible en principe : CLEAR_CORPUS a détruit la fenêtre
+        throw new UnsupportedOperationException("Fenêtre stat présente lors d'un message NEW_CORPUS ???");
+      case MODIF_TEXTE:
+        afficherOccurrences();
+        return;
+      case MODIF_VUE:
+        fermerFenetre();
+        return;
+      case MODIF_STRUCTURE:
+        switch (((StructureEvent) evt).getModif()) {
+          case AJOUT_VALEUR:
+          case RENOM_VALEUR:
+          case FUSION_VALEUR:
+          case SUPPR_VALEUR:
+          case AJOUT_FORME_UNITE:
+          case VALEUR_PAR_DEFAUT:
+            changerDonnees();
+            return;
+          case AJOUT_TYPE:  // à affiner : trop brutal
+          case AJOUT_TYPE_ET_ELEMENTS:
+          case RENOM_TYPE:
+          case FUSION_TYPE:
+          case SUPPR_TYPE:
+          case AJOUT_PROP:
+          case RENOM_PROP:
+          case FUSION_PROP:
+          case SUPPR_PROP:
+            fermerFenetre();
+            return;
+          default:
+            throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+        }
+      case MODIF_ELEMENT:
+        ElementEvent evtE = (ElementEvent) evt;
+        if (evtE.getModif()!=TypeModifElement.BORNES_UNITE) changerDonnees();
+        else afficherOccurrences();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getType()+" oublié dans un switch");
+    }
+  }
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource().equals(saisieTypeElements)) {
+        classe = saisieTypeElements.getClasseSelection();
+        type = saisieTypeElements.getTypeSelection();
+        initSaisieChamps();
+        changerDonnees();
+        return;
+      }
+      if (evt.getSource().equals(saisieChamp1)) {
+        champ1 = (String) saisieChamp1.getSelectedItem();
+        changerDonnees();
+        return;
+      }
+      if (evt.getSource().equals(saisieChamp2)) {
+        champ2 = (String) saisieChamp2.getSelectedItem();
+        changerDonnees();
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.toString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  public void valueChanged(ListSelectionEvent evt) {
+    try {
+      if (evt.getValueIsAdjusting())
+        return;
+      if (evt.getSource().equals(tableau.getSelectionModel())) {
+        afficherOccurrences();
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.toString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/VisuStatsCorrelations.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/GPlanAFC.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/GPlanAFC.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/GPlanAFC.java	(revision 3653)
@@ -0,0 +1,420 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec.statistiques;
+
+import JamaPlus.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.plaf.*;
+import visuAnalec.elements.*;
+import visuAnalec.fichiers.FichiersGraphique.*;
+import visuAnalec.statistiques.ModeleStatsGeometrie.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class GPlanAFC extends JComponent
+        implements DonneesGrapheListener, MouseListener, GraphiqueExport {
+
+  private static class Ellipse {
+
+    double xcentre, ycentre;
+    double grandAxe, petitAxe;
+    double xrotation, yrotation;
+
+    private Ellipse(double xc, double yc, double ga, double pa, double xr, double yr) {
+      xcentre = xc;
+      ycentre = yc;
+      petitAxe = pa;
+      grandAxe = ga;
+      xrotation = xr;
+      yrotation = yr;
+    }
+  }
+  private final static int marge = 20;
+  private final static int delta = 1;
+  private final static int bord = marge - delta;
+  private final static int rayon = 3;
+  private final static int epaisseurSelection = 3;
+  private final static double epsilon = 0.0001;
+  private final static BasicStroke ligneEpaisse = new BasicStroke(epaisseurSelection);
+  private final static BasicStroke ligneFine = new BasicStroke();
+  private final static int dimExport = 500;
+  private double xRange, yRange, xMin, yMin;
+  private double[] xPts, yPts;
+  private int nbPts;
+  private Color[] couleurs;
+  private boolean[] etatPts;
+  private Rectangle[] rects;
+  private Ellipse ellipse;
+  private ModeleStatsGeometrie donnees;
+  private JPopupMenu menu;
+  private double echelleExport;  // pour exporter le graphique
+
+  GPlanAFC(ModeleStatsGeometrie donnees) {
+    super();
+    this.donnees = donnees;
+    donnees.addEventListener(this);
+    addMouseListener(this);
+    menu = new JPopupMenu();
+    menu.add(new GAction("Tout déselectionner") {
+
+      public void executer() {
+        deselectionnerTout();
+      }
+    });
+    menu.add(new GAction("Entourer la sélection") {
+
+      public void executer() {
+        entourerSelection();
+      }
+    });
+    menu.add(new GAction("Supprimer les points") {
+
+      public void executer() {
+        supprimerPts();
+      }
+    });
+    ToolTipManager.sharedInstance().registerComponent(this);
+  }
+
+  @Override
+  public JToolTip createToolTip() {
+    JToolTip jt = new JToolTip();
+//    jt.setBackground(JAUNE_TRES_CLAIR);
+    return jt;
+  }
+
+  public void traiterEvent(DonneesGrapheEvent evt) {
+    switch (evt.getType()) {
+      case NEW_DONNEES:
+      case MODIF_DONNEES:
+        setPts(donnees.getPts());
+        couleurs = new Color[donnees.getPts().getRowDimension()];
+        Arrays.fill(couleurs, GVisu.getCouleurSansValeur());
+        etatPts = donnees.getEtatsChoixtPts();
+        clearEllipse();
+        repaint();
+        return;
+      case NEW_COORDS:
+        setPts(donnees.getPts());
+        repaint();
+        return;
+      case CLEAR_DONNEES:
+        clearPts();
+        repaint();
+        return;
+      case NEW_COULEURS:
+        couleurs = donnees.getCouleurs();
+        repaint();
+        return;
+      case NEW_SELECT_PTS:
+        etatPts = donnees.getEtatsChoixtPts();
+        repaint();
+        return;
+      default:
+        throw new UnsupportedOperationException("cas " + evt.getType() + " non traité");
+    }
+  }
+
+  public void mouseClicked(MouseEvent e) {
+    try {
+      ArrayList<Integer> nos = getPts(getMousePosition());
+      if (!nos.isEmpty() && e.getButton() == MouseEvent.BUTTON1) {
+        clearEllipse();
+        donnees.majPtsChoisis(nos);
+      }
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+
+  public void mousePressed(MouseEvent e) {
+    try {
+      if (e.isPopupTrigger()) {
+        showPopup(e);
+      }
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+
+  public void mouseReleased(MouseEvent e) {
+    try {
+      if (e.isPopupTrigger()) {
+        showPopup(e);
+      }
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+
+  private void showPopup(MouseEvent e) {
+    menu.show(e.getComponent(), e.getX(), e.getY());
+  }
+
+  public void mouseEntered(MouseEvent e) {
+  }
+
+  public void mouseExited(MouseEvent e) {
+  }
+
+  @Override
+  public String getToolTipText() {
+    Point pt = getMousePosition();
+    if (pt == null) return "";
+    ArrayList<Integer> nopts = getPts(pt);
+    if (nopts.isEmpty()) return "";
+    ArrayList<ArrayList<String>> textesEtIds = donnees.getTexteIdElements(nopts);
+    return GVisu.styleIdTooltip(textesEtIds.get(0), textesEtIds.get(1));
+  }
+
+  private void deselectionnerTout() {
+    donnees.setPtsChoisis(new ArrayList<Integer>());
+    clearEllipse();
+  }
+
+  private void entourerSelection() {
+    ArrayList<Integer> nos = setEllipse(donnees.getPts(), donnees.getEtatsChoixtPts());
+    donnees.setPtsChoisis(nos);
+  }
+
+  private void supprimerPts() {
+    int nb = Tableaux.compterValeursVraies(donnees.getEtatsChoixtPts());
+    if (nb == 0) return;
+    if (!GMessages.confirmationAction("Supprimer " + nb
+            + " élément(s) de la représentation ?")) return;
+    donnees.supPtsChoisis();
+  }
+
+  private void setPts(Matrix Pts) {
+    nbPts = Pts.getRowDimension();
+    if (nbPts == 0) {
+      clearPts();
+      return;
+    }
+    xMin = Pts.minColumn(0);
+    yMin = Pts.minColumn(1);
+    xRange = Pts.maxColumn(0) - xMin;
+    yRange = Pts.maxColumn(1) - yMin;
+    xPts = new double[nbPts];
+    yPts = new double[nbPts];
+    rects = new Rectangle[nbPts];
+    for (int i = 0; i < nbPts; i++) {
+      xPts[i] = Pts.get(i, 0) - xMin;
+      yPts[i] = Pts.get(i, 1) - yMin;
+    }
+    ellipse = null;
+  }
+
+  private void clearPts() {
+    nbPts = 0;
+    xRange = 0;
+    yRange = 0;
+    xPts = new double[0];
+    yPts = new double[0];
+    rects = new Rectangle[0];
+    ellipse = null;
+  }
+
+  private void setEtatPts(boolean[] etats) {
+    etatPts = etats;
+  }
+
+  private void setCouleurs(Color[] couleurs) {
+    this.couleurs = couleurs;
+  }
+
+  private ArrayList<Integer> setEllipse(Matrix Pts, boolean[] aentourer) {
+    ArrayList<Integer> listenos = new ArrayList<Integer>();
+    for (int i = 0; i < aentourer.length; i++) if (aentourer[i])
+        listenos.add(i);
+    if (listenos.isEmpty()) return listenos;
+    Matrix PtsEntoures = getPtsUniqueCoord(Pts, listenos);
+    SingularValueDecomposition svd = new SingularValueDecomposition(PtsEntoures.columnCovariance());
+    Matrix C = PtsEntoures.columnMean();
+    double xcentre = C.get(0, 0);
+    double ycentre = C.get(0, 1);
+    Matrix U = svd.getU();
+    double xrotation = U.get(0, 0);
+    double yrotation = U.get(0, 1);
+    double[] s = svd.getSingularValues();
+    Matrix OPts = Pts.firstLineMinus(C).times(U);
+    double[] d2Pts = new double[nbPts];
+    double maxd2Pts = 0;
+    if (s[1] > epsilon) {  // cas général
+      for (int i = 0; i < nbPts; i++) {
+        d2Pts[i] = (OPts.get(i, 0) * OPts.get(i, 0)) / s[0]
+                + (OPts.get(i, 1) * OPts.get(i, 1)) / s[1];
+        if (aentourer[i]) maxd2Pts = Math.max(maxd2Pts, d2Pts[i]);
+      }
+      listenos.clear();
+      for (int i = 0; i < nbPts; i++) if (d2Pts[i] <= maxd2Pts) listenos.add(i);
+    } else if (s[0] > epsilon) { // tous les points sont alignés
+      for (int i = 0; i < nbPts; i++) {
+        d2Pts[i] = (OPts.get(i, 0) * OPts.get(i, 0)) / s[0];
+        if (aentourer[i]) maxd2Pts = Math.max(maxd2Pts, d2Pts[i]);
+      }
+      listenos.clear();
+      for (int i = 0; i < nbPts; i++)
+        if (Math.abs(OPts.get(i, 1)) < epsilon && d2Pts[i] <= maxd2Pts)
+          listenos.add(i);
+    }  // si tous les points sont confondus : on garde listenos et max2Pts=0
+    double r = Math.sqrt(maxd2Pts);
+    double grandaxe = r * Math.sqrt(s[0]);
+    double petitaxe = r * Math.sqrt(s[1]);
+    ellipse = new Ellipse(xcentre - xMin, ycentre - yMin,
+            grandaxe, petitaxe, xrotation, yrotation);
+    return listenos;
+  }
+
+  private void clearEllipse() {
+    ellipse = null;
+  }
+
+  private ArrayList<Integer> getPts(Point pt) {
+    ArrayList<Integer> nos = new ArrayList<Integer>();
+    for (int no = 0; no < nbPts; no++) {
+      if (rects[no].contains(pt)) {
+        nos.add(no);
+      }
+    }
+    return nos;
+  }
+
+  private static Matrix getPtsUniqueCoord(Matrix Pts, ArrayList<Integer> nos) {
+    ArrayList<Integer> noselects = new ArrayList<Integer>();
+    double dx, dy;
+    for (int i : nos) {
+      boolean unique = true;
+      for (int i1 : noselects) {
+        dx = Pts.get(i, 0) - Pts.get(i1, 0);
+        dy = Pts.get(i, 1) - Pts.get(i1, 1);
+        if (dx * dx + dy * dy < epsilon) {
+          unique = false;
+          break;
+        }
+      }
+      if (unique) noselects.add(i);
+    }
+    int[] nosels = new int[noselects.size()];
+    for (int i = 0; i < nosels.length; i++) nosels[i] = noselects.get(i);
+    return Pts.getMatrix(nosels, 0, 1);
+  }
+
+  @Override
+  public void paintComponent(Graphics g0) {
+    if (nbPts == 0) return;
+    Graphics2D g = (Graphics2D) g0;
+    double echelle;
+    int x0, y0, xrg, yrg, x, y;
+    Dimension dim = getSize();
+    if (xRange == 0 && yRange == 0) {
+      x0 = (int) Math.round((dim.width) / 2.0);
+      xrg = 0;
+      y0 = (int) Math.round((dim.height) / 2.0);
+      yrg = 0;
+      echelle = 0;
+    } else if (xRange == 0) {   // impossible en fait : xRange >= yRange
+      x0 = (int) Math.round((dim.width) / 2.0);
+      xrg = 0;
+      y0 = marge;
+      echelle = (dim.height - 2 * marge) / yRange;
+      yrg = (int) Math.round(yRange * echelle);
+    } else if (yRange == 0) {
+      echelle = (dim.width - 2 * marge) / xRange;
+      xrg = (int) Math.round(xRange * echelle);
+      x0 = marge;
+      yrg = 0;
+      y0 = (int) Math.round((dim.height) / 2.0);
+    } else {
+      double echx = (dim.width - 2 * marge) / xRange;
+      double echy = (dim.height - 2 * marge) / yRange;
+      if (echx < echy) {
+        echelle = echx;
+        xrg = (int) Math.round(xRange * echelle);
+        yrg = (int) Math.round(yRange * echelle);
+        x0 = marge;
+        y0 = (int) Math.round((dim.height - yrg) / 2.0);
+      } else {
+        echelle = echy;
+        xrg = (int) Math.round(xRange * echelle);
+        yrg = (int) Math.round(yRange * echelle);
+        x0 = (int) Math.round((dim.width - xrg) / 2.0);
+        y0 = marge;
+      }
+    }
+    g.drawRect(x0 - bord, y0 - bord, xrg + 2 * bord, yrg + 2 * bord);
+    for (int i = 0; i < nbPts; i++) {
+      x = x0 + (int) Math.round(echelle * xPts[i]);
+      y = y0 + (int) Math.round(echelle * yPts[i]);
+      g.setColor(couleurs[i]);
+      rects[i] = new Rectangle(x - rayon, y - rayon, 2 * rayon, 2 * rayon);
+      g.fillOval(x - rayon - 1, y - rayon - 1, 2 * rayon + 2, 2 * rayon + 2);
+      g.setStroke(etatPts[i] ? ligneEpaisse : ligneFine);
+      g.setColor(Color.BLACK);
+      int epais = etatPts[i] ? epaisseurSelection - 1 : 0;
+      g.drawOval(x - (rayon + epais), y - (rayon + epais), 2 * (rayon + epais), 2 * (rayon + epais));
+    }
+    if (ellipse == null) return;
+    double xc = x0 + ellipse.xcentre * echelle;
+    double yc = y0 + ellipse.ycentre * echelle;
+    double ga = ellipse.grandAxe * echelle + rayon + epaisseurSelection - 1;
+    double pa = ellipse.petitAxe * echelle + rayon + epaisseurSelection - 1;
+    Ellipse2D.Double ell = new Ellipse2D.Double(xc - ga, yc - pa, 2 * ga, 2 * pa);
+    g.setStroke(ligneFine);
+    g.draw(AffineTransform.getRotateInstance(ellipse.xrotation, ellipse.yrotation, xc, yc).
+            createTransformedShape(ell));
+  }
+
+  public Dimension initExport() {
+    if (nbPts == 0) return new Dimension(dimExport, dimExport);
+    if (xRange == 0 && yRange == 0) {
+      echelleExport = 0;
+      return new Dimension(2 * marge, 2 * marge);
+    } else if (xRange == 0) { // impossible, en fait
+      echelleExport = dimExport / yRange;
+      return new Dimension(2 * marge, dimExport + 2 * marge);
+    } else if (yRange == 0) {
+      echelleExport = dimExport / xRange;
+      return new Dimension(dimExport + 2 * marge, 2 * marge);
+    } else {
+      echelleExport = dimExport / xRange;
+      return new Dimension(dimExport + 2 * marge,
+              ((int) Math.round(yRange * echelleExport)) + 2 * marge);
+    }
+  }
+
+  public Rectangle getCadre() {
+    if (nbPts == 0) return null;
+    if (xRange == 0 && yRange == 0)
+      return new Rectangle(delta, delta, 2 * bord, 2 * bord);
+    else if (xRange == 0)
+      return new Rectangle(delta, delta, 2 * bord, dimExport + 2 * bord);
+    else if (yRange == 0)
+      return new Rectangle(delta, delta, dimExport + 2 * bord, 2 * bord);
+    else
+      return new Rectangle(delta, delta, dimExport + 2 * bord,
+              ((int) Math.round(yRange * echelleExport)) + 2 * bord);
+  }
+
+  public CercleColore[] getCerclesColores() {
+    CercleColore[] cercles = new CercleColore[nbPts];
+    for (int i = 0; i < nbPts; i++) {
+      cercles[i] = new CercleColore();
+      cercles[i].cx = marge + (int) Math.round(echelleExport * xPts[i]);
+      cercles[i].cy = marge + (int) Math.round(echelleExport * yPts[i]);
+      cercles[i].couleur = couleurs[i];
+      cercles[i].r = rayon;
+    }
+    return cercles;
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/statistiques/GPlanAFC.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauChamps.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauChamps.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauChamps.java	(revision 3653)
@@ -0,0 +1,170 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec;
+
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import visuAnalec.elements.*;
+import visuAnalec.util.*;
+import visuAnalec.vue.*;
+
+import ca.odell.glazedlists.swing.AutoCompleteSupport;
+import ca.odell.glazedlists.GlazedLists;
+
+/**
+ *
+ * @author Bernard, cplancq
+ */
+public class PanneauChamps extends JPanel {
+	
+	ArrayList<GChamp> champs = new ArrayList<>();
+	
+	private Vue vue;
+	
+	private Element element = null;
+	
+	private Class<? extends Element> classe = null;
+	
+	private String type = null;
+	
+	private JPanel cadre;
+	
+	public PanneauChamps(PanneauEditeur pEdit, Vue vue) {
+		super(new BorderLayout());
+		setBorder(new TitledBorder("Champs"));
+		cadre = new JPanel(new GridLayout(0, 1));
+		JScrollPane scroll = new JScrollPane(cadre);
+		add(scroll, BorderLayout.CENTER);
+		this.vue = vue;
+	}
+	
+	void reafficher() {
+		if (element == null) return;
+		type = null;
+		afficher(element);
+	}
+	
+	void afficher(Element elt) {
+		this.element = elt;
+		if (elt.getClass() != classe || !elt.getType().equals(type)) {
+			type = elt.getType();
+			classe = elt.getClass();
+			afficherTouslesChamps();
+		}
+		((TitledBorder) getBorder()).setTitle("Champs " + GVisu.getNomDeLaClasse(elt) + " :  \"" +
+				vue.getIdElement(elt) + "\"");
+		for (GChamp gc : champs) {
+			gc.afficher(elt);
+		}
+		revalidate();
+		repaint();
+	}
+	
+	void effacer() {
+		cadre.removeAll();
+		type = null;
+		element = null;
+		((TitledBorder) getBorder()).setTitle("Champs");
+		revalidate();
+		repaint();
+	}
+	
+	private void afficherTouslesChamps() {
+		cadre.removeAll();
+		champs.clear();
+		
+		int niveau = 0;
+		for (String[] champsniveau : vue.getChamps(classe, type)) {
+			JPanel panneauniveau = new JPanel();
+			// panneauniveau.setBorder(new TitledBorder("Niveau " + ++niveau));
+			for (String champ : champsniveau) {
+				GChamp gc = new GChamp(vue, classe, type, champ);
+				champs.add(gc);
+				panneauniveau.add(gc);
+			}
+			cadre.add(panneauniveau);
+		}
+	}
+	
+	private static class GChamp extends JPanel implements ActionListener {
+		
+		JComboBox afficheValeurChamp;
+		
+		Vue vue;
+		
+		Class<? extends Element> classe;
+		
+		String type;
+		
+		String champ;
+		
+		Element element = null;
+		
+		GChamp(Vue vue, Class<? extends Element> classe, String type, String champ) {
+			super();
+			this.vue = vue;
+			this.classe = classe;
+			this.type = type;
+			this.champ = champ;
+			Box groupe = Box.createVerticalBox();
+			Box titre = Box.createHorizontalBox();
+			titre.add(Box.createHorizontalGlue());
+			JLabel label = new JLabel(champ, JLabel.CENTER);
+			// label.setPreferredSize(new Dimension(50, 10));
+			titre.add(label);
+			titre.add(Box.createHorizontalGlue());
+			groupe.add(titre);
+			groupe.add(Box.createVerticalStrut(2));
+			afficheValeurChamp = new JComboBox(vue.getValeursChamp(classe, type, champ));
+			/*
+			 * CP: JComboBox avec autocompletion. Dépend de la lib glazedlists
+			 * (http://www.glazedlists.com/), (https://github.com/glazedlists/glazedlists)
+			 */
+			AutoCompleteSupport<String> support = AutoCompleteSupport.install(afficheValeurChamp, GlazedLists.eventListOf(vue.getValeursChamp(classe, type, champ)));
+			support.setCorrectsCase(false);
+			afficheValeurChamp.setEditable(vue.isChampModifiable(classe, type, champ));
+			afficheValeurChamp.addActionListener(this);
+			groupe.add(afficheValeurChamp);
+			add(groupe);
+		}
+		
+		void afficher(Element elt) {
+			this.element = elt;
+			afficheValeurChamp.removeActionListener(this);
+			String val = vue.getValeurChamp(elt, champ);
+			if (val.isEmpty()) afficheValeurChamp.setSelectedIndex(-1);
+			else afficheValeurChamp.setSelectedItem(val);
+			afficheValeurChamp.addActionListener(this);
+		}
+		
+		@Override
+		public void actionPerformed(ActionEvent evt) {
+			try {
+				if (!afficheValeurChamp.isEditable()) {
+					JOptionPane.showMessageDialog(getTopLevelAncestor(), "Champ non modifiable pour ce type d'éléments",
+							"Modification impossible", JOptionPane.ERROR_MESSAGE);
+					afficher(element);
+					return;
+				}
+				String newval = ((String) afficheValeurChamp.getSelectedItem());
+				if (newval == null) newval = "";
+				else newval = newval.trim();
+				
+				if (!vue.setValeurChamp(element, champ, newval)) {
+					JOptionPane.showMessageDialog(getTopLevelAncestor(), "Champ non défini pour cet élément",
+							"Saisie de valeur de champ impossible", JOptionPane.ERROR_MESSAGE);
+					afficher(element);
+				}
+			}
+			catch (Throwable ex) {
+				GMessages.erreurFatale(ex);
+			}
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauChamps.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/Message.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/Message.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/Message.java	(revision 3653)
@@ -0,0 +1,149 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec;
+
+import java.util.*;
+import visuAnalec.elements.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class Message extends EventObject {
+  public enum TypeMessage {
+    CLEAR_CORPUS,
+    NEW_CORPUS,
+    MODIF_TEXTE,
+    MODIF_ELEMENT,
+    MODIF_STRUCTURE,
+    MODIF_VUE,
+    CORPUS_SAVED // corpus annotation and structure are saved
+  }
+
+  public enum TypeModifElement {
+    AJOUT_UNITE,
+    SUP_UNITE,
+    BORNES_UNITE,
+    AJOUT_RELATION,
+    SUP_RELATION,
+    AJOUT_SCHEMA,
+    MODIF_SCHEMA,
+    SUP_SCHEMA,
+    MODIF_VALEUR,
+  }
+
+  public enum TypeModifStructure {
+    AJOUT_TYPE_ET_ELEMENTS,
+    AJOUT_TYPE,
+    AJOUT_PROP,
+    AJOUT_FORME_UNITE,
+    AJOUT_VALEUR,
+    RENOM_TYPE,
+    RENOM_PROP,
+    RENOM_VALEUR,
+    FUSION_TYPE,
+    FUSION_PROP,
+    FUSION_VALEUR,
+    SUPPR_TYPE,
+    SUPPR_PROP,
+    SUPPR_VALEUR,
+    VALEUR_PAR_DEFAUT,
+  }
+
+  public enum TypeModifVue {
+    EXTRACTION,
+    NEW_VUE,
+    VUE_DEFAUT,
+  }
+  TypeMessage type;
+  public Message(Object source, TypeMessage type) {
+    super(source);
+    this.type = type;
+  }
+  public TypeMessage getType() {
+    return type;
+  }
+
+  public static class VueEvent extends Message {
+    private TypeModifVue modif;
+    private Unite unite;
+    private String[] args;
+    public VueEvent(Object source, TypeModifVue modif, String... args) {
+      super(source, TypeMessage.MODIF_VUE);
+      this.modif = modif;
+      this.args = args;
+    }
+    public VueEvent(Object source, TypeModifVue modif, Unite unite, String... args) {
+      super(source, TypeMessage.MODIF_VUE);
+      this.unite = unite;
+      this.modif = modif;
+      this.args = args;
+    }
+    public TypeModifVue getModif() {
+      return modif;
+    }
+    public Unite getUnite() {
+      return unite;
+    }
+    public String getArg() {
+      return args[0];
+    }
+    public String getArg(int i) {
+      return args[i];
+    }
+  }
+
+  public static class ElementEvent extends Message {
+    private TypeModifElement modif;
+    private Element element;
+    private String[] args;
+    public ElementEvent(Object source, TypeModifElement modif, Element element, String... args) {
+      super(source, TypeMessage.MODIF_ELEMENT);
+      this.modif = modif;
+      this.element = element;
+      this.args = args;
+    }
+    public TypeModifElement getModif() {
+      return modif;
+    }
+    public Element getElement() {
+      return element;
+    }
+    public String getArg() {
+      return args[0];
+    }
+    public String getArg(int i) {
+      return args[i];
+    }
+  }
+
+  public static class StructureEvent extends Message {
+    private TypeModifStructure modif;
+    private Class<? extends Element> classe;
+    private String[] args;
+    public StructureEvent(Object source, TypeModifStructure modif, Class<? extends Element> classe, String... args) {
+      super(source, TypeMessage.MODIF_STRUCTURE);
+      this.modif = modif;
+      this.classe = classe;
+      this.args = args;
+    }
+    public TypeModifStructure getModif() {
+      return modif;
+    }
+    public Class<? extends Element> getClasse() {
+      return classe;
+    }
+    public String getArg() {
+      return args[0];
+    }
+    public String getArg(int i) {
+      return args[i];
+    }
+  }
+}
+
+
+
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/Message.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauCommandesUnites.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauCommandesUnites.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauCommandesUnites.java	(revision 3653)
@@ -0,0 +1,276 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package visuAnalec;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import visuAnalec.Message.*;
+import visuAnalec.PanneauEditeur.*;
+import visuAnalec.elements.*;
+import visuAnalec.texte.*;
+import visuAnalec.texte.PanneauAffTexte.*;
+import visuAnalec.texte.PanneauTexte.*;
+import visuAnalec.util.*;
+import visuAnalec.util.GMessages.*;
+import visuAnalec.util.GVisu.*;
+import visuAnalec.vue.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class PanneauCommandesUnites extends PanneauCommandes implements ActionListener {
+  private PanneauChamps panneauChamps;
+  public TypeComboBox saisieTypeUnites;
+  private ElementComboBox saisieUnite;
+  private JButton creeUnite;
+  private JButton supprimeUnite;
+  private JButton rectifieBorne;
+  private int[] bornesSelectTexte;
+
+  /*
+   * CREATION PAR LE PANNEAU EDITEUR
+   */
+  PanneauCommandesUnites(Vue vue, PanneauAffTexte pTexte, PanneauChamps pChamps) {
+    super(vue, pTexte);
+    JToolBar barre1 = new JToolBar("Gestion des unités");
+    barre1.setPreferredSize(new Dimension(0, 22));
+//    barre1.setBackground(PanneauTexte.getCouleurFond1());
+    barre1.setAlignmentX(0.0f);
+    add(barre1);
+    panneauChamps = pChamps;
+    saisieTypeUnites = new TypeComboBox(Unite.class);
+    saisieTypeUnites.addActionListener(this);
+    saisieUnite = new ElementComboBox();
+    saisieUnite.addActionListener(this);
+    creeUnite = new JButton(new GAction("Créer") {
+      public void executer() {
+        creerUnite();
+      }
+    });
+    supprimeUnite = new JButton(new GAction("Supprimer") {
+      public void executer() {
+        supprimerUnite();
+      }
+    });
+    rectifieBorne = new JButton(new GAction("Rectifier une borne") {
+      public void executer() {
+        modifierBorne();
+      }
+    });
+    barre1.addSeparator();
+    barre1.add(new TitreBarre("Unité : ", PanneauTexte.getCouleurFond1()));
+    barre1.addSeparator();
+    barre1.add(saisieTypeUnites);
+    barre1.add(saisieUnite);
+    barre1.addSeparator();
+    barre1.add(creeUnite);
+    barre1.addSeparator();
+    barre1.add(supprimeUnite);
+    barre1.addSeparator();
+    barre1.add(rectifieBorne);
+  }
+
+  /*
+   * COMMANDES UTILISEES PAR LE PANNEAU EDITEUR
+   */
+  public void reinitialiser() {
+    // typiquement, appelé par le panneau éditeur à la suite d'une modif de vue ou de structure
+    saisieTypeUnites.removeActionListener(this);
+    saisieTypeUnites.setModele(vue.getTypesUnitesAVoir());
+    saisieTypeUnites.effSelection();
+    saisieTypeUnites.addActionListener(this);
+    supprimeUnite.setEnabled(false);
+    rectifieBorne.setEnabled(false);
+    initSaisieUnite();
+    etatSelectRien();
+    revalidate();
+    repaint();
+  }
+  public void reafficher() {
+    // potentiellement appelé par le panneau éditeur ?
+    // appelé aussi par  traiterElementEvent
+    if (saisieUnite.pasdeSelection()) {
+      initSaisieUnite();
+      etatSelectRien();
+    } else {
+      Unite uniteCourante = (Unite) saisieUnite.getSelection();
+      initSaisieUnite(uniteCourante);
+      etatSelectUnite(uniteCourante);
+    }
+  }
+  public void elementSuivant(int sens) {
+    if (sens>0) saisieUnite.gotoSuivant();
+    else saisieUnite.gotoPrecedent();
+  }
+  public Element elementSelectionne() {
+    if (saisieUnite.pasdeSelection()) return null;
+    return saisieUnite.getSelection();
+  }
+  public void editerElement(Element elt) {
+    // appelé par le panneauEditeur : elt est forcément une unité
+    if (elt.getClass()!=Unite.class)
+      throw new UnsupportedOperationException("Erreur : classe incorrecte");
+    editerUnite((Unite) elt);
+  }
+  public ArrayList<ElementMarque> trouverElementsVises(Unite uniteVisee, TypeMarquage marqueUniteVisee,
+          boolean avecId) {
+    ArrayList<ElementMarque> eltsMarques = new ArrayList<ElementMarque>();
+    eltsMarques.add(new ElementMarque(uniteVisee, marqueUniteVisee,
+            avecId ? saisieUnite.getIdElement(uniteVisee) : null));
+    return eltsMarques;
+  }
+  public void traiterElementEvent(ElementEvent evt) {
+    // relayé par le panneau éditeur 
+    switch (evt.getModif()) {
+      case AJOUT_UNITE:
+        Unite unite = (Unite) evt.getElement();
+        editerUnite(unite);
+        return;
+      case SUP_UNITE:
+        if (evt.getElement()==saisieUnite.getSelection()) {
+          initSaisieUnite();
+          etatSelectRien();
+        } else {
+          reafficher();
+        }
+        return;
+      case BORNES_UNITE:
+        return;  // traité directement par le panneau Texte : à revoir ?
+      case AJOUT_RELATION:
+      case AJOUT_SCHEMA:
+      case SUP_RELATION:
+      case MODIF_SCHEMA:
+      case SUP_SCHEMA:
+      case MODIF_VALEUR:
+        reafficher();
+        return;
+      default:
+        throw new UnsupportedOperationException("Cas "+evt.getModif()+" oublié dans un switch");
+    }
+  }
+  void editerUnite(Unite unite) {
+    // appelé  par traiterElementEvent, 
+    // et aussi directement par le panneau éditeur quand il est sollicité par d'autres fenêtres
+    if (!unite.getType().equals(saisieTypeUnites.getTypeSelection())) {
+      saisieTypeUnites.removeActionListener(this);
+      saisieTypeUnites.setSelection(unite.getType());
+      saisieTypeUnites.addActionListener(this);
+    }
+    initSaisieUnite(unite);
+    etatSelectUnite(unite);
+  }
+  /*
+   * ACTIONS DE L'UTILISATEUR : CHANGEMENTS D'ETAT
+   */
+  public void actionPerformed(ActionEvent evt) {
+    try {
+      if (evt.getSource()==saisieTypeUnites) {
+        initSaisieUnite();
+        if (bornesSelectTexte==null) etatSelectRien();
+        else {
+          panneauTexte.getCaret().setSelectionVisible(true);
+          etatSelectTexte();
+        }
+        return;
+      }
+      if (evt.getSource()==saisieUnite) {
+        if (saisieUnite.pasdeSelection()) etatSelectRien();
+        else etatSelectUnite((Unite) saisieUnite.getSelection());
+        return;
+      }
+      throw new UnsupportedOperationException("Evénement non prévu : "+evt.paramString());
+    } catch (Throwable ex) {
+      GMessages.erreurFatale(ex);
+    }
+  }
+  @Override
+  public void traiterSourisEvent(SourisEvent evt) {
+    switch (evt.getTypeEvent()) {
+      case SELECT_RIEN:
+        saisieUnite.effSelection();
+        bornesSelectTexte = null;
+        return;
+      case SELECT_TEXTE:
+        saisieUnite.removeActionListener(this);
+        saisieUnite.effSelection();
+        saisieUnite.addActionListener(this);
+        bornesSelectTexte = evt.getBornesSelectionTexte();
+        etatSelectTexte();
+        return;
+      case SELECT_ELEMENT:
+        saisieUnite.setSelection(evt.getElementVise());
+        bornesSelectTexte = null;
+        return;
+    }
+    throw new UnsupportedOperationException("Evénement non prévu : "+evt.getTypeEvent());
+  }
+  /*
+   * ACTIONS DE L'UTILISATEUR : BOUTONS
+   */
+  private void creerUnite() {
+    if (vue.getCorpus().checkPresenceUnite(saisieTypeUnites.getTypeSelection(), bornesSelectTexte[0], bornesSelectTexte[1])
+            &&!GMessages.confirmationAction("Dupliquer cette unité  ?")) return;
+    vue.getCorpus().addUniteSaisie(saisieTypeUnites.getTypeSelection(), bornesSelectTexte[0], bornesSelectTexte[1]);
+  }
+  private void supprimerUnite() {
+    if (!GMessages.confirmationAction("Supprimer l'unité sélectionnée ?"))
+      return;
+    vue.getCorpus().supUnite((Unite) saisieUnite.getSelection());
+  }
+  private void modifierBorne() {
+    panneauTexte.rectifierBorneUnite((Unite) saisieUnite.getSelection());
+  }
+  /* 
+   * GESTION INTERNE
+   */
+  private void etatSelectUnite(Unite unite) {  // une unité est sélectionnée
+    panneauTexte.saisir(unite, new Unite[]{unite}, TypeMarquage.SELECT1);
+    //           (Unite[]) saisieUnite.getElements(), TypeMarquage.FOND1);
+    panneauChamps.afficher(unite);
+    creeUnite.setEnabled(false);
+    supprimeUnite.setEnabled(true);
+    rectifieBorne.setEnabled(true);
+  }
+  private void etatSelectRien() {  // rien n'est sélectionné
+    if (saisieTypeUnites.pasdeSelection()) panneauTexte.pasDeMarquage();
+    else
+      panneauTexte.saisir(null, (Unite[]) saisieUnite.getElements(), TypeMarquage.FOND1);
+    panneauChamps.effacer();
+    creeUnite.setEnabled(false);
+    supprimeUnite.setEnabled(false);
+    rectifieBorne.setEnabled(false);
+  }
+  private void etatSelectTexte() {    // du texte est sélectionné
+    panneauTexte.pasDeMarquage();
+//    if (saisieTypeUnites.pasdeSelection()) panneauTexte.pasDeMarquage();
+//    else panneauTexte.saisir(null, (Unite[]) saisieUnite.getElements(), TypeMarquage.FOND1);
+    panneauChamps.effacer();
+    if (!saisieTypeUnites.pasdeSelection()) {
+      creeUnite.setEnabled(true);
+//      Boutons.setDefaut(creeUnite, true);
+    }
+    supprimeUnite.setEnabled(false);
+    rectifieBorne.setEnabled(false);
+  }
+  private void initSaisieUnite(Unite unit) {
+    saisieUnite.removeActionListener(this);
+    if (saisieTypeUnites.pasdeSelection()) saisieUnite.setModeleVide();
+    else {
+      String type0 = saisieTypeUnites.getTypeSelection();
+      Unite[] unites = vue.getUnitesAVoir(type0);
+      saisieUnite.setModele(unites, vue.getIdUnites(type0, unites));
+    }
+    if (unit==null) saisieUnite.effSelection();
+    else saisieUnite.setSelection(unit);
+    saisieUnite.addActionListener(this);
+    saisieUnite.revalidate();
+  }
+  private void initSaisieUnite() {
+    initSaisieUnite(null);
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/visuAnalec/PanneauCommandesUnites.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/LUDecomposition.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/LUDecomposition.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/LUDecomposition.java	(revision 3653)
@@ -0,0 +1,311 @@
+package JamaPlus;
+
+   /** LU Decomposition.
+   <P>
+   For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n
+   unit lower triangular matrix L, an n-by-n upper triangular matrix U,
+   and a permutation vector piv of length m so that A(piv,:) = L*U.
+   If m < n, then L is m-by-m and U is m-by-n.
+   <P>
+   The LU decompostion with pivoting always exists, even if the matrix is
+   singular, so the constructor will never fail.  The primary use of the
+   LU decomposition is in the solution of square systems of simultaneous
+   linear equations.  This will fail if isNonsingular() returns false.
+   */
+
+public class LUDecomposition implements java.io.Serializable {
+
+/* ------------------------
+   Class variables
+ * ------------------------ */
+
+   /** Array for internal storage of decomposition.
+   @serial internal array storage.
+   */
+   private double[][] LU;
+
+   /** Row and column dimensions, and pivot sign.
+   @serial column dimension.
+   @serial row dimension.
+   @serial pivot sign.
+   */
+   private int m, n, pivsign; 
+
+   /** Internal storage of pivot vector.
+   @serial pivot vector.
+   */
+   private int[] piv;
+
+/* ------------------------
+   Constructor
+ * ------------------------ */
+
+   /** LU Decomposition
+   @param  A   Rectangular matrix
+   @return     Structure to access L, U and piv.
+   */
+
+   public LUDecomposition (Matrix A) {
+
+   // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
+
+      LU = A.getArrayCopy();
+      m = A.getRowDimension();
+      n = A.getColumnDimension();
+      piv = new int[m];
+      for (int i = 0; i < m; i++) {
+         piv[i] = i;
+      }
+      pivsign = 1;
+      double[] LUrowi;
+      double[] LUcolj = new double[m];
+
+      // Outer loop.
+
+      for (int j = 0; j < n; j++) {
+
+         // Make a copy of the j-th column to localize references.
+
+         for (int i = 0; i < m; i++) {
+            LUcolj[i] = LU[i][j];
+         }
+
+         // Apply previous transformations.
+
+         for (int i = 0; i < m; i++) {
+            LUrowi = LU[i];
+
+            // Most of the time is spent in the following dot product.
+
+            int kmax = Math.min(i,j);
+            double s = 0.0;
+            for (int k = 0; k < kmax; k++) {
+               s += LUrowi[k]*LUcolj[k];
+            }
+
+            LUrowi[j] = LUcolj[i] -= s;
+         }
+   
+         // Find pivot and exchange if necessary.
+
+         int p = j;
+         for (int i = j+1; i < m; i++) {
+            if (Math.abs(LUcolj[i]) > Math.abs(LUcolj[p])) {
+               p = i;
+            }
+         }
+         if (p != j) {
+            for (int k = 0; k < n; k++) {
+               double t = LU[p][k]; LU[p][k] = LU[j][k]; LU[j][k] = t;
+            }
+            int k = piv[p]; piv[p] = piv[j]; piv[j] = k;
+            pivsign = -pivsign;
+         }
+
+         // Compute multipliers.
+         
+         if (j < m & LU[j][j] != 0.0) {
+            for (int i = j+1; i < m; i++) {
+               LU[i][j] /= LU[j][j];
+            }
+         }
+      }
+   }
+
+/* ------------------------
+   Temporary, experimental code.
+   ------------------------ *\
+
+   \** LU Decomposition, computed by Gaussian elimination.
+   <P>
+   This constructor computes L and U with the "daxpy"-based elimination
+   algorithm used in LINPACK and MATLAB.  In Java, we suspect the dot-product,
+   Crout algorithm will be faster.  We have temporarily included this
+   constructor until timing experiments confirm this suspicion.
+   <P>
+   @param  A             Rectangular matrix
+   @param  linpackflag   Use Gaussian elimination.  Actual value ignored.
+   @return               Structure to access L, U and piv.
+   *\
+
+   public LUDecomposition (Matrix A, int linpackflag) {
+      // Initialize.
+      LU = A.getArrayCopy();
+      m = A.getRowDimension();
+      n = A.getColumnDimension();
+      piv = new int[m];
+      for (int i = 0; i < m; i++) {
+         piv[i] = i;
+      }
+      pivsign = 1;
+      // Main loop.
+      for (int k = 0; k < n; k++) {
+         // Find pivot.
+         int p = k;
+         for (int i = k+1; i < m; i++) {
+            if (Math.abs(LU[i][k]) > Math.abs(LU[p][k])) {
+               p = i;
+            }
+         }
+         // Exchange if necessary.
+         if (p != k) {
+            for (int j = 0; j < n; j++) {
+               double t = LU[p][j]; LU[p][j] = LU[k][j]; LU[k][j] = t;
+            }
+            int t = piv[p]; piv[p] = piv[k]; piv[k] = t;
+            pivsign = -pivsign;
+         }
+         // Compute multipliers and eliminate k-th column.
+         if (LU[k][k] != 0.0) {
+            for (int i = k+1; i < m; i++) {
+               LU[i][k] /= LU[k][k];
+               for (int j = k+1; j < n; j++) {
+                  LU[i][j] -= LU[i][k]*LU[k][j];
+               }
+            }
+         }
+      }
+   }
+
+\* ------------------------
+   End of temporary code.
+ * ------------------------ */
+
+/* ------------------------
+   Public Methods
+ * ------------------------ */
+
+   /** Is the matrix nonsingular?
+   @return     true if U, and hence A, is nonsingular.
+   */
+
+   public boolean isNonsingular () {
+      for (int j = 0; j < n; j++) {
+         if (LU[j][j] == 0)
+            return false;
+      }
+      return true;
+   }
+
+   /** Return lower triangular factor
+   @return     L
+   */
+
+   public Matrix getL () {
+      Matrix X = new Matrix(m,n);
+      double[][] L = X.getArray();
+      for (int i = 0; i < m; i++) {
+         for (int j = 0; j < n; j++) {
+            if (i > j) {
+               L[i][j] = LU[i][j];
+            } else if (i == j) {
+               L[i][j] = 1.0;
+            } else {
+               L[i][j] = 0.0;
+            }
+         }
+      }
+      return X;
+   }
+
+   /** Return upper triangular factor
+   @return     U
+   */
+
+   public Matrix getU () {
+      Matrix X = new Matrix(n,n);
+      double[][] U = X.getArray();
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            if (i <= j) {
+               U[i][j] = LU[i][j];
+            } else {
+               U[i][j] = 0.0;
+            }
+         }
+      }
+      return X;
+   }
+
+   /** Return pivot permutation vector
+   @return     piv
+   */
+
+   public int[] getPivot () {
+      int[] p = new int[m];
+      for (int i = 0; i < m; i++) {
+         p[i] = piv[i];
+      }
+      return p;
+   }
+
+   /** Return pivot permutation vector as a one-dimensional double array
+   @return     (double) piv
+   */
+
+   public double[] getDoublePivot () {
+      double[] vals = new double[m];
+      for (int i = 0; i < m; i++) {
+         vals[i] = (double) piv[i];
+      }
+      return vals;
+   }
+
+   /** Determinant
+   @return     det(A)
+   @exception  IllegalArgumentException  Matrix must be square
+   */
+
+   public double det () {
+      if (m != n) {
+         throw new IllegalArgumentException("Matrix must be square.");
+      }
+      double d = (double) pivsign;
+      for (int j = 0; j < n; j++) {
+         d *= LU[j][j];
+      }
+      return d;
+   }
+
+   /** Solve A*X = B
+   @param  B   A Matrix with as many rows as A and any number of columns.
+   @return     X so that L*U*X = B(piv,:)
+   @exception  IllegalArgumentException Matrix row dimensions must agree.
+   @exception  RuntimeException  Matrix is singular.
+   */
+
+   public Matrix solve (Matrix B) {
+      if (B.getRowDimension() != m) {
+         throw new IllegalArgumentException("Matrix row dimensions must agree.");
+      }
+      if (!this.isNonsingular()) {
+         throw new RuntimeException("Matrix is singular.");
+      }
+
+      // Copy right hand side with pivoting
+      int nx = B.getColumnDimension();
+      Matrix Xmat = B.getMatrix(piv,0,nx-1);
+      double[][] X = Xmat.getArray();
+
+      // Solve L*Y = B(piv,:)
+      for (int k = 0; k < n; k++) {
+         for (int i = k+1; i < n; i++) {
+            for (int j = 0; j < nx; j++) {
+               X[i][j] -= X[k][j]*LU[i][k];
+            }
+         }
+      }
+      // Solve U*X = Y;
+      for (int k = n-1; k >= 0; k--) {
+         for (int j = 0; j < nx; j++) {
+            X[k][j] /= LU[k][k];
+         }
+         for (int i = 0; i < k; i++) {
+            for (int j = 0; j < nx; j++) {
+               X[i][j] -= X[k][j]*LU[i][k];
+            }
+         }
+      }
+      return Xmat;
+   }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/LUDecomposition.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/util/Machine.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/util/Machine.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/util/Machine.java	(revision 3653)
@@ -0,0 +1,143 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package JamaPlus.util;
+
+/**
+ *
+ * @author Bernard
+ */
+public class Machine {
+
+    /***********************************************************************
+     *                                                                     *
+     *				machar()			       *
+     *                                                                     *
+     ***********************************************************************/
+    /***********************************************************************
+    
+    Description
+    -----------
+    
+    This function is a partial translation of a Fortran-77 subroutine 
+    written by W. J. Cody of Argonne National Laboratory.
+    It dynamically determines the listed machine parameters of the
+    floating-point arithmetic.  According to the documentation of
+    the Fortran code, "the determination of the first three uses an
+    extension of an algorithm due to M. Malcolm, ACM 15 (1972), 
+    pp. 949-951, incorporating some, but not all, of the improvements
+    suggested by M. Gentleman and S. Marovich, CACM 17 (1974), 
+    pp. 276-277."  The complete Fortran version of this translation is
+    documented in W. J. Cody, "Machar: a Subroutine to Dynamically 
+    Determine Determine Machine Parameters," TOMS 14, December, 1988.
+    
+    
+    Parameters reported 
+    -------------------
+    
+    ibeta     the radix for the floating-point representation       
+    it        the number of base ibeta digits in the floating-point
+    significand					 
+    irnd      0 if floating-point addition chops		      
+    1 if floating-point addition rounds, but not in the 
+    ieee style					
+    2 if floating-point addition rounds in the ieee style
+    3 if floating-point addition chops, and there is    
+    partial underflow				
+    4 if floating-point addition rounds, but not in the
+    ieee style, and there is partial underflow    
+    5 if floating-point addition rounds in the ieee style,
+    and there is partial underflow                   
+    machep    the largest negative integer such that              
+    1.0+float(ibeta)**machep .ne. 1.0, except that 
+    machep is bounded below by  -(it+3)          
+    negeps    the largest negative integer such that          
+    1.0-float(ibeta)**negeps .ne. 1.0, except that 
+    negeps is bounded below by  -(it+3)	       
+    
+     ***********************************************************************/
+    public static double eps(/*int res[]*/) {
+        int ibeta, it, irnd, machep, negep;
+        double beta, betain, betah, a, b = 0, ZERO, ONE, TWO, temp, tempa, temp1;
+        int i, itemp;
+
+        ONE = (double) 1;
+        TWO = ONE + ONE;
+        ZERO = ONE - ONE;
+
+        a = ONE;
+        temp1 = ONE;
+        while (temp1 - ONE == ZERO) {
+            a += a;
+            temp = a + ONE;
+            temp1 = temp - a;
+            b += a; /* to prevent icc compiler error */
+        }
+        b = ONE;
+        itemp = 0;
+        while (itemp == 0) {
+            b += b;
+            temp = a + b;
+            itemp = (int) (temp - a);
+        }
+        ibeta = itemp;
+        beta = (double) ibeta;
+
+        it = 0;
+        b = ONE;
+        temp1 = ONE;
+        while (temp1 - ONE == ZERO) {
+            it++;
+            b *= beta;
+            temp = b + ONE;
+            temp1 = temp - b;
+        }
+        irnd = 0;
+        betah = beta / TWO;
+        temp = a + betah;
+        if (temp - a != ZERO) irnd = 1;
+        tempa = a + beta;
+        temp = tempa + betah;
+        if ((irnd == 0) && (temp - tempa != ZERO)) irnd = 2;
+
+        negep = it + 3;
+        betain = ONE / beta;
+        a = ONE;
+        for (i = 0; i < negep; i++) a *= betain;
+        b = a;
+        temp = ONE - a;
+        while (temp - ONE == ZERO) {
+            a *= beta;
+            negep--;
+            temp = ONE - a;
+        }
+        negep = -(negep);
+
+        machep = -(it) - 3;
+        a = b;
+        temp = ONE + a;
+        while (temp - ONE == ZERO) {
+            a *= beta;
+            machep += 1;
+            temp = ONE + a;
+        }
+//        res[0] = ibeta;
+//        res[1] = it;
+//        res[2] = irnd;
+//        res[3] = machep;
+//        res[4] = negep;
+        return a;
+    }
+
+    static public void main(String[] args) {
+        int[] res = new int[5];
+//        double precision = eps(res);
+//        System.out.println("eps = " + precision);
+        System.out.println("ibeta = " + res[0]);
+        System.out.println("it = " + res[1]);
+        System.out.println("irnd = " + res[2]);
+        System.out.println("machep = " + res[3]);
+        System.out.println("negep = " + res[4]);
+    }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/util/Machine.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/util/DoubleArraysPlus.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/util/DoubleArraysPlus.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/util/DoubleArraysPlus.java	(revision 3653)
@@ -0,0 +1,97 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package JamaPlus.util;
+
+import java.util.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class DoubleArraysPlus {
+  public static void copyReverse(int length, double[] src, int srcStart,
+          double[] dest, int destStart) {
+    destStart += length-1;
+    for (int i = 0; i<length; i++) dest[destStart-i] = src[srcStart+i];
+  }
+
+   private static class Couple implements Comparable<Couple> {
+    double x1;
+    Object x2;
+
+    public int compareTo(Couple c) {
+      return Double.compare(x1, c.x1);
+    }
+  }
+
+  public static void sort2(double[] a1, double[] a2, int n, int istart) {
+    // sort the first n elements of a1 and a2, starting at index istart,
+    // in increasing order for a1 
+    // (elements with indexes < istart or > istart + n preserved) 
+    Couple[] cs = new Couple[n];
+    for (int i = 0; i<n; i++) {
+      cs[i] = new Couple();
+      cs[i].x1 = a1[i+istart];
+      cs[i].x2 = a2[i+istart];
+    }
+    Arrays.sort(cs);
+    for (int i = 0; i<n; i++) {
+      a1[i+istart] = cs[i].x1;
+      a2[i+istart] = (Double) cs[i].x2;
+    }
+  }
+ public static void sort2(double[] a1, double[][] a2, int n, int istart) {
+    // sort the first n elements of a1 and a2[] (lines of array a2)
+//    starting at index istart, in increasing order for a1
+    // (elements with index < istart or > istart + n preserved) 
+    Couple[] cs = new Couple[n];
+    for (int i = 0; i<n; i++) {
+      cs[i] = new Couple();
+      cs[i].x1 = a1[i+istart];
+      cs[i].x2 = a2[i+istart];
+    }
+    Arrays.sort(cs);
+    for (int i = 0; i<n; i++) {
+      a1[i+istart] = cs[i].x1;
+      a2[i+istart] = (double[]) cs[i].x2;
+    }
+  }
+
+  public static int indAbsMax(int n, double x[], int istart) {
+    // finds the index of element having maximum absolute value 
+    // among the first n elements of x starting at index istart
+    if (n<1||istart<0||istart+n>x.length)
+      throw new ArrayIndexOutOfBoundsException();
+    if (n==1) return (istart);
+    double max = Math.abs(x[istart]);
+    int imax = istart;
+    for (int i = istart+1; i<istart+n; i++) {
+      double ax = Math.abs(x[i]);
+      if (ax>max) {
+        max = ax;
+        imax = i;
+      }
+    }
+    return imax;
+  }
+
+  public static double dot(double[] x, double[] y) {
+    // dot product of vectors x and y
+    int n = x.length;
+    if (n!=y.length) throw new IllegalArgumentException();
+    double res = 0;
+    for (int i = 0; i<n; i++) res += x[i]*y[i];
+    return res;
+  }
+  public static void rotateArray(double[][] a, int x) {
+    // permutation circulaire des lignes de la matrice a
+    // plaçant la ligne x en tête
+  double[][] b =new double[a.length-x][];
+ System.arraycopy(a, x, b, 0, b.length);
+ System.arraycopy(a, 0, a, b.length, a.length-b.length);
+ System.arraycopy(b, 0, a, 0, b.length);
+     }
+
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/util/DoubleArraysPlus.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/CholeskyDecomposition.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/CholeskyDecomposition.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/CholeskyDecomposition.java	(revision 3653)
@@ -0,0 +1,199 @@
+package JamaPlus;
+
+   /** Cholesky Decomposition.
+   <P>
+   For a symmetric, positive definite matrix A, the Cholesky decomposition
+   is an lower triangular matrix L so that A = L*L'.
+   <P>
+   If the matrix is not symmetric or positive definite, the constructor
+   returns a partial decomposition and sets an internal flag that may
+   be queried by the isSPD() method.
+   */
+
+public class CholeskyDecomposition implements java.io.Serializable {
+
+/* ------------------------
+   Class variables
+ * ------------------------ */
+
+   /** Array for internal storage of decomposition.
+   @serial internal array storage.
+   */
+   private double[][] L;
+
+   /** Row and column dimension (square matrix).
+   @serial matrix dimension.
+   */
+   private int n;
+
+   /** Symmetric and positive definite flag.
+   @serial is symmetric and positive definite flag.
+   */
+   private boolean isspd;
+
+/* ------------------------
+   Constructor
+ * ------------------------ */
+
+   /** Cholesky algorithm for symmetric and positive definite matrix.
+   @param  A   Square, symmetric matrix.
+   @return     Structure to access L and isspd flag.
+   */
+
+   public CholeskyDecomposition (Matrix Arg) {
+
+
+     // Initialize.
+      double[][] A = Arg.getArray();
+      n = Arg.getRowDimension();
+      L = new double[n][n];
+      isspd = (Arg.getColumnDimension() == n);
+      // Main loop.
+      for (int j = 0; j < n; j++) {
+         double[] Lrowj = L[j];
+         double d = 0.0;
+         for (int k = 0; k < j; k++) {
+            double[] Lrowk = L[k];
+            double s = 0.0;
+            for (int i = 0; i < k; i++) {
+               s += Lrowk[i]*Lrowj[i];
+            }
+            Lrowj[k] = s = (A[j][k] - s)/L[k][k];
+            d = d + s*s;
+            isspd = isspd & (A[k][j] == A[j][k]); 
+         }
+         d = A[j][j] - d;
+         isspd = isspd & (d > 0.0);
+         L[j][j] = Math.sqrt(Math.max(d,0.0));
+         for (int k = j+1; k < n; k++) {
+            L[j][k] = 0.0;
+         }
+      }
+   }
+
+/* ------------------------
+   Temporary, experimental code.
+ * ------------------------ *\
+
+   \** Right Triangular Cholesky Decomposition.
+   <P>
+   For a symmetric, positive definite matrix A, the Right Cholesky
+   decomposition is an upper triangular matrix R so that A = R'*R.
+   This constructor computes R with the Fortran inspired column oriented
+   algorithm used in LINPACK and MATLAB.  In Java, we suspect a row oriented,
+   lower triangular decomposition is faster.  We have temporarily included
+   this constructor here until timing experiments confirm this suspicion.
+   *\
+
+   \** Array for internal storage of right triangular decomposition. **\
+   private transient double[][] R;
+
+   \** Cholesky algorithm for symmetric and positive definite matrix.
+   @param  A           Square, symmetric matrix.
+   @param  rightflag   Actual value ignored.
+   @return             Structure to access R and isspd flag.
+   *\
+
+   public CholeskyDecomposition (Matrix Arg, int rightflag) {
+      // Initialize.
+      double[][] A = Arg.getArray();
+      n = Arg.getColumnDimension();
+      R = new double[n][n];
+      isspd = (Arg.getColumnDimension() == n);
+      // Main loop.
+      for (int j = 0; j < n; j++) {
+         double d = 0.0;
+         for (int k = 0; k < j; k++) {
+            double s = A[k][j];
+            for (int i = 0; i < k; i++) {
+               s = s - R[i][k]*R[i][j];
+            }
+            R[k][j] = s = s/R[k][k];
+            d = d + s*s;
+            isspd = isspd & (A[k][j] == A[j][k]); 
+         }
+         d = A[j][j] - d;
+         isspd = isspd & (d > 0.0);
+         R[j][j] = Math.sqrt(Math.max(d,0.0));
+         for (int k = j+1; k < n; k++) {
+            R[k][j] = 0.0;
+         }
+      }
+   }
+
+   \** Return upper triangular factor.
+   @return     R
+   *\
+
+   public Matrix getR () {
+      return new Matrix(R,n,n);
+   }
+
+\* ------------------------
+   End of temporary code.
+ * ------------------------ */
+
+/* ------------------------
+   Public Methods
+ * ------------------------ */
+
+   /** Is the matrix symmetric and positive definite?
+   @return     true if A is symmetric and positive definite.
+   */
+
+   public boolean isSPD () {
+      return isspd;
+   }
+
+   /** Return triangular factor.
+   @return     L
+   */
+
+   public Matrix getL () {
+      return new Matrix(L,n,n);
+   }
+
+   /** Solve A*X = B
+   @param  B   A Matrix with as many rows as A and any number of columns.
+   @return     X so that L*L'*X = B
+   @exception  IllegalArgumentException  Matrix row dimensions must agree.
+   @exception  RuntimeException  Matrix is not symmetric positive definite.
+   */
+
+   public Matrix solve (Matrix B) {
+      if (B.getRowDimension() != n) {
+         throw new IllegalArgumentException("Matrix row dimensions must agree.");
+      }
+      if (!isspd) {
+         throw new RuntimeException("Matrix is not symmetric positive definite.");
+      }
+
+      // Copy right hand side.
+      double[][] X = B.getArrayCopy();
+      int nx = B.getColumnDimension();
+
+	      // Solve L*Y = B;
+	      for (int k = 0; k < n; k++) {
+	        for (int j = 0; j < nx; j++) {
+	           for (int i = 0; i < k ; i++) {
+	               X[k][j] -= X[i][j]*L[k][i];
+	           }
+	           X[k][j] /= L[k][k];
+	        }
+	      }
+	
+	      // Solve L'*X = Y;
+	      for (int k = n-1; k >= 0; k--) {
+	        for (int j = 0; j < nx; j++) {
+	           for (int i = k+1; i < n ; i++) {
+	               X[k][j] -= X[i][j]*L[i][k];
+	           }
+	           X[k][j] /= L[k][k];
+	        }
+	      }
+      
+      
+      return new Matrix(X,n,nx);
+   }
+}
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/CholeskyDecomposition.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SingularValueDecomposition.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SingularValueDecomposition.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SingularValueDecomposition.java	(revision 3653)
@@ -0,0 +1,556 @@
+package JamaPlus;
+import JamaPlus.util.*;
+
+   /** Singular Value Decomposition.
+   <P>
+   For an m-by-n matrix A with m >= n, the singular value decomposition is
+   an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and
+   an n-by-n orthogonal matrix V so that A = U*S*V'.
+   <P>
+   The singular values, sigma[k] = S[k][k], are ordered so that
+   sigma[0] >= sigma[1] >= ... >= sigma[n-1].
+   <P>
+   The singular value decompostion always exists, so the constructor will
+   never fail.  The matrix condition number and the effective numerical
+   rank can be computed from this decomposition.
+   */
+
+public class SingularValueDecomposition implements java.io.Serializable {
+
+/* ------------------------
+   Class variables
+ * ------------------------ */
+
+   /** Arrays for internal storage of U and V.
+   @serial internal storage of U.
+   @serial internal storage of V.
+   */
+   private double[][] U, V;
+
+   /** Array for internal storage of singular values.
+   @serial internal storage of singular values.
+   */
+   private double[] s;
+
+   /** Row and column dimensions.
+   @serial row dimension.
+   @serial column dimension.
+   */
+   private int m, n;
+   
+   private boolean transpose; // pour éviter les bugs quand m<n (cf.ci-dessous) 
+
+/* ------------------------
+   Constructor
+ * ------------------------ */
+
+   /** Construct the singular value decomposition
+   @param A    Rectangular matrix
+   @return     Structure to access U, S and V.
+   */
+
+   public SingularValueDecomposition (Matrix Arg) {
+
+      // Derived from LINPACK code.
+      // Initialize.
+      /* Apparently the failing cases are only a proper subset of (m<n), 
+	 so let's not throw error.  Correct fix to come later?
+      if (m<n) {
+	  throw new IllegalArgumentException("Jama SVD only works for m >= n"); }
+      */
+      /* 
+       * Une façon très simple de contourner le problème ci-dessus :
+       * si m < n on transpose A
+       * (ce qui revient à échanger U et V, S restant inchangé)
+       */
+   transpose = Arg.getColumnDimension()>Arg.getRowDimension();
+    Matrix M = transpose ? Arg.transpose() : Arg.copy();
+  
+     double[][] A = M.getArray();
+      m = M.getRowDimension();
+      n = M.getColumnDimension();
+
+      s = new double [n];
+      U = new double [m][n];
+      V = new double [n][n];
+      double[] e = new double [n];
+      double[] work = new double [m];
+      boolean wantu = true;
+      boolean wantv = true;
+
+      // Reduce A to bidiagonal form, storing the diagonal elements
+      // in s and the super-diagonal elements in e.
+
+      int nct = Math.min(m-1,n);
+      int nrt = Math.max(0,Math.min(n-2,m));
+      for (int k = 0; k < Math.max(nct,nrt); k++) {
+         if (k < nct) {
+
+            // Compute the transformation for the k-th column and
+            // place the k-th diagonal in s[k].
+            // Compute 2-norm of k-th column without under/overflow.
+            s[k] = 0;
+            for (int i = k; i < m; i++) {
+               s[k] = Math.hypot(s[k],A[i][k]);
+            }
+            if (s[k] != 0.0) {
+               if (A[k][k] < 0.0) {
+                  s[k] = -s[k];
+               }
+               for (int i = k; i < m; i++) {
+                  A[i][k] /= s[k];
+               }
+               A[k][k] += 1.0;
+            }
+            s[k] = -s[k];
+         }
+         for (int j = k+1; j < n; j++) {
+            if ((k < nct) & (s[k] != 0.0))  {
+
+            // Apply the transformation.
+
+               double t = 0;
+               for (int i = k; i < m; i++) {
+                  t += A[i][k]*A[i][j];
+               }
+               t = -t/A[k][k];
+               for (int i = k; i < m; i++) {
+                  A[i][j] += t*A[i][k];
+               }
+            }
+
+            // Place the k-th row of A into e for the
+            // subsequent calculation of the row transformation.
+
+            e[j] = A[k][j];
+         }
+         if (wantu & (k < nct)) {
+
+            // Place the transformation in U for subsequent back
+            // multiplication.
+
+            for (int i = k; i < m; i++) {
+               U[i][k] = A[i][k];
+            }
+         }
+         if (k < nrt) {
+
+            // Compute the k-th row transformation and place the
+            // k-th super-diagonal in e[k].
+            // Compute 2-norm without under/overflow.
+            e[k] = 0;
+            for (int i = k+1; i < n; i++) {
+               e[k] = Math.hypot(e[k],e[i]);
+            }
+            if (e[k] != 0.0) {
+               if (e[k+1] < 0.0) {
+                  e[k] = -e[k];
+               }
+               for (int i = k+1; i < n; i++) {
+                  e[i] /= e[k];
+               }
+               e[k+1] += 1.0;
+            }
+            e[k] = -e[k];
+            if ((k+1 < m) & (e[k] != 0.0)) {
+
+            // Apply the transformation.
+
+               for (int i = k+1; i < m; i++) {
+                  work[i] = 0.0;
+               }
+               for (int j = k+1; j < n; j++) {
+                  for (int i = k+1; i < m; i++) {
+                     work[i] += e[j]*A[i][j];
+                  }
+               }
+               for (int j = k+1; j < n; j++) {
+                  double t = -e[j]/e[k+1];
+                  for (int i = k+1; i < m; i++) {
+                     A[i][j] += t*work[i];
+                  }
+               }
+            }
+            if (wantv) {
+
+            // Place the transformation in V for subsequent
+            // back multiplication.
+
+               for (int i = k+1; i < n; i++) {
+                  V[i][k] = e[i];
+               }
+            }
+         }
+      }
+
+      // Set up the final bidiagonal matrix or order p.
+
+      int p = Math.min(n,m+1);
+      if (nct < n) {
+         s[nct] = A[nct][nct];
+      }
+      if (m < p) {
+         s[p-1] = 0.0;
+      }
+      if (nrt+1 < p) {
+         e[nrt] = A[nrt][p-1];
+      }
+      e[p-1] = 0.0;
+
+      // If required, generate U.
+
+      if (wantu) {
+         for (int j = nct; j < n; j++) {
+            for (int i = 0; i < m; i++) {
+               U[i][j] = 0.0;
+            }
+            U[j][j] = 1.0;
+         }
+         for (int k = nct-1; k >= 0; k--) {
+            if (s[k] != 0.0) {
+               for (int j = k+1; j < n; j++) {
+                  double t = 0;
+                  for (int i = k; i < m; i++) {
+                     t += U[i][k]*U[i][j];
+                  }
+                  t = -t/U[k][k];
+                  for (int i = k; i < m; i++) {
+                     U[i][j] += t*U[i][k];
+                  }
+               }
+               for (int i = k; i < m; i++ ) {
+                  U[i][k] = -U[i][k];
+               }
+               U[k][k] = 1.0 + U[k][k];
+               for (int i = 0; i < k-1; i++) {
+                  U[i][k] = 0.0;
+               }
+            } else {
+               for (int i = 0; i < m; i++) {
+                  U[i][k] = 0.0;
+               }
+               U[k][k] = 1.0;
+            }
+         }
+      }
+
+      // If required, generate V.
+
+      if (wantv) {
+         for (int k = n-1; k >= 0; k--) {
+            if ((k < nrt) & (e[k] != 0.0)) {
+               for (int j = k+1; j < n; j++) {
+                  double t = 0;
+                  for (int i = k+1; i < n; i++) {
+                     t += V[i][k]*V[i][j];
+                  }
+                  t = -t/V[k+1][k];
+                  for (int i = k+1; i < n; i++) {
+                     V[i][j] += t*V[i][k];
+                  }
+               }
+            }
+            for (int i = 0; i < n; i++) {
+               V[i][k] = 0.0;
+            }
+            V[k][k] = 1.0;
+         }
+      }
+
+      // Main iteration loop for the singular values.
+
+      int pp = p-1;
+      int iter = 0;
+      double eps = Math.pow(2.0,-52.0);
+      double tiny = Math.pow(2.0,-966.0);
+      while (p > 0) {
+         int k,kase;
+
+         // Here is where a test for too many iterations would go.
+
+         // This section of the program inspects for
+         // negligible elements in the s and e arrays.  On
+         // completion the variables kase and k are set as follows.
+
+         // kase = 1     if s(p) and e[k-1] are negligible and k<p
+         // kase = 2     if s(k) is negligible and k<p
+         // kase = 3     if e[k-1] is negligible, k<p, and
+         //              s(k), ..., s(p) are not negligible (qr step).
+         // kase = 4     if e(p-1) is negligible (convergence).
+
+         for (k = p-2; k >= -1; k--) {
+            if (k == -1) {
+               break;
+            }
+            if (Math.abs(e[k]) <=
+                  tiny + eps*(Math.abs(s[k]) + Math.abs(s[k+1]))) {
+               e[k] = 0.0;
+               break;
+            }
+         }
+         if (k == p-2) {
+            kase = 4;
+         } else {
+            int ks;
+            for (ks = p-1; ks >= k; ks--) {
+               if (ks == k) {
+                  break;
+               }
+               double t = (ks != p ? Math.abs(e[ks]) : 0.) + 
+                          (ks != k+1 ? Math.abs(e[ks-1]) : 0.);
+               if (Math.abs(s[ks]) <= tiny + eps*t)  {
+                  s[ks] = 0.0;
+                  break;
+               }
+            }
+            if (ks == k) {
+               kase = 3;
+            } else if (ks == p-1) {
+               kase = 1;
+            } else {
+               kase = 2;
+               k = ks;
+            }
+         }
+         k++;
+
+         // Perform the task indicated by kase.
+
+         switch (kase) {
+
+            // Deflate negligible s(p).
+
+            case 1: {
+               double f = e[p-2];
+               e[p-2] = 0.0;
+               for (int j = p-2; j >= k; j--) {
+                  double t = Math.hypot(s[j],f);
+                  double cs = s[j]/t;
+                  double sn = f/t;
+                  s[j] = t;
+                  if (j != k) {
+                     f = -sn*e[j-1];
+                     e[j-1] = cs*e[j-1];
+                  }
+                  if (wantv) {
+                     for (int i = 0; i < n; i++) {
+                        t = cs*V[i][j] + sn*V[i][p-1];
+                        V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1];
+                        V[i][j] = t;
+                     }
+                  }
+               }
+            }
+            break;
+
+            // Split at negligible s(k).
+
+            case 2: {
+               double f = e[k-1];
+               e[k-1] = 0.0;
+               for (int j = k; j < p; j++) {
+                  double t = Math.hypot(s[j],f);
+                  double cs = s[j]/t;
+                  double sn = f/t;
+                  s[j] = t;
+                  f = -sn*e[j];
+                  e[j] = cs*e[j];
+                  if (wantu) {
+                     for (int i = 0; i < m; i++) {
+                        t = cs*U[i][j] + sn*U[i][k-1];
+                        U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1];
+                        U[i][j] = t;
+                     }
+                  }
+               }
+            }
+            break;
+
+            // Perform one qr step.
+
+            case 3: {
+
+               // Calculate the shift.
+   
+               double scale = Math.max(Math.max(Math.max(Math.max(
+                       Math.abs(s[p-1]),Math.abs(s[p-2])),Math.abs(e[p-2])), 
+                       Math.abs(s[k])),Math.abs(e[k]));
+               double sp = s[p-1]/scale;
+               double spm1 = s[p-2]/scale;
+               double epm1 = e[p-2]/scale;
+               double sk = s[k]/scale;
+               double ek = e[k]/scale;
+               double b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
+               double c = (sp*epm1)*(sp*epm1);
+               double shift = 0.0;
+               if ((b != 0.0) | (c != 0.0)) {
+                  shift = Math.sqrt(b*b + c);
+                  if (b < 0.0) {
+                     shift = -shift;
+                  }
+                  shift = c/(b + shift);
+               }
+               double f = (sk + sp)*(sk - sp) + shift;
+               double g = sk*ek;
+   
+               // Chase zeros.
+   
+               for (int j = k; j < p-1; j++) {
+                  double t = Math.hypot(f,g);
+                  double cs = f/t;
+                  double sn = g/t;
+                  if (j != k) {
+                     e[j-1] = t;
+                  }
+                  f = cs*s[j] + sn*e[j];
+                  e[j] = cs*e[j] - sn*s[j];
+                  g = sn*s[j+1];
+                  s[j+1] = cs*s[j+1];
+                  if (wantv) {
+                     for (int i = 0; i < n; i++) {
+                        t = cs*V[i][j] + sn*V[i][j+1];
+                        V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1];
+                        V[i][j] = t;
+                     }
+                  }
+                  t = Math.hypot(f,g);
+                  cs = f/t;
+                  sn = g/t;
+                  s[j] = t;
+                  f = cs*e[j] + sn*s[j+1];
+                  s[j+1] = -sn*e[j] + cs*s[j+1];
+                  g = sn*e[j+1];
+                  e[j+1] = cs*e[j+1];
+                  if (wantu && (j < m-1)) {
+                     for (int i = 0; i < m; i++) {
+                        t = cs*U[i][j] + sn*U[i][j+1];
+                        U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1];
+                        U[i][j] = t;
+                     }
+                  }
+               }
+               e[p-2] = f;
+               iter = iter + 1;
+            }
+            break;
+
+            // Convergence.
+
+            case 4: {
+
+               // Make the singular values positive.
+   
+               if (s[k] <= 0.0) {
+                  s[k] = (s[k] < 0.0 ? -s[k] : 0.0);
+                  if (wantv) {
+                     for (int i = 0; i <= pp; i++) {
+                        V[i][k] = -V[i][k];
+                     }
+                  }
+               }
+   
+               // Order the singular values.
+   
+               while (k < pp) {
+                  if (s[k] >= s[k+1]) {
+                     break;
+                  }
+                  double t = s[k];
+                  s[k] = s[k+1];
+                  s[k+1] = t;
+                  if (wantv && (k < n-1)) {
+                     for (int i = 0; i < n; i++) {
+                        t = V[i][k+1]; V[i][k+1] = V[i][k]; V[i][k] = t;
+                     }
+                  }
+                  if (wantu && (k < m-1)) {
+                     for (int i = 0; i < m; i++) {
+                        t = U[i][k+1]; U[i][k+1] = U[i][k]; U[i][k] = t;
+                     }
+                  }
+                  k++;
+               }
+               iter = 0;
+               p--;
+            }
+            break;
+         }
+      }
+   }
+
+/* ------------------------
+   Public Methods
+ * ------------------------ */
+
+   /** Return the left singular vectors
+   @return     U
+   */
+
+   public Matrix getU () {
+      return transpose ? new Matrix(V,n,n) : new Matrix(U,m,n);
+   }
+
+   /** Return the right singular vectors
+   @return     V
+   */
+
+   public Matrix getV () {
+      return transpose ? new Matrix(U,m,n) : new Matrix(V,n,n);
+   }
+
+   /** Return the one-dimensional array of singular values
+   @return     diagonal of S.
+   */
+
+   public double[] getSingularValues () {
+      return s;
+   }
+
+   /** Return the diagonal matrix of singular values
+   @return     S
+   */
+
+   public Matrix getS () {
+      Matrix X = new Matrix(n,n);
+      double[][] S = X.getArray();
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            S[i][j] = 0.0;
+         }
+         S[i][i] = this.s[i];
+      }
+      return X;
+   }
+
+   /** Two norm
+   @return     max(S)
+   */
+
+   public double norm2 () {
+      return s[0];
+   }
+
+   /** Two norm condition number
+   @return     max(S)/min(S)
+   */
+
+   public double cond () {
+      return s[0]/s[Math.min(m,n)-1];
+   }
+
+   /** Effective numerical matrix rank
+   @return     Number of nonnegligible singular values.
+   */
+
+   public int rank () {
+      double eps = Math.pow(2.0,-52.0);
+      double tol = Math.max(m,n)*s[0]*eps;
+      int r = 0;
+      for (int i = 0; i < s.length; i++) {
+         if (s[i] > tol) {
+            r++;
+         }
+      }
+      return r;
+   }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SingularValueDecomposition.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SingularValueDecomposition.java0
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SingularValueDecomposition.java0	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SingularValueDecomposition.java0	(revision 3653)
@@ -0,0 +1,547 @@
+package JamaPlus;
+import JamaPlus.util.*;
+
+   /** Singular Value Decomposition.
+   <P>
+   For an m-by-n matrix A with m >= n, the singular value decomposition is
+   an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and
+   an n-by-n orthogonal matrix V so that A = U*S*V'.
+   <P>
+   The singular values, sigma[k] = S[k][k], are ordered so that
+   sigma[0] >= sigma[1] >= ... >= sigma[n-1].
+   <P>
+   The singular value decompostion always exists, so the constructor will
+   never fail.  The matrix condition number and the effective numerical
+   rank can be computed from this decomposition.
+   */
+
+public class SingularValueDecomposition implements java.io.Serializable {
+
+/* ------------------------
+   Class variables
+ * ------------------------ */
+
+   /** Arrays for internal storage of U and V.
+   @serial internal storage of U.
+   @serial internal storage of V.
+   */
+   private double[][] U, V;
+
+   /** Array for internal storage of singular values.
+   @serial internal storage of singular values.
+   */
+   private double[] s;
+
+   /** Row and column dimensions.
+   @serial row dimension.
+   @serial column dimension.
+   */
+   private int m, n;
+
+/* ------------------------
+   Constructor
+ * ------------------------ */
+
+   /** Construct the singular value decomposition
+   @param A    Rectangular matrix
+   @return     Structure to access U, S and V.
+   */
+
+   public SingularValueDecomposition (Matrix Arg) {
+
+      // Derived from LINPACK code.
+      // Initialize.
+      double[][] A = Arg.getArrayCopy();
+      m = Arg.getRowDimension();
+      n = Arg.getColumnDimension();
+
+      /* Apparently the failing cases are only a proper subset of (m<n), 
+	 so let's not throw error.  Correct fix to come later?
+      if (m<n) {
+	  throw new IllegalArgumentException("Jama SVD only works for m >= n"); }
+      */
+      int nu = Math.min(m,n);
+      s = new double [Math.min(m+1,n)];
+      U = new double [m][nu];
+      V = new double [n][n];
+      double[] e = new double [n];
+      double[] work = new double [m];
+      boolean wantu = true;
+      boolean wantv = true;
+
+      // Reduce A to bidiagonal form, storing the diagonal elements
+      // in s and the super-diagonal elements in e.
+
+      int nct = Math.min(m-1,n);
+      int nrt = Math.max(0,Math.min(n-2,m));
+      for (int k = 0; k < Math.max(nct,nrt); k++) {
+         if (k < nct) {
+
+            // Compute the transformation for the k-th column and
+            // place the k-th diagonal in s[k].
+            // Compute 2-norm of k-th column without under/overflow.
+            s[k] = 0;
+            for (int i = k; i < m; i++) {
+               s[k] = Math.hypot(s[k],A[i][k]);
+            }
+            if (s[k] != 0.0) {
+               if (A[k][k] < 0.0) {
+                  s[k] = -s[k];
+               }
+               for (int i = k; i < m; i++) {
+                  A[i][k] /= s[k];
+               }
+               A[k][k] += 1.0;
+            }
+            s[k] = -s[k];
+         }
+         for (int j = k+1; j < n; j++) {
+            if ((k < nct) & (s[k] != 0.0))  {
+
+            // Apply the transformation.
+
+               double t = 0;
+               for (int i = k; i < m; i++) {
+                  t += A[i][k]*A[i][j];
+               }
+               t = -t/A[k][k];
+               for (int i = k; i < m; i++) {
+                  A[i][j] += t*A[i][k];
+               }
+            }
+
+            // Place the k-th row of A into e for the
+            // subsequent calculation of the row transformation.
+
+            e[j] = A[k][j];
+         }
+         if (wantu & (k < nct)) {
+
+            // Place the transformation in U for subsequent back
+            // multiplication.
+
+            for (int i = k; i < m; i++) {
+               U[i][k] = A[i][k];
+            }
+         }
+         if (k < nrt) {
+
+            // Compute the k-th row transformation and place the
+            // k-th super-diagonal in e[k].
+            // Compute 2-norm without under/overflow.
+            e[k] = 0;
+            for (int i = k+1; i < n; i++) {
+               e[k] = Math.hypot(e[k],e[i]);
+            }
+            if (e[k] != 0.0) {
+               if (e[k+1] < 0.0) {
+                  e[k] = -e[k];
+               }
+               for (int i = k+1; i < n; i++) {
+                  e[i] /= e[k];
+               }
+               e[k+1] += 1.0;
+            }
+            e[k] = -e[k];
+            if ((k+1 < m) & (e[k] != 0.0)) {
+
+            // Apply the transformation.
+
+               for (int i = k+1; i < m; i++) {
+                  work[i] = 0.0;
+               }
+               for (int j = k+1; j < n; j++) {
+                  for (int i = k+1; i < m; i++) {
+                     work[i] += e[j]*A[i][j];
+                  }
+               }
+               for (int j = k+1; j < n; j++) {
+                  double t = -e[j]/e[k+1];
+                  for (int i = k+1; i < m; i++) {
+                     A[i][j] += t*work[i];
+                  }
+               }
+            }
+            if (wantv) {
+
+            // Place the transformation in V for subsequent
+            // back multiplication.
+
+               for (int i = k+1; i < n; i++) {
+                  V[i][k] = e[i];
+               }
+            }
+         }
+      }
+
+      // Set up the final bidiagonal matrix or order p.
+
+      int p = Math.min(n,m+1);
+      if (nct < n) {
+         s[nct] = A[nct][nct];
+      }
+      if (m < p) {
+         s[p-1] = 0.0;
+      }
+      if (nrt+1 < p) {
+         e[nrt] = A[nrt][p-1];
+      }
+      e[p-1] = 0.0;
+
+      // If required, generate U.
+
+      if (wantu) {
+         for (int j = nct; j < nu; j++) {
+            for (int i = 0; i < m; i++) {
+               U[i][j] = 0.0;
+            }
+            U[j][j] = 1.0;
+         }
+         for (int k = nct-1; k >= 0; k--) {
+            if (s[k] != 0.0) {
+               for (int j = k+1; j < nu; j++) {
+                  double t = 0;
+                  for (int i = k; i < m; i++) {
+                     t += U[i][k]*U[i][j];
+                  }
+                  t = -t/U[k][k];
+                  for (int i = k; i < m; i++) {
+                     U[i][j] += t*U[i][k];
+                  }
+               }
+               for (int i = k; i < m; i++ ) {
+                  U[i][k] = -U[i][k];
+               }
+               U[k][k] = 1.0 + U[k][k];
+               for (int i = 0; i < k-1; i++) {
+                  U[i][k] = 0.0;
+               }
+            } else {
+               for (int i = 0; i < m; i++) {
+                  U[i][k] = 0.0;
+               }
+               U[k][k] = 1.0;
+            }
+         }
+      }
+
+      // If required, generate V.
+
+      if (wantv) {
+         for (int k = n-1; k >= 0; k--) {
+            if ((k < nrt) & (e[k] != 0.0)) {
+               for (int j = k+1; j < nu; j++) {
+                  double t = 0;
+                  for (int i = k+1; i < n; i++) {
+                     t += V[i][k]*V[i][j];
+                  }
+                  t = -t/V[k+1][k];
+                  for (int i = k+1; i < n; i++) {
+                     V[i][j] += t*V[i][k];
+                  }
+               }
+            }
+            for (int i = 0; i < n; i++) {
+               V[i][k] = 0.0;
+            }
+            V[k][k] = 1.0;
+         }
+      }
+
+      // Main iteration loop for the singular values.
+
+      int pp = p-1;
+      int iter = 0;
+      double eps = Math.pow(2.0,-52.0);
+      double tiny = Math.pow(2.0,-966.0);
+      while (p > 0) {
+         int k,kase;
+
+         // Here is where a test for too many iterations would go.
+
+         // This section of the program inspects for
+         // negligible elements in the s and e arrays.  On
+         // completion the variables kase and k are set as follows.
+
+         // kase = 1     if s(p) and e[k-1] are negligible and k<p
+         // kase = 2     if s(k) is negligible and k<p
+         // kase = 3     if e[k-1] is negligible, k<p, and
+         //              s(k), ..., s(p) are not negligible (qr step).
+         // kase = 4     if e(p-1) is negligible (convergence).
+
+         for (k = p-2; k >= -1; k--) {
+            if (k == -1) {
+               break;
+            }
+            if (Math.abs(e[k]) <=
+                  tiny + eps*(Math.abs(s[k]) + Math.abs(s[k+1]))) {
+               e[k] = 0.0;
+               break;
+            }
+         }
+         if (k == p-2) {
+            kase = 4;
+         } else {
+            int ks;
+            for (ks = p-1; ks >= k; ks--) {
+               if (ks == k) {
+                  break;
+               }
+               double t = (ks != p ? Math.abs(e[ks]) : 0.) + 
+                          (ks != k+1 ? Math.abs(e[ks-1]) : 0.);
+               if (Math.abs(s[ks]) <= tiny + eps*t)  {
+                  s[ks] = 0.0;
+                  break;
+               }
+            }
+            if (ks == k) {
+               kase = 3;
+            } else if (ks == p-1) {
+               kase = 1;
+            } else {
+               kase = 2;
+               k = ks;
+            }
+         }
+         k++;
+
+         // Perform the task indicated by kase.
+
+         switch (kase) {
+
+            // Deflate negligible s(p).
+
+            case 1: {
+               double f = e[p-2];
+               e[p-2] = 0.0;
+               for (int j = p-2; j >= k; j--) {
+                  double t = Math.hypot(s[j],f);
+                  double cs = s[j]/t;
+                  double sn = f/t;
+                  s[j] = t;
+                  if (j != k) {
+                     f = -sn*e[j-1];
+                     e[j-1] = cs*e[j-1];
+                  }
+                  if (wantv) {
+                     for (int i = 0; i < n; i++) {
+                        t = cs*V[i][j] + sn*V[i][p-1];
+                        V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1];
+                        V[i][j] = t;
+                     }
+                  }
+               }
+            }
+            break;
+
+            // Split at negligible s(k).
+
+            case 2: {
+               double f = e[k-1];
+               e[k-1] = 0.0;
+               for (int j = k; j < p; j++) {
+                  double t = Math.hypot(s[j],f);
+                  double cs = s[j]/t;
+                  double sn = f/t;
+                  s[j] = t;
+                  f = -sn*e[j];
+                  e[j] = cs*e[j];
+                  if (wantu) {
+                     for (int i = 0; i < m; i++) {
+                        t = cs*U[i][j] + sn*U[i][k-1];
+                        U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1];
+                        U[i][j] = t;
+                     }
+                  }
+               }
+            }
+            break;
+
+            // Perform one qr step.
+
+            case 3: {
+
+               // Calculate the shift.
+   
+               double scale = Math.max(Math.max(Math.max(Math.max(
+                       Math.abs(s[p-1]),Math.abs(s[p-2])),Math.abs(e[p-2])), 
+                       Math.abs(s[k])),Math.abs(e[k]));
+               double sp = s[p-1]/scale;
+               double spm1 = s[p-2]/scale;
+               double epm1 = e[p-2]/scale;
+               double sk = s[k]/scale;
+               double ek = e[k]/scale;
+               double b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
+               double c = (sp*epm1)*(sp*epm1);
+               double shift = 0.0;
+               if ((b != 0.0) | (c != 0.0)) {
+                  shift = Math.sqrt(b*b + c);
+                  if (b < 0.0) {
+                     shift = -shift;
+                  }
+                  shift = c/(b + shift);
+               }
+               double f = (sk + sp)*(sk - sp) + shift;
+               double g = sk*ek;
+   
+               // Chase zeros.
+   
+               for (int j = k; j < p-1; j++) {
+                  double t = Math.hypot(f,g);
+                  double cs = f/t;
+                  double sn = g/t;
+                  if (j != k) {
+                     e[j-1] = t;
+                  }
+                  f = cs*s[j] + sn*e[j];
+                  e[j] = cs*e[j] - sn*s[j];
+                  g = sn*s[j+1];
+                  s[j+1] = cs*s[j+1];
+                  if (wantv) {
+                     for (int i = 0; i < n; i++) {
+                        t = cs*V[i][j] + sn*V[i][j+1];
+                        V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1];
+                        V[i][j] = t;
+                     }
+                  }
+                  t = Math.hypot(f,g);
+                  cs = f/t;
+                  sn = g/t;
+                  s[j] = t;
+                  f = cs*e[j] + sn*s[j+1];
+                  s[j+1] = -sn*e[j] + cs*s[j+1];
+                  g = sn*e[j+1];
+                  e[j+1] = cs*e[j+1];
+                  if (wantu && (j < m-1)) {
+                     for (int i = 0; i < m; i++) {
+                        t = cs*U[i][j] + sn*U[i][j+1];
+                        U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1];
+                        U[i][j] = t;
+                     }
+                  }
+               }
+               e[p-2] = f;
+               iter = iter + 1;
+            }
+            break;
+
+            // Convergence.
+
+            case 4: {
+
+               // Make the singular values positive.
+   
+               if (s[k] <= 0.0) {
+                  s[k] = (s[k] < 0.0 ? -s[k] : 0.0);
+                  if (wantv) {
+                     for (int i = 0; i <= pp; i++) {
+                        V[i][k] = -V[i][k];
+                     }
+                  }
+               }
+   
+               // Order the singular values.
+   
+               while (k < pp) {
+                  if (s[k] >= s[k+1]) {
+                     break;
+                  }
+                  double t = s[k];
+                  s[k] = s[k+1];
+                  s[k+1] = t;
+                  if (wantv && (k < n-1)) {
+                     for (int i = 0; i < n; i++) {
+                        t = V[i][k+1]; V[i][k+1] = V[i][k]; V[i][k] = t;
+                     }
+                  }
+                  if (wantu && (k < m-1)) {
+                     for (int i = 0; i < m; i++) {
+                        t = U[i][k+1]; U[i][k+1] = U[i][k]; U[i][k] = t;
+                     }
+                  }
+                  k++;
+               }
+               iter = 0;
+               p--;
+            }
+            break;
+         }
+      }
+   }
+
+/* ------------------------
+   Public Methods
+ * ------------------------ */
+
+   /** Return the left singular vectors
+   @return     U
+   */
+
+   public Matrix getU () {
+      return new Matrix(U,m,Math.min(m+1,n));
+   }
+
+   /** Return the right singular vectors
+   @return     V
+   */
+
+   public Matrix getV () {
+      return new Matrix(V,n,n);
+   }
+
+   /** Return the one-dimensional array of singular values
+   @return     diagonal of S.
+   */
+
+   public double[] getSingularValues () {
+      return s;
+   }
+
+   /** Return the diagonal matrix of singular values
+   @return     S
+   */
+
+   public Matrix getS () {
+      Matrix X = new Matrix(n,n);
+      double[][] S = X.getArray();
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            S[i][j] = 0.0;
+         }
+         S[i][i] = this.s[i];
+      }
+      return X;
+   }
+
+   /** Two norm
+   @return     max(S)
+   */
+
+   public double norm2 () {
+      return s[0];
+   }
+
+   /** Two norm condition number
+   @return     max(S)/min(S)
+   */
+
+   public double cond () {
+      return s[0]/s[Math.min(m,n)-1];
+   }
+
+   /** Effective numerical matrix rank
+   @return     Number of nonnegligible singular values.
+   */
+
+   public int rank () {
+      double eps = Math.pow(2.0,-52.0);
+      double tol = Math.max(m,n)*s[0]*eps;
+      int r = 0;
+      for (int i = 0; i < s.length; i++) {
+         if (s[i] > tol) {
+            r++;
+         }
+      }
+      return r;
+   }
+}
Index: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/QRDecomposition.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/QRDecomposition.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/QRDecomposition.java	(revision 3653)
@@ -0,0 +1,218 @@
+package JamaPlus;
+import JamaPlus.util.*;
+
+/** QR Decomposition.
+<P>
+   For an m-by-n matrix A with m >= n, the QR decomposition is an m-by-n
+   orthogonal matrix Q and an n-by-n upper triangular matrix R so that
+   A = Q*R.
+<P>
+   The QR decompostion always exists, even if the matrix does not have
+   full rank, so the constructor will never fail.  The primary use of the
+   QR decomposition is in the least squares solution of nonsquare systems
+   of simultaneous linear equations.  This will fail if isFullRank()
+   returns false.
+*/
+
+public class QRDecomposition implements java.io.Serializable {
+
+/* ------------------------
+   Class variables
+ * ------------------------ */
+
+   /** Array for internal storage of decomposition.
+   @serial internal array storage.
+   */
+   private double[][] QR;
+
+   /** Row and column dimensions.
+   @serial column dimension.
+   @serial row dimension.
+   */
+   private int m, n;
+
+   /** Array for internal storage of diagonal of R.
+   @serial diagonal of R.
+   */
+   private double[] Rdiag;
+
+/* ------------------------
+   Constructor
+ * ------------------------ */
+
+   /** QR Decomposition, computed by Householder reflections.
+   @param A    Rectangular matrix
+   @return     Structure to access R and the Householder vectors and compute Q.
+   */
+
+   public QRDecomposition (Matrix A) {
+      // Initialize.
+      QR = A.getArrayCopy();
+      m = A.getRowDimension();
+      n = A.getColumnDimension();
+      Rdiag = new double[n];
+
+      // Main loop.
+      for (int k = 0; k < n; k++) {
+         // Compute 2-norm of k-th column without under/overflow.
+         double nrm = 0;
+         for (int i = k; i < m; i++) {
+            nrm = Math.hypot(nrm,QR[i][k]);
+         }
+
+         if (nrm != 0.0) {
+            // Form k-th Householder vector.
+            if (QR[k][k] < 0) {
+               nrm = -nrm;
+            }
+            for (int i = k; i < m; i++) {
+               QR[i][k] /= nrm;
+            }
+            QR[k][k] += 1.0;
+
+            // Apply transformation to remaining columns.
+            for (int j = k+1; j < n; j++) {
+               double s = 0.0; 
+               for (int i = k; i < m; i++) {
+                  s += QR[i][k]*QR[i][j];
+               }
+               s = -s/QR[k][k];
+               for (int i = k; i < m; i++) {
+                  QR[i][j] += s*QR[i][k];
+               }
+            }
+         }
+         Rdiag[k] = -nrm;
+      }
+   }
+
+/* ------------------------
+   Public Methods
+ * ------------------------ */
+
+   /** Is the matrix full rank?
+   @return     true if R, and hence A, has full rank.
+   */
+
+   public boolean isFullRank () {
+      for (int j = 0; j < n; j++) {
+         if (Rdiag[j] == 0)
+            return false;
+      }
+      return true;
+   }
+
+   /** Return the Householder vectors
+   @return     Lower trapezoidal matrix whose columns define the reflections
+   */
+
+   public Matrix getH () {
+      Matrix X = new Matrix(m,n);
+      double[][] H = X.getArray();
+      for (int i = 0; i < m; i++) {
+         for (int j = 0; j < n; j++) {
+            if (i >= j) {
+               H[i][j] = QR[i][j];
+            } else {
+               H[i][j] = 0.0;
+            }
+         }
+      }
+      return X;
+   }
+
+   /** Return the upper triangular factor
+   @return     R
+   */
+
+   public Matrix getR () {
+      Matrix X = new Matrix(n,n);
+      double[][] R = X.getArray();
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            if (i < j) {
+               R[i][j] = QR[i][j];
+            } else if (i == j) {
+               R[i][j] = Rdiag[i];
+            } else {
+               R[i][j] = 0.0;
+            }
+         }
+      }
+      return X;
+   }
+
+   /** Generate and return the (economy-sized) orthogonal factor
+   @return     Q
+   */
+
+   public Matrix getQ () {
+      Matrix X = new Matrix(m,n);
+      double[][] Q = X.getArray();
+      for (int k = n-1; k >= 0; k--) {
+         for (int i = 0; i < m; i++) {
+            Q[i][k] = 0.0;
+         }
+         Q[k][k] = 1.0;
+         for (int j = k; j < n; j++) {
+            if (QR[k][k] != 0) {
+               double s = 0.0;
+               for (int i = k; i < m; i++) {
+                  s += QR[i][k]*Q[i][j];
+               }
+               s = -s/QR[k][k];
+               for (int i = k; i < m; i++) {
+                  Q[i][j] += s*QR[i][k];
+               }
+            }
+         }
+      }
+      return X;
+   }
+
+   /** Least squares solution of A*X = B
+   @param B    A Matrix with as many rows as A and any number of columns.
+   @return     X that minimizes the two norm of Q*R*X-B.
+   @exception  IllegalArgumentException  Matrix row dimensions must agree.
+   @exception  RuntimeException  Matrix is rank deficient.
+   */
+
+   public Matrix solve (Matrix B) {
+      if (B.getRowDimension() != m) {
+         throw new IllegalArgumentException("Matrix row dimensions must agree.");
+      }
+      if (!this.isFullRank()) {
+         throw new RuntimeException("Matrix is rank deficient.");
+      }
+      
+      // Copy right hand side
+      int nx = B.getColumnDimension();
+      double[][] X = B.getArrayCopy();
+
+      // Compute Y = transpose(Q)*B
+      for (int k = 0; k < n; k++) {
+         for (int j = 0; j < nx; j++) {
+            double s = 0.0; 
+            for (int i = k; i < m; i++) {
+               s += QR[i][k]*X[i][j];
+            }
+            s = -s/QR[k][k];
+            for (int i = k; i < m; i++) {
+               X[i][j] += s*QR[i][k];
+            }
+         }
+      }
+      // Solve R*X = Y;
+      for (int k = n-1; k >= 0; k--) {
+         for (int j = 0; j < nx; j++) {
+            X[k][j] /= Rdiag[k];
+         }
+         for (int i = 0; i < k; i++) {
+            for (int j = 0; j < nx; j++) {
+               X[i][j] -= X[k][j]*QR[i][k];
+            }
+         }
+      }
+      return (new Matrix(X,n,nx).getMatrix(0,n-1,0,nx-1));
+   }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/QRDecomposition.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/EigenvalueDecomposition.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/EigenvalueDecomposition.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/EigenvalueDecomposition.java	(revision 3653)
@@ -0,0 +1,955 @@
+package JamaPlus;
+import JamaPlus.util.*;
+
+/** Eigenvalues and eigenvectors of a real matrix. 
+<P>
+    If A is symmetric, then A = V*D*V' where the eigenvalue matrix D is
+    diagonal and the eigenvector matrix V is orthogonal.
+    I.e. A = V.times(D.times(V.transpose())) and 
+    V.times(V.transpose()) equals the identity matrix.
+<P>
+    If A is not symmetric, then the eigenvalue matrix D is block diagonal
+    with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,
+    lambda + i*mu, in 2-by-2 blocks, [lambda, mu; -mu, lambda].  The
+    columns of V represent the eigenvectors in the sense that A*V = V*D,
+    i.e. A.times(V) equals V.times(D).  The matrix V may be badly
+    conditioned, or even singular, so the validity of the equation
+    A = V*D*inverse(V) depends upon V.cond().
+**/
+
+public class EigenvalueDecomposition implements java.io.Serializable {
+
+/* ------------------------
+   Class variables
+ * ------------------------ */
+
+   /** Row and column dimension (square matrix).
+   @serial matrix dimension.
+   */
+   private int n;
+
+   /** Symmetry flag.
+   @serial internal symmetry flag.
+   */
+   private boolean issymmetric;
+
+   /** Arrays for internal storage of eigenvalues.
+   @serial internal storage of eigenvalues.
+   */
+   private double[] d, e;
+
+   /** Array for internal storage of eigenvectors.
+   @serial internal storage of eigenvectors.
+   */
+   private double[][] V;
+
+   /** Array for internal storage of nonsymmetric Hessenberg form.
+   @serial internal storage of nonsymmetric Hessenberg form.
+   */
+   private double[][] H;
+
+   /** Working storage for nonsymmetric algorithm.
+   @serial working storage for nonsymmetric algorithm.
+   */
+   private double[] ort;
+
+/* ------------------------
+   Private Methods
+ * ------------------------ */
+
+   // Symmetric Householder reduction to tridiagonal form.
+
+   private void tred2 () {
+
+   //  This is derived from the Algol procedures tred2 by
+   //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
+   //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
+   //  Fortran subroutine in EISPACK.
+
+      for (int j = 0; j < n; j++) {
+         d[j] = V[n-1][j];
+      }
+
+      // Householder reduction to tridiagonal form.
+   
+      for (int i = n-1; i > 0; i--) {
+   
+         // Scale to avoid under/overflow.
+   
+         double scale = 0.0;
+         double h = 0.0;
+         for (int k = 0; k < i; k++) {
+            scale = scale + Math.abs(d[k]);
+         }
+         if (scale == 0.0) {
+            e[i] = d[i-1];
+            for (int j = 0; j < i; j++) {
+               d[j] = V[i-1][j];
+               V[i][j] = 0.0;
+               V[j][i] = 0.0;
+            }
+         } else {
+   
+            // Generate Householder vector.
+   
+            for (int k = 0; k < i; k++) {
+               d[k] /= scale;
+               h += d[k] * d[k];
+            }
+            double f = d[i-1];
+            double g = Math.sqrt(h);
+            if (f > 0) {
+               g = -g;
+            }
+            e[i] = scale * g;
+            h = h - f * g;
+            d[i-1] = f - g;
+            for (int j = 0; j < i; j++) {
+               e[j] = 0.0;
+            }
+   
+            // Apply similarity transformation to remaining columns.
+   
+            for (int j = 0; j < i; j++) {
+               f = d[j];
+               V[j][i] = f;
+               g = e[j] + V[j][j] * f;
+               for (int k = j+1; k <= i-1; k++) {
+                  g += V[k][j] * d[k];
+                  e[k] += V[k][j] * f;
+               }
+               e[j] = g;
+            }
+            f = 0.0;
+            for (int j = 0; j < i; j++) {
+               e[j] /= h;
+               f += e[j] * d[j];
+            }
+            double hh = f / (h + h);
+            for (int j = 0; j < i; j++) {
+               e[j] -= hh * d[j];
+            }
+            for (int j = 0; j < i; j++) {
+               f = d[j];
+               g = e[j];
+               for (int k = j; k <= i-1; k++) {
+                  V[k][j] -= (f * e[k] + g * d[k]);
+               }
+               d[j] = V[i-1][j];
+               V[i][j] = 0.0;
+            }
+         }
+         d[i] = h;
+      }
+   
+      // Accumulate transformations.
+   
+      for (int i = 0; i < n-1; i++) {
+         V[n-1][i] = V[i][i];
+         V[i][i] = 1.0;
+         double h = d[i+1];
+         if (h != 0.0) {
+            for (int k = 0; k <= i; k++) {
+               d[k] = V[k][i+1] / h;
+            }
+            for (int j = 0; j <= i; j++) {
+               double g = 0.0;
+               for (int k = 0; k <= i; k++) {
+                  g += V[k][i+1] * V[k][j];
+               }
+               for (int k = 0; k <= i; k++) {
+                  V[k][j] -= g * d[k];
+               }
+            }
+         }
+         for (int k = 0; k <= i; k++) {
+            V[k][i+1] = 0.0;
+         }
+      }
+      for (int j = 0; j < n; j++) {
+         d[j] = V[n-1][j];
+         V[n-1][j] = 0.0;
+      }
+      V[n-1][n-1] = 1.0;
+      e[0] = 0.0;
+   } 
+
+   // Symmetric tridiagonal QL algorithm.
+   
+   private void tql2 () {
+
+   //  This is derived from the Algol procedures tql2, by
+   //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
+   //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
+   //  Fortran subroutine in EISPACK.
+   
+      for (int i = 1; i < n; i++) {
+         e[i-1] = e[i];
+      }
+      e[n-1] = 0.0;
+   
+      double f = 0.0;
+      double tst1 = 0.0;
+      double eps = Math.pow(2.0,-52.0);
+      for (int l = 0; l < n; l++) {
+
+         // Find small subdiagonal element
+   
+         tst1 = Math.max(tst1,Math.abs(d[l]) + Math.abs(e[l]));
+         int m = l;
+         while (m < n) {
+            if (Math.abs(e[m]) <= eps*tst1) {
+               break;
+            }
+            m++;
+         }
+   
+         // If m == l, d[l] is an eigenvalue,
+         // otherwise, iterate.
+   
+         if (m > l) {
+            int iter = 0;
+            do {
+               iter = iter + 1;  // (Could check iteration count here.)
+   
+               // Compute implicit shift
+   
+               double g = d[l];
+               double p = (d[l+1] - g) / (2.0 * e[l]);
+               double r = Math.hypot(p,1.0);
+               if (p < 0) {
+                  r = -r;
+               }
+               d[l] = e[l] / (p + r);
+               d[l+1] = e[l] * (p + r);
+               double dl1 = d[l+1];
+               double h = g - d[l];
+               for (int i = l+2; i < n; i++) {
+                  d[i] -= h;
+               }
+               f = f + h;
+   
+               // Implicit QL transformation.
+   
+               p = d[m];
+               double c = 1.0;
+               double c2 = c;
+               double c3 = c;
+               double el1 = e[l+1];
+               double s = 0.0;
+               double s2 = 0.0;
+               for (int i = m-1; i >= l; i--) {
+                  c3 = c2;
+                  c2 = c;
+                  s2 = s;
+                  g = c * e[i];
+                  h = c * p;
+                  r = Math.hypot(p,e[i]);
+                  e[i+1] = s * r;
+                  s = e[i] / r;
+                  c = p / r;
+                  p = c * d[i] - s * g;
+                  d[i+1] = h + s * (c * g + s * d[i]);
+   
+                  // Accumulate transformation.
+   
+                  for (int k = 0; k < n; k++) {
+                     h = V[k][i+1];
+                     V[k][i+1] = s * V[k][i] + c * h;
+                     V[k][i] = c * V[k][i] - s * h;
+                  }
+               }
+               p = -s * s2 * c3 * el1 * e[l] / dl1;
+               e[l] = s * p;
+               d[l] = c * p;
+   
+               // Check for convergence.
+   
+            } while (Math.abs(e[l]) > eps*tst1);
+         }
+         d[l] = d[l] + f;
+         e[l] = 0.0;
+      }
+     
+      // Sort eigenvalues and corresponding vectors.
+   
+      for (int i = 0; i < n-1; i++) {
+         int k = i;
+         double p = d[i];
+         for (int j = i+1; j < n; j++) {
+            if (d[j] < p) {
+               k = j;
+               p = d[j];
+            }
+         }
+         if (k != i) {
+            d[k] = d[i];
+            d[i] = p;
+            for (int j = 0; j < n; j++) {
+               p = V[j][i];
+               V[j][i] = V[j][k];
+               V[j][k] = p;
+            }
+         }
+      }
+   }
+
+   // Nonsymmetric reduction to Hessenberg form.
+
+   private void orthes () {
+   
+      //  This is derived from the Algol procedures orthes and ortran,
+      //  by Martin and Wilkinson, Handbook for Auto. Comp.,
+      //  Vol.ii-Linear Algebra, and the corresponding
+      //  Fortran subroutines in EISPACK.
+   
+      int low = 0;
+      int high = n-1;
+   
+      for (int m = low+1; m <= high-1; m++) {
+   
+         // Scale column.
+   
+         double scale = 0.0;
+         for (int i = m; i <= high; i++) {
+            scale = scale + Math.abs(H[i][m-1]);
+         }
+         if (scale != 0.0) {
+   
+            // Compute Householder transformation.
+   
+            double h = 0.0;
+            for (int i = high; i >= m; i--) {
+               ort[i] = H[i][m-1]/scale;
+               h += ort[i] * ort[i];
+            }
+            double g = Math.sqrt(h);
+            if (ort[m] > 0) {
+               g = -g;
+            }
+            h = h - ort[m] * g;
+            ort[m] = ort[m] - g;
+   
+            // Apply Householder similarity transformation
+            // H = (I-u*u'/h)*H*(I-u*u')/h)
+   
+            for (int j = m; j < n; j++) {
+               double f = 0.0;
+               for (int i = high; i >= m; i--) {
+                  f += ort[i]*H[i][j];
+               }
+               f = f/h;
+               for (int i = m; i <= high; i++) {
+                  H[i][j] -= f*ort[i];
+               }
+           }
+   
+           for (int i = 0; i <= high; i++) {
+               double f = 0.0;
+               for (int j = high; j >= m; j--) {
+                  f += ort[j]*H[i][j];
+               }
+               f = f/h;
+               for (int j = m; j <= high; j++) {
+                  H[i][j] -= f*ort[j];
+               }
+            }
+            ort[m] = scale*ort[m];
+            H[m][m-1] = scale*g;
+         }
+      }
+   
+      // Accumulate transformations (Algol's ortran).
+
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            V[i][j] = (i == j ? 1.0 : 0.0);
+         }
+      }
+
+      for (int m = high-1; m >= low+1; m--) {
+         if (H[m][m-1] != 0.0) {
+            for (int i = m+1; i <= high; i++) {
+               ort[i] = H[i][m-1];
+            }
+            for (int j = m; j <= high; j++) {
+               double g = 0.0;
+               for (int i = m; i <= high; i++) {
+                  g += ort[i] * V[i][j];
+               }
+               // Double division avoids possible underflow
+               g = (g / ort[m]) / H[m][m-1];
+               for (int i = m; i <= high; i++) {
+                  V[i][j] += g * ort[i];
+               }
+            }
+         }
+      }
+   }
+
+
+   // Complex scalar division.
+
+   private transient double cdivr, cdivi;
+   private void cdiv(double xr, double xi, double yr, double yi) {
+      double r,d;
+      if (Math.abs(yr) > Math.abs(yi)) {
+         r = yi/yr;
+         d = yr + r*yi;
+         cdivr = (xr + r*xi)/d;
+         cdivi = (xi - r*xr)/d;
+      } else {
+         r = yr/yi;
+         d = yi + r*yr;
+         cdivr = (r*xr + xi)/d;
+         cdivi = (r*xi - xr)/d;
+      }
+   }
+
+
+   // Nonsymmetric reduction from Hessenberg to real Schur form.
+
+   private void hqr2 () {
+   
+      //  This is derived from the Algol procedure hqr2,
+      //  by Martin and Wilkinson, Handbook for Auto. Comp.,
+      //  Vol.ii-Linear Algebra, and the corresponding
+      //  Fortran subroutine in EISPACK.
+   
+      // Initialize
+   
+      int nn = this.n;
+      int n = nn-1;
+      int low = 0;
+      int high = nn-1;
+      double eps = Math.pow(2.0,-52.0);
+      double exshift = 0.0;
+      double p=0,q=0,r=0,s=0,z=0,t,w,x,y;
+   
+      // Store roots isolated by balanc and compute matrix norm
+   
+      double norm = 0.0;
+      for (int i = 0; i < nn; i++) {
+         if (i < low | i > high) {
+            d[i] = H[i][i];
+            e[i] = 0.0;
+         }
+         for (int j = Math.max(i-1,0); j < nn; j++) {
+            norm = norm + Math.abs(H[i][j]);
+         }
+      }
+   
+      // Outer loop over eigenvalue index
+   
+      int iter = 0;
+      while (n >= low) {
+   
+         // Look for single small sub-diagonal element
+   
+         int l = n;
+         while (l > low) {
+            s = Math.abs(H[l-1][l-1]) + Math.abs(H[l][l]);
+            if (s == 0.0) {
+               s = norm;
+            }
+            if (Math.abs(H[l][l-1]) < eps * s) {
+               break;
+            }
+            l--;
+         }
+       
+         // Check for convergence
+         // One root found
+   
+         if (l == n) {
+            H[n][n] = H[n][n] + exshift;
+            d[n] = H[n][n];
+            e[n] = 0.0;
+            n--;
+            iter = 0;
+   
+         // Two roots found
+   
+         } else if (l == n-1) {
+            w = H[n][n-1] * H[n-1][n];
+            p = (H[n-1][n-1] - H[n][n]) / 2.0;
+            q = p * p + w;
+            z = Math.sqrt(Math.abs(q));
+            H[n][n] = H[n][n] + exshift;
+            H[n-1][n-1] = H[n-1][n-1] + exshift;
+            x = H[n][n];
+   
+            // Real pair
+   
+            if (q >= 0) {
+               if (p >= 0) {
+                  z = p + z;
+               } else {
+                  z = p - z;
+               }
+               d[n-1] = x + z;
+               d[n] = d[n-1];
+               if (z != 0.0) {
+                  d[n] = x - w / z;
+               }
+               e[n-1] = 0.0;
+               e[n] = 0.0;
+               x = H[n][n-1];
+               s = Math.abs(x) + Math.abs(z);
+               p = x / s;
+               q = z / s;
+               r = Math.sqrt(p * p+q * q);
+               p = p / r;
+               q = q / r;
+   
+               // Row modification
+   
+               for (int j = n-1; j < nn; j++) {
+                  z = H[n-1][j];
+                  H[n-1][j] = q * z + p * H[n][j];
+                  H[n][j] = q * H[n][j] - p * z;
+               }
+   
+               // Column modification
+   
+               for (int i = 0; i <= n; i++) {
+                  z = H[i][n-1];
+                  H[i][n-1] = q * z + p * H[i][n];
+                  H[i][n] = q * H[i][n] - p * z;
+               }
+   
+               // Accumulate transformations
+   
+               for (int i = low; i <= high; i++) {
+                  z = V[i][n-1];
+                  V[i][n-1] = q * z + p * V[i][n];
+                  V[i][n] = q * V[i][n] - p * z;
+               }
+   
+            // Complex pair
+   
+            } else {
+               d[n-1] = x + p;
+               d[n] = x + p;
+               e[n-1] = z;
+               e[n] = -z;
+            }
+            n = n - 2;
+            iter = 0;
+   
+         // No convergence yet
+   
+         } else {
+   
+            // Form shift
+   
+            x = H[n][n];
+            y = 0.0;
+            w = 0.0;
+            if (l < n) {
+               y = H[n-1][n-1];
+               w = H[n][n-1] * H[n-1][n];
+            }
+   
+            // Wilkinson's original ad hoc shift
+   
+            if (iter == 10) {
+               exshift += x;
+               for (int i = low; i <= n; i++) {
+                  H[i][i] -= x;
+               }
+               s = Math.abs(H[n][n-1]) + Math.abs(H[n-1][n-2]);
+               x = y = 0.75 * s;
+               w = -0.4375 * s * s;
+            }
+
+            // MATLAB's new ad hoc shift
+
+            if (iter == 30) {
+                s = (y - x) / 2.0;
+                s = s * s + w;
+                if (s > 0) {
+                    s = Math.sqrt(s);
+                    if (y < x) {
+                       s = -s;
+                    }
+                    s = x - w / ((y - x) / 2.0 + s);
+                    for (int i = low; i <= n; i++) {
+                       H[i][i] -= s;
+                    }
+                    exshift += s;
+                    x = y = w = 0.964;
+                }
+            }
+   
+            iter = iter + 1;   // (Could check iteration count here.)
+   
+            // Look for two consecutive small sub-diagonal elements
+   
+            int m = n-2;
+            while (m >= l) {
+               z = H[m][m];
+               r = x - z;
+               s = y - z;
+               p = (r * s - w) / H[m+1][m] + H[m][m+1];
+               q = H[m+1][m+1] - z - r - s;
+               r = H[m+2][m+1];
+               s = Math.abs(p) + Math.abs(q) + Math.abs(r);
+               p = p / s;
+               q = q / s;
+               r = r / s;
+               if (m == l) {
+                  break;
+               }
+               if (Math.abs(H[m][m-1]) * (Math.abs(q) + Math.abs(r)) <
+                  eps * (Math.abs(p) * (Math.abs(H[m-1][m-1]) + Math.abs(z) +
+                  Math.abs(H[m+1][m+1])))) {
+                     break;
+               }
+               m--;
+            }
+   
+            for (int i = m+2; i <= n; i++) {
+               H[i][i-2] = 0.0;
+               if (i > m+2) {
+                  H[i][i-3] = 0.0;
+               }
+            }
+   
+            // Double QR step involving rows l:n and columns m:n
+   
+            for (int k = m; k <= n-1; k++) {
+               boolean notlast = (k != n-1);
+               if (k != m) {
+                  p = H[k][k-1];
+                  q = H[k+1][k-1];
+                  r = (notlast ? H[k+2][k-1] : 0.0);
+                  x = Math.abs(p) + Math.abs(q) + Math.abs(r);
+                  if (x != 0.0) {
+                     p = p / x;
+                     q = q / x;
+                     r = r / x;
+                  }
+               }
+               if (x == 0.0) {
+                  break;
+               }
+               s = Math.sqrt(p * p + q * q + r * r);
+               if (p < 0) {
+                  s = -s;
+               }
+               if (s != 0) {
+                  if (k != m) {
+                     H[k][k-1] = -s * x;
+                  } else if (l != m) {
+                     H[k][k-1] = -H[k][k-1];
+                  }
+                  p = p + s;
+                  x = p / s;
+                  y = q / s;
+                  z = r / s;
+                  q = q / p;
+                  r = r / p;
+   
+                  // Row modification
+   
+                  for (int j = k; j < nn; j++) {
+                     p = H[k][j] + q * H[k+1][j];
+                     if (notlast) {
+                        p = p + r * H[k+2][j];
+                        H[k+2][j] = H[k+2][j] - p * z;
+                     }
+                     H[k][j] = H[k][j] - p * x;
+                     H[k+1][j] = H[k+1][j] - p * y;
+                  }
+   
+                  // Column modification
+   
+                  for (int i = 0; i <= Math.min(n,k+3); i++) {
+                     p = x * H[i][k] + y * H[i][k+1];
+                     if (notlast) {
+                        p = p + z * H[i][k+2];
+                        H[i][k+2] = H[i][k+2] - p * r;
+                     }
+                     H[i][k] = H[i][k] - p;
+                     H[i][k+1] = H[i][k+1] - p * q;
+                  }
+   
+                  // Accumulate transformations
+   
+                  for (int i = low; i <= high; i++) {
+                     p = x * V[i][k] + y * V[i][k+1];
+                     if (notlast) {
+                        p = p + z * V[i][k+2];
+                        V[i][k+2] = V[i][k+2] - p * r;
+                     }
+                     V[i][k] = V[i][k] - p;
+                     V[i][k+1] = V[i][k+1] - p * q;
+                  }
+               }  // (s != 0)
+            }  // k loop
+         }  // check convergence
+      }  // while (n >= low)
+      
+      // Backsubstitute to find vectors of upper triangular form
+
+      if (norm == 0.0) {
+         return;
+      }
+   
+      for (n = nn-1; n >= 0; n--) {
+         p = d[n];
+         q = e[n];
+   
+         // Real vector
+   
+         if (q == 0) {
+            int l = n;
+            H[n][n] = 1.0;
+            for (int i = n-1; i >= 0; i--) {
+               w = H[i][i] - p;
+               r = 0.0;
+               for (int j = l; j <= n; j++) {
+                  r = r + H[i][j] * H[j][n];
+               }
+               if (e[i] < 0.0) {
+                  z = w;
+                  s = r;
+               } else {
+                  l = i;
+                  if (e[i] == 0.0) {
+                     if (w != 0.0) {
+                        H[i][n] = -r / w;
+                     } else {
+                        H[i][n] = -r / (eps * norm);
+                     }
+   
+                  // Solve real equations
+   
+                  } else {
+                     x = H[i][i+1];
+                     y = H[i+1][i];
+                     q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
+                     t = (x * s - z * r) / q;
+                     H[i][n] = t;
+                     if (Math.abs(x) > Math.abs(z)) {
+                        H[i+1][n] = (-r - w * t) / x;
+                     } else {
+                        H[i+1][n] = (-s - y * t) / z;
+                     }
+                  }
+   
+                  // Overflow control
+   
+                  t = Math.abs(H[i][n]);
+                  if ((eps * t) * t > 1) {
+                     for (int j = i; j <= n; j++) {
+                        H[j][n] = H[j][n] / t;
+                     }
+                  }
+               }
+            }
+   
+         // Complex vector
+   
+         } else if (q < 0) {
+            int l = n-1;
+
+            // Last vector component imaginary so matrix is triangular
+   
+            if (Math.abs(H[n][n-1]) > Math.abs(H[n-1][n])) {
+               H[n-1][n-1] = q / H[n][n-1];
+               H[n-1][n] = -(H[n][n] - p) / H[n][n-1];
+            } else {
+               cdiv(0.0,-H[n-1][n],H[n-1][n-1]-p,q);
+               H[n-1][n-1] = cdivr;
+               H[n-1][n] = cdivi;
+            }
+            H[n][n-1] = 0.0;
+            H[n][n] = 1.0;
+            for (int i = n-2; i >= 0; i--) {
+               double ra,sa,vr,vi;
+               ra = 0.0;
+               sa = 0.0;
+               for (int j = l; j <= n; j++) {
+                  ra = ra + H[i][j] * H[j][n-1];
+                  sa = sa + H[i][j] * H[j][n];
+               }
+               w = H[i][i] - p;
+   
+               if (e[i] < 0.0) {
+                  z = w;
+                  r = ra;
+                  s = sa;
+               } else {
+                  l = i;
+                  if (e[i] == 0) {
+                     cdiv(-ra,-sa,w,q);
+                     H[i][n-1] = cdivr;
+                     H[i][n] = cdivi;
+                  } else {
+   
+                     // Solve complex equations
+   
+                     x = H[i][i+1];
+                     y = H[i+1][i];
+                     vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
+                     vi = (d[i] - p) * 2.0 * q;
+                     if (vr == 0.0 & vi == 0.0) {
+                        vr = eps * norm * (Math.abs(w) + Math.abs(q) +
+                        Math.abs(x) + Math.abs(y) + Math.abs(z));
+                     }
+                     cdiv(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);
+                     H[i][n-1] = cdivr;
+                     H[i][n] = cdivi;
+                     if (Math.abs(x) > (Math.abs(z) + Math.abs(q))) {
+                        H[i+1][n-1] = (-ra - w * H[i][n-1] + q * H[i][n]) / x;
+                        H[i+1][n] = (-sa - w * H[i][n] - q * H[i][n-1]) / x;
+                     } else {
+                        cdiv(-r-y*H[i][n-1],-s-y*H[i][n],z,q);
+                        H[i+1][n-1] = cdivr;
+                        H[i+1][n] = cdivi;
+                     }
+                  }
+   
+                  // Overflow control
+
+                  t = Math.max(Math.abs(H[i][n-1]),Math.abs(H[i][n]));
+                  if ((eps * t) * t > 1) {
+                     for (int j = i; j <= n; j++) {
+                        H[j][n-1] = H[j][n-1] / t;
+                        H[j][n] = H[j][n] / t;
+                     }
+                  }
+               }
+            }
+         }
+      }
+   
+      // Vectors of isolated roots
+   
+      for (int i = 0; i < nn; i++) {
+         if (i < low | i > high) {
+            for (int j = i; j < nn; j++) {
+               V[i][j] = H[i][j];
+            }
+         }
+      }
+   
+      // Back transformation to get eigenvectors of original matrix
+   
+      for (int j = nn-1; j >= low; j--) {
+         for (int i = low; i <= high; i++) {
+            z = 0.0;
+            for (int k = low; k <= Math.min(j,high); k++) {
+               z = z + V[i][k] * H[k][j];
+            }
+            V[i][j] = z;
+         }
+      }
+   }
+
+
+/* ------------------------
+   Constructor
+ * ------------------------ */
+
+   /** Check for symmetry, then construct the eigenvalue decomposition
+   @param A    Square matrix
+   @return     Structure to access D and V.
+   */
+
+   public EigenvalueDecomposition (Matrix Arg) {
+      double[][] A = Arg.getArray();
+      n = Arg.getColumnDimension();
+      V = new double[n][n];
+      d = new double[n];
+      e = new double[n];
+
+      issymmetric = true;
+      for (int j = 0; (j < n) & issymmetric; j++) {
+         for (int i = 0; (i < n) & issymmetric; i++) {
+            issymmetric = (A[i][j] == A[j][i]);
+         }
+      }
+
+      if (issymmetric) {
+         for (int i = 0; i < n; i++) {
+            for (int j = 0; j < n; j++) {
+               V[i][j] = A[i][j];
+            }
+         }
+   
+         // Tridiagonalize.
+         tred2();
+   
+         // Diagonalize.
+         tql2();
+
+      } else {
+         H = new double[n][n];
+         ort = new double[n];
+         
+         for (int j = 0; j < n; j++) {
+            for (int i = 0; i < n; i++) {
+               H[i][j] = A[i][j];
+            }
+         }
+   
+         // Reduce to Hessenberg form.
+         orthes();
+   
+         // Reduce Hessenberg to real Schur form.
+         hqr2();
+      }
+   }
+
+/* ------------------------
+   Public Methods
+ * ------------------------ */
+
+   /** Return the eigenvector matrix
+   @return     V
+   */
+
+   public Matrix getV () {
+      return new Matrix(V,n,n);
+   }
+
+   /** Return the real parts of the eigenvalues
+   @return     real(diag(D))
+   */
+
+   public double[] getRealEigenvalues () {
+      return d;
+   }
+
+   /** Return the imaginary parts of the eigenvalues
+   @return     imag(diag(D))
+   */
+
+   public double[] getImagEigenvalues () {
+      return e;
+   }
+
+   /** Return the block diagonal eigenvalue matrix
+   @return     D
+   */
+
+   public Matrix getD () {
+      Matrix X = new Matrix(n,n);
+      double[][] D = X.getArray();
+      for (int i = 0; i < n; i++) {
+         for (int j = 0; j < n; j++) {
+            D[i][j] = 0.0;
+         }
+         D[i][i] = d[i];
+         if (e[i] > 0) {
+            D[i][i+1] = e[i];
+         } else if (e[i] < 0) {
+            D[i][i-1] = e[i];
+         }
+      }
+      return X;
+   }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/EigenvalueDecomposition.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SparseMatrix.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SparseMatrix.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SparseMatrix.java	(revision 3653)
@@ -0,0 +1,271 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package JamaPlus;
+
+import JamaPlus.SparseSVD.SparseSVDException;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Bernard
+ */
+public class SparseMatrix {
+  private int m, n, nnz;
+  private int[] colpts, rowinds;
+  private double[] vals;
+  private double[] tempRow;  // stockage temporaire pour certains calculs (opb)
+
+  public SparseMatrix(int m, int n) { // null matrix
+    this.m = m;
+    this.n = n;
+    nnz = 0;
+    colpts = new int[n+1];
+    rowinds = new int[0];
+    vals = new double[0];
+  }
+
+   private static class Triple implements Comparable<Triple> {
+    int row;
+    int col;
+    double val;
+
+    private Triple(int row, int col, double val) {
+      this.row = row;
+      this.col = col;
+      this.val = val;
+    }
+    private Triple(int row, int col) {
+      this.row = row;
+      this.col = col;
+    }
+    public int compareTo(Triple t) {
+      int res = col - t.col;
+      if(res==0) res = row - t.row;
+      return res;
+    }
+  }
+
+ public SparseMatrix(int m, int n, ArrayList<Integer> rows, ArrayList<Integer> cols,
+          ArrayList<Double> values) {
+    this.m = m;
+    this.n = n;
+    nnz = rows.size();
+    if (nnz!=cols.size()||nnz!=rows.size())
+      throw new ArrayIndexOutOfBoundsException(
+              "Size of lines, cols and values don't agree");
+    colpts = new int[n+1];
+    rowinds = new int[nnz];
+    vals = new double[nnz];
+    Triple[] triples = new Triple[nnz];
+    for(int i=0; i<nnz; i++) 
+     triples[i] = new Triple(rows.get(i), cols.get(i), values.get(i));    
+    Arrays.sort(triples);
+    colpts[0] = 0;
+    int c = 0;
+    for(int i=0; i<nnz; i++) {
+      if(i>0 && triples[i].row == triples[i-1].row && triples[i].col == triples[i-1].col) 
+        throw new ArrayIndexOutOfBoundsException(
+              "Two values with same row and column numbers");
+      while(c<triples[i].col) colpts[++c] = i;
+      rowinds[i] = triples[i].row;
+      vals[i] = triples[i].val;
+    }
+    while(c<n) colpts[++c] = nnz;
+  }
+
+public SparseMatrix(int m, int n, ArrayList<Integer> rows, ArrayList<Integer> cols,
+          double value) {
+    this.m = m;
+    this.n = n;
+    nnz = rows.size();
+    if (nnz!=cols.size()||nnz!=rows.size())
+      throw new ArrayIndexOutOfBoundsException(
+              "Size of lines, cols and values don't agree");
+    colpts = new int[n+1];
+    rowinds = new int[nnz];
+        vals = new double[nnz];
+    Triple[] triples = new Triple[nnz];
+    for(int i=0; i<nnz; i++) 
+     triples[i] = new Triple(rows.get(i), cols.get(i));    
+    Arrays.sort(triples);
+    colpts[0] = 0;
+    int c = 0;
+    for(int i=0; i<nnz; i++) {
+      if(i>0 && triples[i].row == triples[i-1].row && triples[i].col == triples[i-1].col) 
+        throw new ArrayIndexOutOfBoundsException(
+              "Two values with same row and column numbers");
+      while(c<triples[i].col) colpts[++c] = i;
+      rowinds[i] = triples[i].row;
+      vals[i] = value;
+    }
+    while(c<n) colpts[++c] = nnz;
+  }
+
+  private SparseMatrix(int m, int n, int nnz, int[] colpts, int[] rowinds, double[] vals) {
+    this.m = m;
+    this.n = n;
+    this.nnz = nnz;
+    this.colpts = colpts;
+    this.rowinds = rowinds;
+    this.vals = vals;
+  }
+
+  public SparseMatrix(Matrix mat) {  // convert a dense matrix
+    m = mat.getRowDimension();
+    n = mat.getColumnDimension();
+    long nbval = mat.getNumberNonZeroValues();
+    if (nbval>Integer.MAX_VALUE) throw new ArrayIndexOutOfBoundsException(
+              "Number of non-zero values exceeds 32 bits integer");
+    nnz = (int) nbval;
+    colpts = new int[n+1];
+    rowinds = new int[nnz];
+    vals = new double[nnz];
+    int nval = 0;
+    for (int j = 0; j<n; j++) {
+      colpts[j] = nval;
+      for (int i = 0; i<m; i++) if (mat.get(i, j)!=0) {
+          rowinds[nval] = i;
+          vals[nval++] = mat.get(i, j);
+        }
+    }
+    colpts[n] = nnz;
+  }
+
+  public SparseMatrix copy() {
+    int[] colpts1 = new int[n+1];
+    int[] rowinds1 = new int[nnz];
+    double[] vals1 = new double[nnz];
+    System.arraycopy(colpts, 0, colpts1, 0, n+1);
+    System.arraycopy(rowinds, 0, rowinds1, 0, nnz);
+    System.arraycopy(vals, 0, vals1, 0, nnz);
+    return new SparseMatrix(m, n, nnz, colpts1, rowinds1, vals1);
+  }
+
+  public int getRowDimension() {
+    return m;
+  }
+
+  public int getColumnDimension() {
+    return n;
+  }
+
+  public double get(int i, int j) {
+    try {
+      for (int nval = colpts[j]; nval<colpts[j+1]; nval++)
+        if (rowinds[nval]==i) return vals[nval];
+      return 0;
+    } catch (ArrayIndexOutOfBoundsException ex) {
+      throw new ArrayIndexOutOfBoundsException("Sparse matrix : "
+              +ex.getLocalizedMessage());
+    }
+  }
+
+  public SparseMatrix transpose() {
+    int[] colpts1 = new int[m+1];
+    int[] rowinds1 = new int[nnz];
+    double[] vals1 = new double[nnz];
+    for (int v = 0; v<nnz; v++) colpts1[rowinds[v]]++;  // nnz in each row
+    colpts1[m] = nnz-colpts1[m-1];
+    for (int r = m-1; r>0; r--)
+      colpts1[r] = colpts1[r+1]-colpts1[r-1]; // starting point of the previous row
+    colpts1[0] = 0;
+    int i = 0;
+    for (int c = 0; c<n; c++) while (i<colpts[c+1]) {
+        int j = colpts1[rowinds[i]+1]++;  // j : index of the value in the new vectors
+        rowinds1[j] = c;
+        vals1[j] = vals[i++];
+      }
+    return new SparseMatrix(n, m, nnz, colpts1, rowinds1, vals1);
+  }
+
+  public void nulColumnSuppression() {
+    ArrayList<Integer> colpts1 = new ArrayList<Integer>();
+    colpts1.add(0);
+    for (int i = 0; i<n; i++) if (colpts[i+1]>colpts[i])
+        colpts1.add(colpts[i+1]);
+    n = colpts1.size()-1;
+    colpts = new int[n+1];
+    for (int i = 0; i<=n; i++) colpts[i] = colpts1.get(i);
+  }
+
+  public double elementSum() {
+    double s = 0;
+    for (int i = 0; i<nnz; i++) s += vals[i];
+
+    return s;
+  }
+
+  public Matrix lineSum() {
+    double[] S = new double[m];
+    for (int i = 0; i<nnz; i++) S[rowinds[i]] += vals[i];
+
+    return new Matrix(S, m);
+  }
+
+  public Matrix columnSum() {
+    double[] S = new double[n];
+    for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++)
+        S[i] += vals[j];
+
+    return new Matrix(S, 1);
+  }
+
+  public SparseMatrix timesEquals(double s) {
+    for (int i = 0; i<nnz; i++) {
+      vals[i] *= s;
+    }
+    return this;
+  }
+
+  public SparseMatrix firstColumnTimesEqual(Matrix B) {
+    double[][] A = B.getArray();
+    for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++)
+        vals[j] *= A[rowinds[j]][0];
+    return this;
+  }
+
+  public SparseMatrix firstLineTimesEqual(Matrix B) {
+    double[][] A = B.getArray();
+    for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++)
+        vals[j] *= A[0][i];
+    return this;
+  }
+
+  public void opa(double x[], double y[]) {
+    // Computes y = Ax (x et y : length n)
+    Arrays.fill(y, 0);
+    for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++)
+        y[rowinds[j]] += vals[j]*x[i];
+  }
+
+  public void opb(double x[], double y[]) {
+    // Computes y = A'Ax (x et y : length n)
+    if (tempRow==null) tempRow = new double[m];
+    else Arrays.fill(tempRow, 0);
+    Arrays.fill(y, 0);
+    for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++)
+        tempRow[rowinds[j]] += vals[j]*x[i];
+    for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++)
+        y[i] += vals[j]*tempRow[rowinds[j]];
+  }
+
+  public SparseSVD svd(int dim) throws SparseSVD.SparseSVDException {
+    return new SparseSVD(this, dim);
+  }
+
+  /** Analyse factorielle de correspondances
+  @return     Analyse factorielle de correspondances
+  @see Analyse factorielle de correspondances
+   */
+  public SparseAFC afc() {
+    try {
+      return new SparseAFC(this);
+    } catch (SparseSVDException ex) {
+      return null;
+    }
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SparseMatrix.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/Matrix.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/Matrix.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/Matrix.java	(revision 3653)
@@ -0,0 +1,1221 @@
+package JamaPlus;
+
+import java.text.NumberFormat;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+import java.io.PrintWriter;
+import java.io.BufferedReader;
+import java.io.StreamTokenizer;
+import JamaPlus.util.*;
+import java.util.ArrayList;
+
+/**
+Jama = Java Matrix class.
+<P>
+The Java Matrix Class provides the fundamental operations of numerical
+linear algebra.  Various constructors create Matrices from two dimensional
+arrays of double precision floating point numbers.  Various "gets" and
+"sets" provide access to submatrices and matrix elements.  Several methods 
+implement basic matrix arithmetic, including matrix addition and
+multiplication, matrix norms, and element-by-element array operations.
+Methods for reading and printing matrices are also included.  All the
+operations in this version of the Matrix Class involve real matrices.
+Complex matrices may be handled in a future version.
+<P>
+Five fundamental matrix decompositions, which consist of pairs or triples
+of matrices, permutation vectors, and the like, produce results in five
+decomposition classes.  These decompositions are accessed by the Matrix
+class to compute solutions of simultaneous linear equations, determinants,
+inverses and other matrix functions.  The five decompositions are:
+<P><UL>
+<LI>Cholesky Decomposition of symmetric, positive definite matrices.
+<LI>LU Decomposition of rectangular matrices.
+<LI>QR Decomposition of rectangular matrices.
+<LI>Singular Value Decomposition of rectangular matrices.
+<LI>Eigenvalue Decomposition of both symmetric and nonsymmetric square matrices.
+</UL>
+<DL>
+<DT><B>Example of use:</B></DT>
+<P>
+<DD>Solve a linear system A x = b and compute the residual norm, ||b - A x||.
+<P><PRE>
+double[][] vals = {{1.,2.,3},{4.,5.,6.},{7.,8.,10.}};
+Matrix A = new Matrix(vals);
+Matrix b = Matrix.random(3,1);
+Matrix x = A.solve(b);
+Matrix r = A.times(x).minus(b);
+double rnorm = r.normInf();
+</PRE></DD>
+</DL>
+
+@author The MathWorks, Inc. and the National Institute of Standards and Technology.
+@version 5 August 1998
+ */
+public class Matrix implements Cloneable, java.io.Serializable {
+
+  /* ------------------------
+  Class variables
+   * ------------------------ */
+  /** Array for internal storage of elements.
+  @serial internal array storage.
+   */
+  private double[][] A;
+  /** Row and column dimensions.
+  @serial row dimension.
+  @serial column dimension.
+   */
+  private int m, n;
+
+  /* ------------------------
+  Constructors
+   * ------------------------ */
+  /** Construct an m-by-n matrix of zeros. 
+  @param m    Number of rows.
+  @param n    Number of colums.
+   */
+  public Matrix(int m, int n) {
+    this.m = m;
+    this.n = n;
+    A = new double[m][n];
+  }
+
+  /** Construct an m-by-n constant matrix.
+  @param m    Number of rows.
+  @param n    Number of colums.
+  @param s    Fill the matrix with this scalar value.
+   */
+  public Matrix(int m, int n, double s) {
+    this.m = m;
+    this.n = n;
+    A = new double[m][n];
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = s;
+      }
+    }
+  }
+
+  /** Construct a matrix from a 2-D array.
+  @param A    Two-dimensional array of doubles.
+  @exception  IllegalArgumentException All rows must have the same length
+  @see        #constructWithCopy
+   */
+  public Matrix(double[][] A) {
+    m = A.length;
+    n = A[0].length;
+    for (int i = 0; i < m; i++) {
+      if (A[i].length != n) {
+        throw new IllegalArgumentException("All rows must have the same length.");
+      }
+    }
+    this.A = A;
+  }
+
+  /** Construct a matrix quickly without checking arguments.
+  @param A    Two-dimensional array of doubles.
+  @param m    Number of rows.
+  @param n    Number of colums.
+   */
+  public Matrix(double[][] A, int m, int n) {
+    this.A = A;
+    this.m = m;
+    this.n = n;
+  }
+
+  /** Construct a matrix from a one-dimensional packed array
+  @param vals One-dimensional array of doubles, packed by columns (ala Fortran).
+  @param m    Number of rows.
+  @exception  IllegalArgumentException Array length must be a multiple of m.
+   */
+  public Matrix(double vals[], int m) {
+    this.m = m;
+    n = (m != 0 ? vals.length / m : 0);
+    if (m * n != vals.length) {
+      throw new IllegalArgumentException("Array length must be a multiple of m.");
+    }
+    A = new double[m][n];
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = vals[i + j * m];
+      }
+    }
+  }
+
+  /* ------------------------
+  Public Methods
+   * ------------------------ */
+  /** Construct a matrix from a copy of a 2-D array.
+  @param A    Two-dimensional array of doubles.
+  @exception  IllegalArgumentException All rows must have the same length
+   */
+  public static Matrix constructWithCopy(double[][] A) {
+    int m = A.length;
+    int n = A[0].length;
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      if (A[i].length != n) {
+        throw new IllegalArgumentException("All rows must have the same length.");
+      }
+      for (int j = 0; j < n; j++) {
+        C[i][j] = A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** Make a deep copy of a matrix
+   */
+  public Matrix copy() {
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      System.arraycopy(A[i], 0, C[i], 0, n);
+    }
+    return X;
+  }
+
+  /** Clone the Matrix object.
+   */
+  public Object clone() {
+    return this.copy();
+  }
+
+  /** Access the internal two-dimensional array.
+  @return     Pointer to the two-dimensional array of matrix elements.
+   */
+  public double[][] getArray() {
+    return A;
+  }
+
+  /** Copy the internal two-dimensional array.
+  @return     Two-dimensional array copy of matrix elements.
+   */
+  public double[][] getArrayCopy() {
+    double[][] C = new double[m][n];
+    for (int i = 0; i < m; i++) {
+      System.arraycopy(A[i], 0, C[i], 0, n);
+    }
+    return C;
+  }
+
+  /** Make a one-dimensional column packed copy of the internal array.
+  @return     Matrix elements packed in a one-dimensional array by columns.
+   */
+  public double[] getColumnPackedCopy() {
+    double[] vals = new double[m * n];
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        vals[i + j * m] = A[i][j];
+      }
+    }
+    return vals;
+  }
+
+  /** Make a one-dimensional row packed copy of the internal array.
+  @return     Matrix elements packed in a one-dimensional array by rows.
+   */
+  public double[] getRowPackedCopy() {
+    double[] vals = new double[m * n];
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        vals[i * n + j] = A[i][j];
+      }
+    }
+    return vals;
+  }
+
+  /** Get row dimension.
+  @return     m, the number of rows.
+   */
+  public int getRowDimension() {
+    return m;
+  }
+
+  /** Get column dimension.
+  @return     n, the number of columns.
+   */
+  public int getColumnDimension() {
+    return n;
+  }
+
+  /** Get a single element.
+  @param i    Row index.
+  @param j    Column index.
+  @return     A(i,j)
+  @exception  ArrayIndexOutOfBoundsException
+   */
+  public double get(int i, int j) {
+    return A[i][j];
+  }
+
+  /** Get a submatrix.
+  @param i0   Initial row index
+  @param i1   Final row index
+  @param j0   Initial column index
+  @param j1   Final column index
+  @return     A(i0:i1,j0:j1)
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public Matrix getMatrix(int i0, int i1, int j0, int j1) {
+    Matrix X = new Matrix(i1 - i0 + 1, j1 - j0 + 1);
+    double[][] B = X.getArray();
+    try {
+      for (int i = i0; i <= i1; i++) {
+        for (int j = j0; j <= j1; j++) {
+          B[i - i0][j - j0] = A[i][j];
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+    return X;
+  }
+
+  /** Get a submatrix.
+  @param r    Array of row indices.
+  @param c    Array of column indices.
+  @return     A(r(:),c(:))
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public Matrix getMatrix(int[] r, int[] c) {
+    Matrix X = new Matrix(r.length, c.length);
+    double[][] B = X.getArray();
+    try {
+      for (int i = 0; i < r.length; i++) {
+        for (int j = 0; j < c.length; j++) {
+          B[i][j] = A[r[i]][c[j]];
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+    return X;
+  }
+
+  /** Get a submatrix.
+  @param i0   Initial row index
+  @param i1   Final row index
+  @param c    Array of column indices.
+  @return     A(i0:i1,c(:))
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public Matrix getMatrix(int i0, int i1, int[] c) {
+    Matrix X = new Matrix(i1 - i0 + 1, c.length);
+    double[][] B = X.getArray();
+    try {
+      for (int i = i0; i <= i1; i++) {
+        for (int j = 0; j < c.length; j++) {
+          B[i - i0][j] = A[i][c[j]];
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+    return X;
+  }
+
+  /** Get a submatrix.
+  @param r    Array of row indices.
+  @param i0   Initial column index
+  @param i1   Final column index
+  @return     A(r(:),j0:j1)
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public Matrix getMatrix(int[] r, int j0, int j1) {
+    Matrix X = new Matrix(r.length, j1 - j0 + 1);
+    double[][] B = X.getArray();
+    try {
+      for (int i = 0; i < r.length; i++) {
+        for (int j = j0; j <= j1; j++) {
+          B[i][j - j0] = A[r[i]][j];
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+    return X;
+  }
+
+  /** Set a single element.
+  @param i    Row index.
+  @param j    Column index.
+  @param s    A(i,j).
+  @exception  ArrayIndexOutOfBoundsException
+   */
+  public void set(int i, int j, double s) {
+    A[i][j] = s;
+  }
+
+  /** Set a submatrix.
+  @param i0   Initial row index
+  @param i1   Final row index
+  @param j0   Initial column index
+  @param j1   Final column index
+  @param X    A(i0:i1,j0:j1)
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public void setMatrix(int i0, int i1, int j0, int j1, Matrix X) {
+    try {
+      for (int i = i0; i <= i1; i++) {
+        for (int j = j0; j <= j1; j++) {
+          A[i][j] = X.get(i - i0, j - j0);
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+  }
+
+  /** Set a submatrix.
+  @param r    Array of row indices.
+  @param c    Array of column indices.
+  @param X    A(r(:),c(:))
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public void setMatrix(int[] r, int[] c, Matrix X) {
+    try {
+      for (int i = 0; i < r.length; i++) {
+        for (int j = 0; j < c.length; j++) {
+          A[r[i]][c[j]] = X.get(i, j);
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+  }
+
+  /** Set a submatrix.
+  @param r    Array of row indices.
+  @param j0   Initial column index
+  @param j1   Final column index
+  @param X    A(r(:),j0:j1)
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public void setMatrix(int[] r, int j0, int j1, Matrix X) {
+    try {
+      for (int i = 0; i < r.length; i++) {
+        for (int j = j0; j <= j1; j++) {
+          A[r[i]][j] = X.get(i, j - j0);
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+  }
+
+  /** Set a submatrix.
+  @param i0   Initial row index
+  @param i1   Final row index
+  @param c    Array of column indices.
+  @param X    A(i0:i1,c(:))
+  @exception  ArrayIndexOutOfBoundsException Submatrix indices
+   */
+  public void setMatrix(int i0, int i1, int[] c, Matrix X) {
+    try {
+      for (int i = i0; i <= i1; i++) {
+        for (int j = 0; j < c.length; j++) {
+          A[i][c[j]] = X.get(i - i0, j);
+        }
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
+    }
+  }
+
+  /** Matrix transpose.
+  @return    A'
+   */
+  public Matrix transpose() {
+    Matrix X = new Matrix(n, m);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[j][i] = A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** One norm
+  @return    maximum column sum.
+   */
+  public double norm1() {
+    double f = 0;
+    for (int j = 0; j < n; j++) {
+      double s = 0;
+      for (int i = 0; i < m; i++) {
+        s += Math.abs(A[i][j]);
+      }
+      f = Math.max(f, s);
+    }
+    return f;
+  }
+
+  /** Two norm
+  @return    maximum singular value.
+   */
+  public double norm2() {
+    return (new SingularValueDecomposition(this).norm2());
+  }
+
+  /** Infinity norm
+  @return    maximum row sum.
+   */
+  public double normInf() {
+    double f = 0;
+    for (int i = 0; i < m; i++) {
+      double s = 0;
+      for (int j = 0; j < n; j++) {
+        s += Math.abs(A[i][j]);
+      }
+      f = Math.max(f, s);
+    }
+    return f;
+  }
+
+  /** Frobenius norm
+  @return    sqrt of sum of squares of all elements.
+   */
+  public double normF() {
+    double f = 0;
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        f = Math.hypot(f, A[i][j]);
+      }
+    }
+    return f;
+  }
+
+  /**  Unary minus
+  @return    -A
+   */
+  public Matrix uminus() {
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = -A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** C = A + B
+  @param B    another matrix
+  @return     A + B
+   */
+  public Matrix plus(Matrix B) {
+    checkMatrixDimensions(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = A[i][j] + B.A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** A = A + B
+  @param B    another matrix
+  @return     A + B
+   */
+  public Matrix plusEquals(Matrix B) {
+    checkMatrixDimensions(B);
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = A[i][j] + B.A[i][j];
+      }
+    }
+    return this;
+  }
+
+  /** C = A - B
+  @param B    another matrix
+  @return     A - B
+   */
+  public Matrix minus(Matrix B) {
+    checkMatrixDimensions(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = A[i][j] - B.A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** A = A - B
+  @param B    another matrix
+  @return     A - B
+   */
+  public Matrix minusEquals(Matrix B) {
+    checkMatrixDimensions(B);
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = A[i][j] - B.A[i][j];
+      }
+    }
+    return this;
+  }
+
+  /** Element-by-element multiplication, C = A.*B
+  @param B    another matrix
+  @return     A.*B
+   */
+  public Matrix arrayTimes(Matrix B) {
+    checkMatrixDimensions(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = A[i][j] * B.A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** Element-by-element multiplication in place, A = A.*B
+  @param B    another matrix
+  @return     A.*B
+   */
+  public Matrix arrayTimesEquals(Matrix B) {
+    checkMatrixDimensions(B);
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = A[i][j] * B.A[i][j];
+      }
+    }
+    return this;
+  }
+
+  /** Element-by-element right division, C = A./B
+  @param B    another matrix
+  @return     A./B
+   */
+  public Matrix arrayRightDivide(Matrix B) {
+    checkMatrixDimensions(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = A[i][j] / B.A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** Element-by-element right division in place, A = A./B
+  @param B    another matrix
+  @return     A./B
+   */
+  public Matrix arrayRightDivideEquals(Matrix B) {
+    checkMatrixDimensions(B);
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = A[i][j] / B.A[i][j];
+      }
+    }
+    return this;
+  }
+
+  /** Element-by-element left division, C = A.\B
+  @param B    another matrix
+  @return     A.\B
+   */
+  public Matrix arrayLeftDivide(Matrix B) {
+    checkMatrixDimensions(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = B.A[i][j] / A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** Element-by-element left division in place, A = A.\B
+  @param B    another matrix
+  @return     A.\B
+   */
+  public Matrix arrayLeftDivideEquals(Matrix B) {
+    checkMatrixDimensions(B);
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = B.A[i][j] / A[i][j];
+      }
+    }
+    return this;
+  }
+
+  /** Multiply a matrix by a scalar, C = s*A
+  @param s    scalar
+  @return     s*A
+   */
+  public Matrix times(double s) {
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = s * A[i][j];
+      }
+    }
+    return X;
+  }
+
+  /** Multiply a matrix by a scalar in place, A = s*A
+  @param s    scalar
+  @return     replace A by s*A
+   */
+  public Matrix timesEquals(double s) {
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] = s * A[i][j];
+      }
+    }
+    return this;
+  }
+
+  /** Linear algebraic matrix multiplication, A * B
+  @param B    another matrix
+  @return     Matrix product, A * B
+  @exception  IllegalArgumentException Matrix inner dimensions must agree.
+   */
+  public Matrix times(Matrix B) {
+    if (B.m != n) {
+      throw new IllegalArgumentException("Matrix inner dimensions must agree.");
+    }
+    Matrix X = new Matrix(m, B.n);
+    double[][] C = X.getArray();
+    double[] Bcolj = new double[n];
+    for (int j = 0; j < B.n; j++) {
+      for (int k = 0; k < n; k++) {
+        Bcolj[k] = B.A[k][j];
+      }
+      for (int i = 0; i < m; i++) {
+        double[] Arowi = A[i];
+        double s = 0;
+        for (int k = 0; k < n; k++) {
+          s += Arowi[k] * Bcolj[k];
+        }
+        C[i][j] = s;
+      }
+    }
+    return X;
+  }
+
+  /** LU Decomposition
+  @return     LUDecomposition
+  @see LUDecomposition
+   */
+  public LUDecomposition lu() {
+    return new LUDecomposition(this);
+  }
+
+  /** QR Decomposition
+  @return     QRDecomposition
+  @see QRDecomposition
+   */
+  public QRDecomposition qr() {
+    return new QRDecomposition(this);
+  }
+
+  /** Cholesky Decomposition
+  @return     CholeskyDecomposition
+  @see CholeskyDecomposition
+   */
+  public CholeskyDecomposition chol() {
+    return new CholeskyDecomposition(this);
+  }
+
+  /** Singular Value Decomposition
+  @return     SingularValueDecomposition
+  @see SingularValueDecomposition
+   */
+  public SingularValueDecomposition svd() {
+    return new SingularValueDecomposition(this);
+  }
+
+  /** Eigenvalue Decomposition
+  @return     EigenvalueDecomposition
+  @see EigenvalueDecomposition
+   */
+  public EigenvalueDecomposition eig() {
+    return new EigenvalueDecomposition(this);
+  }
+
+  /** Solve A*X = B
+  @param B    right hand side
+  @return     solution if A is square, least squares solution otherwise
+   */
+  public Matrix solve(Matrix B) {
+    return (m == n ? (new LUDecomposition(this)).solve(B) : (new QRDecomposition(this)).solve(B));
+  }
+
+  /** Solve X*A = B, which is also A'*X' = B'
+  @param B    right hand side
+  @return     solution if A is square, least squares solution otherwise.
+   */
+  public Matrix solveTranspose(Matrix B) {
+    return transpose().solve(B.transpose());
+  }
+
+  /** Matrix inverse or pseudoinverse
+  @return     inverse(A) if A is square, pseudoinverse otherwise.
+   */
+  public Matrix inverse() {
+    return solve(identity(m, m));
+  }
+
+  /** Matrix determinant
+  @return     determinant
+   */
+  public double det() {
+    return new LUDecomposition(this).det();
+  }
+
+  /** Matrix rank
+  @return     effective numerical rank, obtained from SVD.
+   */
+  public int rank() {
+    return new SingularValueDecomposition(this).rank();
+  }
+
+  /** Matrix condition (2 norm)
+  @return     ratio of largest to smallest singular value.
+   */
+  public double cond() {
+    return new SingularValueDecomposition(this).cond();
+  }
+
+  /** Matrix trace.
+  @return     sum of the diagonal elements.
+   */
+  public double trace() {
+    double t = 0;
+    for (int i = 0; i < Math.min(m, n); i++) {
+      t += A[i][i];
+    }
+    return t;
+  }
+
+  /** Generate matrix with random elements
+  @param m    Number of rows.
+  @param n    Number of colums.
+  @return     An m-by-n matrix with uniformly distributed random elements.
+   */
+  public static Matrix random(int m, int n) {
+    Matrix A = new Matrix(m, n);
+    double[][] X = A.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        X[i][j] = Math.random();
+      }
+    }
+    return A;
+  }
+
+  /** Generate identity matrix
+  @param m    Number of rows.
+  @param n    Number of colums.
+  @return     An m-by-n matrix with ones on the diagonal and zeros elsewhere.
+   */
+  public static Matrix identity(int m, int n) {
+    Matrix A = new Matrix(m, n);
+    double[][] X = A.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        X[i][j] = (i == j ? 1.0 : 0.0);
+      }
+    }
+    return A;
+  }
+
+  /** Print the matrix to stdout.   Line the elements up in columns
+   * with a Fortran-like 'Fw.d' style format.
+  @param w    Column width.
+  @param d    Number of digits after the decimal.
+   */
+  public void print(int w, int d) {
+    print(new PrintWriter(System.out, true), w, d);
+  }
+
+  /** Print the matrix to the output stream.   Line the elements up in
+   * columns with a Fortran-like 'Fw.d' style format.
+  @param output Output stream.
+  @param w      Column width.
+  @param d      Number of digits after the decimal.
+   */
+  public void print(PrintWriter output, int w, int d) {
+    DecimalFormat format = new DecimalFormat();
+    format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
+    format.setMinimumIntegerDigits(1);
+    format.setMaximumFractionDigits(d);
+    format.setMinimumFractionDigits(d);
+    format.setGroupingUsed(false);
+    print(output, format, w + 2);
+  }
+
+  /** Print the matrix to stdout.  Line the elements up in columns.
+   * Use the format object, and right justify within columns of width
+   * characters.
+   * Note that is the matrix is to be read back in, you probably will want
+   * to use a NumberFormat that is set to US Locale.
+  @param format A  Formatting object for individual elements.
+  @param width     Field width for each column.
+  @see java.text.DecimalFormat#setDecimalFormatSymbols
+   */
+  public void print(NumberFormat format, int width) {
+    print(new PrintWriter(System.out, true), format, width);
+  }
+
+  // DecimalFormat is a little disappointing coming from Fortran or C's printf.
+  // Since it doesn't pad on the left, the elements will come out different
+  // widths.  Consequently, we'll pass the desired column width in as an
+  // argument and do the extra padding ourselves.
+  /** Print the matrix to the output stream.  Line the elements up in columns.
+   * Use the format object, and right justify within columns of width
+   * characters.
+   * Note that is the matrix is to be read back in, you probably will want
+   * to use a NumberFormat that is set to US Locale.
+  @param output the output stream.
+  @param format A formatting object to format the matrix elements 
+  @param width  Column width.
+  @see java.text.DecimalFormat#setDecimalFormatSymbols
+   */
+  public void print(PrintWriter output, NumberFormat format, int width) {
+    output.println();  // start on new line.
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        String s = format.format(A[i][j]); // format the number
+        int padding = Math.max(1, width - s.length()); // At _least_ 1 space
+        for (int k = 0; k < padding; k++) {
+          output.print(' ');
+        }
+        output.print(s);
+      }
+      output.println();
+    }
+    output.println();   // end with blank line.
+  }
+
+  /** Read a matrix from a stream.  The format is the same the print method,
+   * so printed matrices can be read back in (provided they were printed using
+   * US Locale).  Elements are separated by
+   * whitespace, all the elements for each row appear on a single line,
+   * the last row is followed by a blank line.
+  @param input the input stream.
+   */
+  @SuppressWarnings("unchecked")
+  public static Matrix read(BufferedReader input) throws java.io.IOException {
+    StreamTokenizer tokenizer = new StreamTokenizer(input);
+
+    // Although StreamTokenizer will parse numbers, it doesn't recognize
+    // scientific notation (E or D); however, Double.valueOf does.
+    // The strategy here is to disable StreamTokenizer's number parsing.
+    // We'll only get whitespace delimited words, EOL's and EOF's.
+    // These words should all be numbers, for Double.valueOf to parse.
+
+    tokenizer.resetSyntax();
+    tokenizer.wordChars(0, 255);
+    tokenizer.whitespaceChars(0, ' ');
+    tokenizer.eolIsSignificant(true);
+    java.util.Vector v = new java.util.Vector();
+
+    // Ignore initial empty lines
+    while (tokenizer.nextToken() == StreamTokenizer.TT_EOL);
+    if (tokenizer.ttype == StreamTokenizer.TT_EOF) {
+      throw new java.io.IOException("Unexpected EOF on matrix read.");
+    }
+    do {
+      v.addElement(Double.valueOf(tokenizer.sval)); // Read & store 1st row.
+    } while (tokenizer.nextToken() == StreamTokenizer.TT_WORD);
+
+    int n = v.size();  // Now we've got the number of columns!
+    double row[] = new double[n];
+    for (int j = 0; j < n; j++) // extract the elements of the 1st row.
+    {
+      row[j] = ((Double) v.elementAt(j)).doubleValue();
+    }
+    v.removeAllElements();
+    v.addElement(row);  // Start storing rows instead of columns.
+    while (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
+      // While non-empty lines
+      v.addElement(row = new double[n]);
+      int j = 0;
+      do {
+        if (j >= n) {
+          throw new java.io.IOException("Row " + v.size() + " is too long.");
+        }
+        row[j++] = Double.valueOf(tokenizer.sval).doubleValue();
+      } while (tokenizer.nextToken() == StreamTokenizer.TT_WORD);
+      if (j < n) {
+        throw new java.io.IOException("Row " + v.size() + " is too short.");
+      }
+    }
+    int m = v.size();  // Now we've got the number of rows.
+    double[][] A = new double[m][];
+    v.copyInto(A);  // copy the rows out of the vector
+    return new Matrix(A);
+  }
+
+
+  /* ------------------------
+  Private Methods
+   * ------------------------ */
+  /** Check if size(A) == size(B) **/
+  private void checkMatrixDimensions(Matrix B) {
+    if (B.m != m || B.n != n) {
+      throw new IllegalArgumentException("Matrix dimensions must agree.");
+    }
+  }
+
+  /* ---------------------------------
+  Quelques méthodes supplémentaires
+   * ---------------------------------*/
+  private void checkLineDimension(Matrix B) {
+    if (B.m != m) {
+      throw new IllegalArgumentException("Matrix line dimension must agree.");
+    }
+  }
+
+  private void checkColumnDimension(Matrix B) {
+    if (B.n != n) {
+      throw new IllegalArgumentException("Matrix column dimension must agree.");
+    }
+  }
+
+  public long getNumberNonZeroValues() {
+    long nnz = 0;
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        if (A[i][j] != 0) nnz++;
+      }
+    }
+    return nnz;
+  }
+
+  public double minColumn(int j) {
+    double min = Double.POSITIVE_INFINITY;
+    for (int i = 0; i < m; i++) {
+      min = Math.min(min, A[i][j]);
+    }
+    return min;
+  }
+
+  public double maxColumn(int j) {
+    double max = Double.NEGATIVE_INFINITY;
+    for (int i = 0; i < m; i++) {
+      max = Math.max(max, A[i][j]);
+    }
+    return max;
+  }
+
+  public double elementSum() {
+    double s = 0;
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        s += A[i][j];
+      }
+    }
+    return s;
+  }
+
+  public Matrix lineSum() {
+    Matrix S = new Matrix(m, 1);
+    double s[][] = S.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        s[i][0] += A[i][j];
+      }
+    }
+    return S;
+  }
+
+  public Matrix lineMean() {
+    Matrix S = new Matrix(m, 1);
+    double s[][] = S.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        s[i][0] += A[i][j];
+      }
+      s[i][0] /= n;
+    }
+    return S;
+  }
+
+  public Matrix columnSum() {
+    Matrix S = new Matrix(1, n);
+    double s[][] = S.getArray();
+    for (int j = 0; j < n; j++) {
+      for (int i = 0; i < m; i++) {
+        s[0][j] += A[i][j];
+      }
+    }
+    return S;
+  }
+
+  public Matrix columnMean() {
+    Matrix S = new Matrix(1, n);
+    double s[][] = S.getArray();
+    for (int j = 0; j < n; j++) {
+      for (int i = 0; i < m; i++) {
+        s[0][j] += A[i][j];
+      }
+      s[0][j] /= m;
+    }
+    return S;
+  }
+
+  public Matrix columnCovariance() {
+    double mean[] = new double[n];
+    for (int j = 0; j < n; j++) {
+      for (int i = 0; i < m; i++) {
+        mean[j] += A[i][j];
+      }
+      mean[j] /= m;
+    }
+    Matrix X = new Matrix(n, n);
+    double[][] B = X.getArray();
+    double[] Acolj = new double[m];
+    int coef = m > 2 ? m-1 : 1;
+    for (int j = 0; j < n; j++) {
+      for (int k = 0; k < m; k++) {
+        Acolj[k] = A[k][j] - mean[j];
+      }
+      for (int i = 0; i < n; i++) {
+        double[] Atrowi = new double[m];
+        for (int k = 0; k < m; k++) {
+          Atrowi[k] = A[k][i] - mean[i];
+        }
+        double s = 0;
+        for (int k = 0; k < m; k++) {
+          s += Atrowi[k] * Acolj[k];
+        }
+        B[i][j] = s / coef;
+      }
+    }
+    return X;
+  }
+
+public Matrix firstLineMinus(Matrix B) {
+     checkColumnDimension(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = A[i][j] - B.A[0][j];
+      }
+    }
+    return X;
+ 
+}
+  public Matrix nulColumnSuppression() {
+    ArrayList<Integer> cols = new ArrayList<Integer>();
+    for (int j = 0; j < n; j++) {
+      for (int i = 0; i < m; i++) {
+        if (A[i][j] != 0) {
+          cols.add(j);
+          break;
+        }
+      }
+    }
+    int[] c = new int[cols.size()];
+    for (int i = 0; i < c.length; i++) {
+      c[i] = cols.get(i);
+    }
+    return getMatrix(0, m - 1, c);
+  }
+
+  public Matrix arrayInverse() {
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = 1 / A[i][j];
+      }
+    }
+    return X;
+  }
+
+  public Matrix arraySqrt() {
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = Math.sqrt(A[i][j]);
+      }
+    }
+    return X;
+  }
+
+  public Matrix firstColumTimes(Matrix B) {
+    checkLineDimension(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+
+        C[i][j] = A[i][j] * B.A[i][0];
+      }
+    }
+    return X;
+  }
+
+  public Matrix firstColumnTimesEqual(Matrix B) {
+    checkLineDimension(B);
+    for (int i = 0; i < m; i++) {
+       for (int j = 0; j < n; j++) {
+
+        A[i][j] *= B.A[i][0];
+      }
+    }
+    return this;
+  }
+
+  public Matrix firstLineTimesEqual(Matrix B) {
+    checkColumnDimension(B);
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        A[i][j] *= B.A[0][j];
+      }
+    }
+    return this;
+  }
+
+  public Matrix firstLineTimes(Matrix B) {
+    checkColumnDimension(B);
+    Matrix X = new Matrix(m, n);
+    double[][] C = X.getArray();
+    for (int i = 0; i < m; i++) {
+      for (int j = 0; j < n; j++) {
+        C[i][j] = A[i][j] * B.A[0][j];
+      }
+    }
+    return X;
+  }
+
+  public void fixColumnSigns() {
+    for (int j = 0; j < n; j++) {
+      int i = 0;
+      while (i<m && A[i][j] == 0) i++;
+      if (i==m || A[i][j] > 0)  continue;
+      while (i < m) {
+        A[i][j] = -A[i][j];
+        i++;
+      }
+    }
+  }
+
+  /** Analyse factorielle de correspondances
+  @return     Analyse factorielle de correspondances
+  @see Analyse factorielle de correspondances
+   */
+  public AFC afc() {
+    return new AFC(this);
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/Matrix.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SparseAFC.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SparseAFC.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SparseAFC.java	(revision 3653)
@@ -0,0 +1,82 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package JamaPlus;
+
+import JamaPlus.SparseSVD.SparseSVDException;
+
+/**
+ /**
+ *
+ * SparseAFC analyse factorielle des correspondances (matrices creuses)
+ * mat :  matrice binaire (0. ou 1.) profil des lignes (un individu par ligne, un caractère par colonne)
+ * CP: composantes principales,
+ * VP: valeurs d'inertie, 
+ * CG: centres de gravité des CP contenant un même caractère (non calculé dans cette version)
+ * [p,q] = size(mat); p:nb de lignes, q:nb de col
+ * 
+ * @author Bernard
+ */
+public class SparseAFC {
+  private double[][] CP;
+  private double[] VP;
+  private int p, q, n;
+
+  SparseAFC(SparseMatrix Arg) throws SparseSVDException {
+    SparseMatrix mat = Arg.copy();
+    mat.nulColumnSuppression();
+    p = mat.getRowDimension();
+    q = mat.getColumnDimension();
+    n = Math.min(Math.min(p, q), 5); 
+    // n : nombre de composantes principales espérées (pas plus de 5)
+    if (n == 0) return;
+    if (n == 1) {
+      CP = new double[p][1];
+      VP = new double[1];
+      return;
+    }
+    double f = mat.elementSum();
+    if (f == 0) return;
+    mat = mat.timesEquals(1 / f);
+    Matrix r = mat.lineSum();
+    Matrix r1 = r.arrayInverse();
+    Matrix r2 = r.arraySqrt();
+    Matrix r3 = r2.arrayInverse();
+    Matrix c = mat.columnSum();
+    Matrix c1 = c.arrayInverse();
+    Matrix c2 = c.arraySqrt();
+    Matrix c3 = c2.arrayInverse();
+    mat = mat.firstColumnTimesEqual(r3);
+    mat = mat.firstLineTimesEqual(c3);
+    SparseSVD svd = mat.svd(n);
+    Matrix cp = svd.getU();
+    Matrix vp = new Matrix(svd.getSingularValues(), 1);
+    n = vp.getColumnDimension();   
+    // peut-être moins de composantes principales effectivement calculées
+     if (n == 0) return;
+    if (n == 1) {
+      CP = new double[p][1];
+      VP = new double[1];
+      return;
+    }
+    cp = cp.getMatrix(0, p - 1, 1, n - 1);
+    cp = cp.firstColumnTimesEqual(r2);
+    vp = vp.getMatrix(0, 0, 1, n - 1);
+    cp = cp.firstLineTimesEqual(vp);
+    cp.fixColumnSigns();
+    cp = cp.firstColumnTimesEqual(r1);
+    CP = cp.getArray();
+    VP = vp.getColumnPackedCopy();
+  }
+
+  public Matrix getCP() {
+    if (CP == null) return null;
+    return new Matrix(CP, p, n - 1);
+  }
+
+  public double[] getVP() {
+    return VP;
+  }
+}
+

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SparseAFC.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/AFC.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/AFC.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/AFC.java	(revision 3653)
@@ -0,0 +1,70 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package JamaPlus;
+
+/**
+ *
+ * AFC analyse factorielle des correspondances (optimisé mémoire)
+ * mat :  matrice binaire (0. ou 1.) profil des lignes (un individu par ligne, un caractère par colonne)
+ * CP: composantes principales,
+ * VP: valeurs d'inertie, 
+ * CG: centres de gravité des CP contenant un même caractère (non calculé dans cette version)
+ * [p,q] = size(mat); p:nb de lignes, q:nb de col
+ * 
+ * @author Bernard
+ */
+public class AFC {
+
+  private double[][] CP;
+  private double[] VP;
+  private int p, q, n;
+
+  AFC(Matrix Arg) {
+    Matrix mat = Arg.copy();
+    mat = mat.nulColumnSuppression();
+    p = mat.getRowDimension();
+    q = mat.getColumnDimension();
+    n = Math.min(Math.min(p, q), 5); // n : nombre de composantes principales calculées
+    if (n == 0) return;
+    if (n == 1) {
+      CP = new double[p][1];
+      VP = new double[1];
+      return;
+    }
+    double f = mat.elementSum();
+    if (f == 0) return;
+    mat = mat.timesEquals(1 / f);
+    Matrix r = mat.lineSum();
+    Matrix r1 = r.arrayInverse();
+    Matrix r2 = r.arraySqrt();
+    Matrix r3 = r2.arrayInverse();
+    Matrix c = mat.columnSum();
+    Matrix c1 = c.arrayInverse();
+    Matrix c2 = c.arraySqrt();
+    Matrix c3 = c2.arrayInverse();
+    mat = mat.firstColumnTimesEqual(r3);
+    mat = mat.firstLineTimesEqual(c3);
+    SingularValueDecomposition svd = mat.svd();
+    Matrix cp = svd.getU();
+    Matrix vp = new Matrix(svd.getSingularValues(), 1);
+    cp = cp.getMatrix(0, p - 1, 1, n - 1);
+    cp = cp.firstColumnTimesEqual(r2);
+    vp = vp.getMatrix(0, 0, 1, n - 1);
+    cp = cp.firstLineTimesEqual(vp);
+    cp.fixColumnSigns();
+    cp = cp.firstColumnTimesEqual(r1);
+    CP = cp.getArray();
+    VP = vp.getColumnPackedCopy();
+  }
+
+  public Matrix getCP() {
+    if (CP == null) return null;
+    return new Matrix(CP, p, n - 1);
+  }
+
+  public double[] getVP() {
+    return VP;
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/AFC.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SparseSVD.java
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SparseSVD.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SparseSVD.java	(revision 3653)
@@ -0,0 +1,920 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package JamaPlus;
+
+import JamaPlus.util.*;
+import java.util.*;
+
+/**
+ *
+ * @author Bernard
+ */
+public class SparseSVD {  // based on code adapted from SVDLIBC - svdLAS2 (adapted from SVDPACKC)
+  private boolean transpose; // si transposition de la matrice en entrée
+  private int rows, cols, dim; // nb rows, nb cols, nb de val sing. désirées
+  // (après transposition éventuelle)
+  private double[][] Ut; // (d x m) transpose of left singular vectors (rows of Ut)
+  private double[][] Vt; // (d x n) transpose of right singular vectors (rows of Vt)
+  private double[] S; // d singular values
+  /* Constantes */
+  private final static int MAXLL = 2; // ??
+  private final static double[] END = {-1e-30, 1e-30};
+  private final static double EPS = Machine.eps(); // precision de la machine
+  private final static double RAD_EPS = Math.sqrt(EPS);
+  private final static double RAD34_EPS = RAD_EPS*Math.sqrt(RAD_EPS);
+  private final static double KAPPA = Math.max(RAD34_EPS, 1e-6);
+  private double EPS1;  // = precision * sqrt(nbcols)
+  /* Variables de travail : mémoire à libérer en fin de calcul */
+  private double[] alph;  // diagonale de la matrice tridiagonale T
+  private double[] bet; // éléments hors-diagonale de T
+  private double[] ritz; // valeurs propres de la  projection de A'A sur l'espace de Krylov
+  private double[] bnd; // a vérifier : initialisation (127) nécessaire ?? 
+  private double[] rj ;
+  private  double[] qj;
+  private  double[] qj1;
+  private  double[] pj ;
+  private  double[] pj1;
+  private  double[] wk;
+   private   double[] eta; 
+  private  double[] oldeta; 
+
+
+//    private static int irandom = 0;  // deboguage : à supprimer
+
+  private static class Storage {  // store Lanczos vectors q(j) 
+    private double[][] P, Q;  // P supplementary storage for j < MAXLL (j= 0 or 1)
+
+    private Storage(int nb, int maxll) {
+      P = new double[maxll][];
+      Q = new double[nb][];
+    }
+
+    private void storeP(int n, int j, double[] p) {
+      if (P[j]==null) P[j] = new double[n];
+      System.arraycopy(p, 0, P[j], 0, n);
+    }
+
+    private void storeQ(int n, int j, double[] q) {
+      if (Q[j]==null) Q[j] = new double[n];
+      System.arraycopy(q, 0, Q[j], 0, n);
+    }
+
+    private void retrieveP(int n, int j, double[] p) {
+      System.arraycopy(P[j], 0, p, 0, n);
+    }
+
+    private void retrieveQ(int n, int j, double[] q) {
+      System.arraycopy(Q[j], 0, q, 0, n);
+    }
+  }
+  private Storage storage;
+
+ public enum CodeSVDException {
+   DIM_OUT_OF_BOUNDS ("Nombre de valeurs singulières désirées invalide"),
+   FIRST_STEP_FAILURE("Impossible d'initialiser le premier pas de calcul"),
+   CONVERGENCE_FAILURE("Echec de convergence ");
+   String message;
+  CodeSVDException(String message) {
+   this.message = message;
+ }
+ }
+  public static class SparseSVDException extends Exception { // Erreurs
+    private CodeSVDException code;
+    private int k;
+
+    private SparseSVDException(CodeSVDException code, int k) {
+      super();
+      this.code = code;
+      this.k = k;
+    }
+
+    public CodeSVDException getCode() {
+      return code;
+    }
+
+    public int getK() {
+      return k;
+    }
+
+    @Override
+    public String getMessage() {
+      return super.getMessage()+"\ncode = "+getCode().message +", n = "+getK();
+    }
+  }
+
+  public SparseSVD(SparseMatrix spm, int d) throws SparseSVDException {
+    int iter = Math.min(spm.getRowDimension(), spm.getColumnDimension()); // nb d'itérations 
+    if (d<=0 || d>iter)
+      throw new SparseSVDException(CodeSVDException.DIM_OUT_OF_BOUNDS, d);
+    dim = d;
+    transpose = spm.getColumnDimension()>=spm.getRowDimension()*1.2;
+    SparseMatrix A = transpose ? spm.transpose() : spm.copy();
+    rows = A.getRowDimension();
+    cols = A.getColumnDimension();
+    EPS1 = EPS*Math.sqrt(cols);
+    alph = new double[iter];  // diagonale de la matrice tridiagonale T
+    bet = new double[iter+1]; // éléments hors-diagonale de T
+    ritz = new double[iter+1];
+    bnd = new double[iter+1]; // a vérifier : initialisation (127) nécessaire ?? 
+    storage = new Storage(iter, MAXLL);
+    // Calcul de la matrice tridiagonale 
+    int[] steps_neig_ = lanso(A, iter);
+    Ut = new double[dim][rows];
+    Vt = new double[dim][cols];
+    S = new double[dim];
+    // Calcul des  vecteurs propres
+    //  nsig  : nb de val. propres "kappa-acceptables"
+    int nsig = ritvec(A, steps_neig_);
+    if (nsig<dim) dim = nsig;  // moins de valeurs obtenues que demandées
+    // libère la mémoire
+    storage = null;
+    alph =  bet = ritz = bnd = null;
+
+  }
+
+  private int[] lanso(SparseMatrix A, int iter) throws SparseSVDException {
+    // Calcul de la matrice tridiagonale
+    int neig = 0;
+    // espace de travail
+    rj = new double[cols];
+    qj = new double[cols];
+     qj1 = new double[cols];
+     pj = new double[cols];
+     pj1 = new double[cols];
+     wk = new double[cols];
+    // step one 
+    double[] rnm_tol_ = stpone(A, cols); // initialise rmn et tol
+     eta = new double[iter]; // orthogonality estimate of Lanczos vectors
+    oldeta = new double[iter];
+    if (rnm_tol_[0]==0) {
+      ritz[0] = alph[0];
+      storage.storeQ(cols, 0, qj);
+      return new int[]{0, 1}; // steps = 0 et neig = 1
+    }
+    eta[0] = oldeta[0] = EPS1;
+    boolean[] enough_ = {false}; // flag de sortie de boucle
+    int steps = 0; // j = steps
+    int[] ll_ = {0};  // 0, 1 or 2 initial Lanczos vectors in local orthog.
+    int first = 1;
+    int last = Math.min(dim+Math.max(8, dim), iter);  // = iter dans notre version
+    int i, l;
+    int intro = 0;
+    while (!enough_[0]) {
+      steps = lanczos_step(A, first, last, 
+              ll_, enough_, rnm_tol_, cols);
+      steps = enough_[0] ? steps-1 : last-1;
+      first = steps+1;
+      bet[first] = rnm_tol_[0];
+      // analyse T
+      l = 0;
+      for (int id2 = 0; id2<steps; id2++) {
+        if (l>steps) break;
+        for (i = l; i<=steps; i++) if (bet[i+1]==0) break;
+        if (i>steps) i = steps;
+        // now i is at the end of an unreduced submatrix
+        DoubleArraysPlus.copyReverse(i-l+1, alph, l, ritz, l);
+        DoubleArraysPlus.copyReverse(i-l, bet, l+1, wk, l+1);
+        imtqlb(i-l+1, l, ritz, wk, bnd);
+        for (int id3 = l; id3<=i; id3++)
+          bnd[id3] = rnm_tol_[0]*Math.abs(bnd[id3]);
+        l = i+1;
+      }
+      // sort eigenvalues into increasing order
+      DoubleArraysPlus.sort2(ritz, bnd, steps+1, 0);
+      // massage error bounds for very close ritz values 
+      neig = error_bound(enough_, END[0], END[1], steps, rnm_tol_[1]);
+      // should we stop? 
+      if (neig<dim) {
+        if (neig==0) {
+          last = first+9;
+          intro = first;
+        } else {
+          last = first+Math.max(3, 1+((steps-intro)*(dim-neig))/neig);
+        }
+        last = Math.min(last, iter);
+      } else {
+        enough_[0] = true;
+      }
+      enough_[0] = enough_[0]||first>=iter;
+    }
+    storage.storeQ(cols, steps, qj);
+    // libère la mémoire
+     rj = qj =  qj1 = pj =  pj1 =  wk = null;
+     eta = oldeta = null;
+    return new int[]{steps, neig};
+  }
+
+  private double[] stpone(SparseMatrix A,  int n)
+          throws SparseSVDException {
+    /*  stp-one performs the first step of the Lanczos algorithm.  It also
+    does a step of extended local re-orthogonalization.
+    Arguments 
+    (input)
+    n      dimension of the eigenproblem for matrix B
+    (output)
+    wptr   array of pointers that point to work space that contains
+    wptr[0]             r[j]
+    wptr[1]             q[j]
+    wptr[2]             q[j-1]
+    wptr[3]             p
+    wptr[4]             p[j-1]
+    alph             diagonal elements of matrix T 
+    throw a SparseSVDException(-1) if the choice of initial vector (startv) failed
+     */
+    // get initial normalized vector; default is random 
+    startv0(A, n);
+    System.arraycopy(pj, 0, qj, 0, n);
+    // take the first step   
+    A.opb(pj, rj);
+    alph[0] = DoubleArraysPlus.dot(rj, pj);
+    for (int i = 0; i<n; i++) rj[i] -= alph[0]*qj[i];
+    /* extended local reorthogonalization */
+    double t = DoubleArraysPlus.dot(rj, pj);
+    for (int i = 0; i<n; i++) rj[i] -= t*qj[i];
+    alph[0] += t;
+    System.arraycopy(rj, 0, pj1, 0, n);
+    double rnm = Math.sqrt(DoubleArraysPlus.dot(pj1, pj1));
+    double tol = RAD_EPS*(rnm+Math.abs(alph[0]));
+    return new double[]{rnm, tol};
+  }
+
+//  private static double random2() {
+//    double x = 0.11*(++irandom);
+//    return x-Math.floor(x);
+//  }
+//
+private void startv0(SparseMatrix A, int n)
+          throws SparseSVDException {
+    /* startv delivers a starting normalized vector in r, 
+     * and throws a SparseSVDException(-1) if no starting vector can be found.
+    Parameters 
+    (input)
+    n      dimension of the eigenproblem matrix B
+    wptr   array of pointers that point to work space
+    step      starting index for a Lanczos run
+    (output)
+    wptr   array of pointers that point to work space that contains
+    r[j], q[j], q[j-1], p[j], p[j-1]
+     */
+// get initial vector; default is random
+    double rnm2 = 0;
+    Random random = new Random(918273);
+    for (int id = 0; id<3; id++) {
+      for (int i = 0; i<n; i++) wk[i]  = random.nextDouble(); 
+      // apply operator to put r in range (essential if m singular)
+      A.opb(wk, pj);
+      rnm2 = DoubleArraysPlus.dot(pj, pj);
+      if (rnm2>0) break;
+    }
+    // normalize
+    if (rnm2<=0) throw new SparseSVDException(CodeSVDException.FIRST_STEP_FAILURE, 0);
+    rnm2 = 1/Math.sqrt(rnm2);
+    for (int i = 0; i<n; i++) pj[i] *= rnm2;
+  }
+
+  private int lanczos_step(SparseMatrix A, int first, int last,int[] ll_,   
+          boolean[] enough_, double[] rnm_tol_, int n) throws SparseSVDException {
+    /*   embodies a single Lanczos step
+    Arguments 
+    (input)
+    n        dimension of the eigenproblem for matrix B
+    first    start of index through loop				      
+    last     end of index through loop				     
+    wptr	    array of pointers pointing to work space		    
+    alf	    array to hold diagonal of the tridiagonal matrix T
+    eta      orthogonality estimate of Lanczos vectors at step j   
+    oldeta   orthogonality estimate of Lanczos vectors at step j-1
+    bet      array to hold off-diagonal of T                     
+    ll       number of intitial Lanczos vectors in local orthog. 
+    (has value of 0, 1 or 2)			
+    enough   stop flag			
+     */
+    int j;
+    double t;
+    double mid[];
+    for (j = first; j<last; j++) {
+      mid = qj1;
+      qj1 = qj;
+      qj = mid;
+      mid = pj;
+      pj = pj1;
+      pj1 = mid;
+      storage.storeQ(n, j-1, qj1);
+      if (j-1<MAXLL) storage.storeP(n, j-1, pj1);
+      bet[j] = rnm_tol_[0];
+
+      // restart if invariant subspace is found 
+      if (bet[j]==0) {
+        rnm_tol_[0] = startv(A, j, n);
+        if (rnm_tol_[0]==0) enough_[0] = true;
+      }
+      if (enough_[0]) {
+        /* added by Doug... */
+        /* These lines fix a bug that occurs with low-rank matrices */
+        mid = qj1;
+        qj1 = qj;
+        qj = mid;
+        /* ...added by Doug */
+        break;
+      }
+      /* take a lanczos step */
+      t = 1.0/rnm_tol_[0];
+      for (int i = 0; i<n; i++) qj[i] = t*rj[i];
+      for (int i = 0; i<n; i++) pj[i] *= t;
+      A.opb(pj, rj);
+      for (int i = 0; i<n; i++) rj[i] -= rnm_tol_[0]*qj1[i];
+      alph[j] = DoubleArraysPlus.dot(rj, pj);
+      for (int i = 0; i<n; i++) rj[i] -= alph[j]*qj[i];
+      /* orthogonalize against initial lanczos vectors */
+      if (j<=MAXLL&&(Math.abs(alph[j-1])>4.0*Math.abs(alph[j])))
+        ll_[0] = j;
+      for (int i = 0; i<Math.min(ll_[0], j-1); i++) {
+        storage.retrieveP(n, i, wk);
+        t = DoubleArraysPlus.dot(wk, rj);
+        storage.retrieveQ(n, i, wk);
+        for (int ii = 0; ii<n; ii++) rj[ii] -= t*wk[ii];
+        oldeta[i] = eta[i] = EPS1;
+      }
+      /* extended local reorthogonalization */
+      t = DoubleArraysPlus.dot(rj, pj1);
+      for (int i = 0; i<n; i++) rj[i] -= t*qj1[i];
+      if (bet[j]>0) bet[j] += t;
+      t = DoubleArraysPlus.dot(rj, pj);
+      for (int i = 0; i<n; i++) rj[i] -= t*qj[i];
+      alph[j] += t;
+      System.arraycopy(rj, 0, pj1, 0, n);
+      rnm_tol_[0] = Math.sqrt(DoubleArraysPlus.dot(rj, pj1));
+      rnm_tol_[1] = RAD_EPS*(bet[j]+Math.abs(alph[j])+rnm_tol_[0]);
+      /* update the orthogonality bounds */
+      ortbnd(j, rnm_tol_[0]);
+      /* restore the orthogonality state when needed */
+      purge(n, ll_[0], j, rnm_tol_);
+      if (rnm_tol_[0]<=rnm_tol_[1]) rnm_tol_[0] = 0;
+    }
+    return j;
+  }
+
+  private double startv(SparseMatrix A, int step, int n)
+          throws SparseSVDException {
+    /* startv delivers a starting vector in r and returns |r|; it returns 
+    zero if the range is spanned, and throws a SparseSVDException(-1) if no starting 
+    vector within range of operator can be found.
+    Parameters 
+    (input)
+    n      dimension of the eigenproblem matrix B
+    wptr   array of pointers that point to work space
+    step      starting index for a Lanczos run
+    (output)
+    wptr   array of pointers that point to work space that contains
+    r[j], q[j], q[j-1], p[j], p[j-1]
+     */
+// get initial vector; default is random
+    double rnm2 = DoubleArraysPlus.dot(rj, rj);
+    Random random = new Random(918273+step);
+    for (int id = 0; id<3; id++) {
+      for (int i = 0; i<n; i++) rj[i] = random.nextDouble();
+      System.arraycopy(rj, 0, pj, 0, n);
+      // apply operator to put r in range (essential if m singular)
+      A.opb(pj, rj);
+      System.arraycopy(rj, 0, pj, 0, n);
+      rnm2 = DoubleArraysPlus.dot(rj, pj);
+      if (rnm2>0) break;
+    }
+    if (rnm2<=0) throw new SparseSVDException(CodeSVDException.FIRST_STEP_FAILURE, 0);
+    double t;
+    for (int j = 0; j<step; j++) {
+      storage.retrieveQ(n, j, wk);
+      t = -DoubleArraysPlus.dot(pj, wk);
+      for (int i = 0; i<n; i++) rj[i] += t*wk[i];
+    }
+    // make sure q[step] is orthogonal to q[step-1] 
+    t = DoubleArraysPlus.dot(pj1, rj);
+    for (int i = 0; i<n; i++) rj[i] -= t*qj1[i];
+    System.arraycopy(rj, 0, pj, 0, n);
+    t = DoubleArraysPlus.dot(pj, rj);
+    if (t<=EPS*rnm2) rnm2 = 0;
+    else rnm2 = t;
+    return Math.sqrt(rnm2);
+  }
+
+  private void ortbnd(int step, double rnm) {
+    /*  updates the eta recurrence
+    Arguments 
+    (input)
+    alf      array to hold diagonal of the tridiagonal matrix T         
+    eta      orthogonality estimate of Lanczos vectors at step j        
+    oldeta   orthogonality estimate of Lanczos vectors at step j-1     
+    bet      array to hold off-diagonal of T                          
+    n        dimension of the eigenproblem for matrix B		    
+    j        dimension of T					  
+    rnm	    norm of the next residual vector			 
+    eps1	    roundoff estimate for dot product of two unit vectors
+    (output)
+    eta      orthogonality estimate of Lanczos vectors at step j+1     
+    oldeta   orthogonality estimate of Lanczos vectors at step j        
+     */
+    if (step<1) return;
+    if (rnm!=0) {
+      if (step>1)
+        oldeta[0] = (bet[1]*eta[1]+(alph[0]-alph[step])*eta[0]
+                -bet[step]*oldeta[0])/rnm+EPS1;
+      for (int i = 1; i<=step-2; i++)
+        oldeta[i] = (bet[i+1]*eta[i+1]+(alph[i]-alph[step])*eta[i]
+                +bet[i]*eta[i-1]-bet[step]*oldeta[i])/rnm+EPS1;
+    }
+    oldeta[step-1] = EPS1;
+    double t;
+    for (int i = 0; i<step; i++) {
+      t = oldeta[i];
+      oldeta[i] = eta[i];
+      eta[i] = t;
+    }
+    eta[step] = EPS1;
+  }
+
+  private void purge(int n, int ll, int step, double[] rnm_tol_) {
+    /*
+    purge examines the state of orthogonality between the new Lanczos
+    vector and the previous ones to decide whether re-orthogonalization 
+    should be performed
+    Arguments 
+    (input)
+    n        dimension of the eigenproblem for matrix B		       
+    ll       number of intitial Lanczos vectors in local orthog.       
+    r        residual vector to become next Lanczos vector            
+    q        current Lanczos vector			           
+    ra       previous Lanczos vector
+    qa       previous Lanczos vector
+    wrk      temporary vector to hold the previous Lanczos vector
+    eta      state of orthogonality between r and prev. Lanczos vectors 
+    oldeta   state of orthogonality between q and prev. Lanczos vectors
+    j        current Lanczos step				     
+    (output)
+    r	    residual vector orthogonalized against previous Lanczos 
+    vectors
+    q        current Lanczos vector orthogonalized against previous ones    
+     */
+    if (step<ll+2) return;
+    int k = DoubleArraysPlus.indAbsMax(step-(ll+1), eta, ll);
+    if (Math.abs(eta[k])<=RAD_EPS) return;
+    double REPS1 = EPS1/RAD_EPS;
+    double t;
+    for (int iteration = 0; iteration<2; iteration++) {
+      if (rnm_tol_[0]<=rnm_tol_[1]) break;
+      /* bring in a lanczos vector t and orthogonalize both 
+       * r and q against it */
+      double tq = 0;
+      double tr = 0;
+      for (int i = ll; i<step; i++) {
+        storage.retrieveQ(n, i, wk);
+        t = -DoubleArraysPlus.dot(pj, wk);
+        tq += Math.abs(t);
+        for (int ii = 0; ii<n; ii++) qj[ii] += t*wk[ii];
+        t = -DoubleArraysPlus.dot(pj1, wk);
+        tr += Math.abs(t);
+        for (int ii = 0; ii<n; ii++) rj[ii] += t*wk[ii];
+      }
+      System.arraycopy(qj, 0, pj, 0, n);
+      t = -DoubleArraysPlus.dot(rj, pj);
+      tr += Math.abs(t);
+      for (int i = 0; i<n; i++) rj[i] += t*qj[i];
+      System.arraycopy(rj, 0, pj1, 0, n);
+      rnm_tol_[0] = Math.sqrt(DoubleArraysPlus.dot(pj1, rj));
+      if (tq<=REPS1&&tr<=REPS1*rnm_tol_[0]) break;
+    }
+    for (int i = ll; i<=step; i++) {
+      eta[i] = EPS1;
+      oldeta[i] = EPS1;
+    }
+  }
+
+  private static void imtqlb(int n, int i0, double[] d, double[] e, double[] bnd)
+          throws SparseSVDException {
+    /*   imtqlb() finds the eigenvalues of a symmetric tridiagonal
+    matrix by the implicit QL method.
+    Arguments 
+    (input)
+    n      order of the symmetric tridiagonal matrix   
+    d      contains the diagonal elements of the input matrix           
+    e      contains the subdiagonal elements of the input matrix in its
+    last n-1 positions.  e[0] is arbitrary
+    i0   starting index for the 3 vectors
+    (elements with index < i0 or >= i0+n are preserved)
+    (output)
+    d      contains the eigenvalues in ascending order.  if an error
+    exit is made, the eigenvalues are correct and ordered for
+    indices 0,1,...ierr, but may not be the smallest eigenvalues.
+    e      has been destroyed.					    
+    throws a SparseSVDException(j) if the j-th eigenvalue has
+    not been determined after 30 iterations.		    
+     */
+    if (n==1) return;
+    bnd[i0] = 1;
+    for (int i = i0+1; i<i0+n; i++) {
+      bnd[i] = 0;
+      e[i-1] = e[i];
+    }
+    e[i0+n-1] = 0;
+    for (int l = i0; l<i0+n; l++) {
+      for (int iteration = 0; iteration<=30; iteration++) {
+        double p = d[l];
+        double f = bnd[l];
+        int m;
+        for (m = l; m<i0+n-1; m++) { // test de convergence
+          double test = Math.abs(d[m])+Math.abs(d[m+1]);
+          if (test+Math.abs(e[m])==test) break;
+        }
+        if (m==l) {
+          d[l] = p;
+          bnd[l] = f;
+          /* order the eigenvalues */
+          DoubleArraysPlus.sort2(d, bnd, l-i0+1, i0);
+          break;
+        } else {
+          if (iteration==30) throw new SparseSVDException(CodeSVDException.CONVERGENCE_FAILURE, l);
+          /*........ form shift ........*/
+          double g = (d[l+1]-p)/(2.0*e[l]);
+          double r = Math.hypot(g, 1);
+          g = d[m]-p+e[l]/(g+Math.copySign(r, g));
+          double s = 1;
+          double c = 1;
+          p = 0;
+          boolean underflow = false;
+          for (int i = m-1; i>=l; i--) {
+            f = s*e[i];
+            double b = c*e[i];
+            r = Math.hypot(f, g);
+            e[i+1] = r;
+            if (r==0) {
+              /*........ recover from underflow .........*/
+              underflow = true;
+              d[i+1] -= p;
+              e[m] = 0.0;
+              break;
+            }
+            s = f/r;
+            c = g/r;
+            g = d[i+1]-p;
+            r = (d[i]-g)*s+2*c*b;
+            p = s*r;
+            d[i+1] = g+p;
+            g = c*r-b;
+            f = bnd[i+1];
+            bnd[i+1] = s*bnd[i]+c*f;
+            bnd[i] = c*bnd[i]-s*f;
+          }
+
+          if (!underflow) {
+            d[l] -= p;
+            e[l] = g;
+            e[m] = 0.0;
+          }
+        }
+      }
+    }
+  }
+
+  private int error_bound(boolean[] enough_, double endl, double endr,
+          int step, double tol) {
+    /*
+    massages error bounds for very close ritz values by placing 
+    a gap between them.  The error bounds are then refined to reflect this.
+    Arguments 
+    (input)
+    endl     left end of interval containing unwanted eigenvalues
+    endr     right end of interval containing unwanted eigenvalues
+    ritz     array to store the ritz values
+    bnd      array to store the error bounds
+    enough   stop flag
+     */
+    int mid = DoubleArraysPlus.indAbsMax(step+1, bnd, 1);
+
+    for (int i = step; i>mid; i--)
+      if (Math.abs(ritz[i-1]-ritz[i])<RAD34_EPS*Math.abs(ritz[i]))
+        if (bnd[i]>tol&&bnd[i-1]>tol) {
+          bnd[i-1] = Math.hypot(bnd[i], bnd[i-1]);
+          bnd[i] = 0;
+        }
+    for (int i = 1; i<mid; i++)
+      if (Math.abs(ritz[i+1]-ritz[i])<RAD34_EPS*Math.abs(ritz[i]))
+        if (bnd[i]>tol&&bnd[i+1]>tol) {
+          bnd[i+1] = Math.hypot(bnd[i], bnd[i+1]);
+          bnd[i] = 0.0;
+        }
+    /* refine the error bounds */
+    int neig = 0;
+    double gapl = ritz[step]-ritz[0];
+    for (int i = 0; i<=step; i++) {
+      double gap = gapl;
+      if (i<step) gapl = ritz[i+1]-ritz[i];
+      gap = Math.min(gap, gapl);
+      if (gap>bnd[i]) bnd[i] *= (bnd[i]/gap);
+      if (bnd[i]<=16.0*EPS*Math.abs(ritz[i])) {
+        neig++;
+        if (!enough_[0]) enough_[0] = endl<ritz[i]&&ritz[i]<endr;
+      }
+    }
+    return neig;
+  }
+
+  private int ritvec0(SparseMatrix A, int[] steps_neig_) throws SparseSVDException {
+
+    int js, jsq, i, k, /*size,*/ id2, tmp, nsig, x;
+    double[] s, xv2;
+    double tmp0, tmp1, xnorm;
+    double[] w1 = Vt[0];
+    double[] w2 = new double[cols];
+
+    js = steps_neig_[0]+1;
+    jsq = js*js;
+    /*size = sizeof(double) * n;*/
+
+    s = new double[jsq];
+    xv2 = new double[cols];
+
+    /* initialize s to an identity matrix */
+    for (i = 0; i<jsq; i += (js+1)) s[i] = 1.0;
+    DoubleArraysPlus.copyReverse(js, alph, 0, w1, 0);
+    DoubleArraysPlus.copyReverse(steps_neig_[0], bet, 1, w2, 1);
+
+    /* on return from imtql2(), w1 contains eigenvalues in ascending 
+     * order and s contains the corresponding eigenvectors */
+    double[][] z = new double[js][js];
+    for (int r = 0; r<js; r++) for (int c = 0; c<js; c++) z[r][c] = s[r*js+c];
+    imtql2(js, js, w1, w2, z);
+    for (int r = 0; r<js; r++) for (int c = 0; c<js; c++) s[r*js+c] = z[r][c];
+
+
+    /*fwrite((char *)&n, sizeof(n), 1, fp_out2);
+    fwrite((char *)&js, sizeof(js), 1, fp_out2);
+    fwrite((char *)&kappa, sizeof(kappa), 1, fp_out2);*/
+    /*id = 0;*/
+    nsig = 0;
+    x = 0;
+    id2 = jsq-js;
+    for (k = 0; k<js; k++) {
+      tmp = id2;
+      if (bnd[k]<=KAPPA*Math.abs(ritz[k])&&k>js-steps_neig_[1]-1) {
+        if (--x<0) x = dim-1;
+        w1 = Vt[x];
+        for (i = 0; i<cols; i++) w1[i] = 0.0;
+        for (i = 0; i<js; i++) {
+          storage.retrieveQ(cols, i, w2);
+          for (int ii = 0; ii<cols; ii++) w1[ii] += s[tmp]*w2[ii];
+          tmp -= js;
+        }
+        /*fwrite((char *)w1, size, 1, fp_out2);*/
+
+        /* store the w1 vector row-wise in array xv1;   
+         * size of xv1 is (steps+1) * (nrow+ncol) elements 
+         * and each vector, even though only ncol long,
+         * will have (nrow+ncol) elements in xv1.      
+         * It is as if xv1 is a 2-d array (steps+1) by     
+         * (nrow+ncol) and each vector occupies a row  */
+
+        /* j is the index in the R arrays, which are sorted by high to low 
+        singular values. */
+
+        /*for (i = 0; i < n; i++) R->Vt->value[x]xv1[id++] = w1[i];*/
+        /*id += nrow;*/
+        nsig++;
+      }
+      id2++;
+    }
+    s = null;
+
+    /* Rotate the singular vectors and values. */
+    /* x is now the location of the highest singular value. */
+    DoubleArraysPlus.rotateArray(Vt, x);
+    dim = Math.min(dim, nsig);
+    for (x = 0; x<dim; x++) {
+      /* multiply by matrix B first */
+      A.opb(Vt[x], xv2);
+      tmp0 = DoubleArraysPlus.dot(Vt[x], xv2);
+      for (int ii = 0; ii<cols; ii++) xv2[ii] -= tmp0*Vt[x][ii];
+      tmp0 = Math.sqrt(tmp0);
+      xnorm = Math.sqrt(DoubleArraysPlus.dot(xv2, xv2));
+
+      /* multiply by matrix A to get (scaled) left s-vector */
+      A.opa(Vt[x], Ut[x]);
+      tmp1 = 1.0/tmp0;
+      for (int ii = 0; ii<rows; ii++) Ut[x][ii] *= tmp1;
+      xnorm *= tmp1;
+      bnd[i] = xnorm;
+      S[x] = tmp0;
+    }
+
+    xv2 = w2 = null;
+    return nsig;
+    /* multiply by matrix A to get (scaled) left s-vector */
+
+  }
+
+  private int ritvec(SparseMatrix A, int[] steps_neig_) throws SparseSVDException {
+    //  computes the singular vectors of matrix A	       *
+/*  Parameters
+    (input)
+    nrow       number of rows of A
+    steps      number of Lanczos iterations performed
+    fp_out2    pointer to unformatted output file
+    n	      dimension of matrix A
+    kappa      relative accuracy of ritz values acceptable as 
+    eigenvalues of A'A
+    ritz       array of ritz values
+    bnd        array of error bounds
+    alf        array of diagonal elements of the tridiagonal matrix T
+    bet        array of off-diagonal elements of T
+    w1, w2     work space
+    (output)
+    xv1        array of eigenvectors of A'A (right singular vectors of A)
+    ierr	      error code
+    0 for normal return from imtql2()
+    k if convergence did not occur for k-th eigenvalue in
+    imtql2()
+    nsig       number of accepted ritz values based on kappa
+    (local)
+    s	      work array which is initialized to the identity matrix
+    of order (j + 1) upon calling imtql2().  After the call,
+    s contains the orthonormal eigenvectors of the symmetric 
+    tridiagonal matrix T
+     */
+    // int n = cols;
+
+    double[] w1 = Vt[0];
+    double[] w2 = new double[cols];
+    int js = steps_neig_[0]+1;
+    double[][] s = new double[js][js];
+    double[] xv2 = new double[cols];
+    /* initialize s to an identity matrix */
+    for (int i = 0; i<js; i++) s[i][i] = 1;
+    DoubleArraysPlus.copyReverse(js, alph, 0, w1, 0);
+    DoubleArraysPlus.copyReverse(steps_neig_[0], bet, 1, w2, 1);
+    /* on return from imtql2(), w1 contains eigenvalues in ascending 
+     * order and s contains the corresponding eigenvectors */
+    imtql2(js, js, w1, w2, s);
+    int nsig = 0;
+    int x = 0;
+    for (int k = 0; k<js; k++) {
+      if (bnd[k]<=KAPPA*Math.abs(ritz[k])&&k>js-steps_neig_[1]-1) {
+        if (--x<0) x = dim-1;
+        w1 = Vt[x];
+        for (int i = 0; i<cols; i++) w1[i] = 0;
+        for (int i = 0; i<js; i++) {
+          storage.retrieveQ(cols, i, w2);
+          for (int ii = 0; ii<cols; ii++) w1[ii] += s[k][js-1-i]*w2[ii];
+        }
+        /*fwrite((char *)w1, size, 1, fp_out2);*/
+
+        /* store the w1 vector row-wise in array xv1;   
+         * size of xv1 is (steps+1) * (nrow+ncol) elements 
+         * and each vector, even though only ncol long,
+         * will have (nrow+ncol) elements in xv1.      
+         * It is as if xv1 is a 2-d array (steps+1) by     
+         * (nrow+ncol) and each vector occupies a row  */
+
+        /* j is the index in the R arrays, which are sorted by high to low 
+        singular values. */
+
+        /*for (i = 0; i < n; i++) R->Vt->value[x]xv1[id++] = w1[i];*/
+        /*id += nrow;*/
+        nsig++;
+      }
+    }
+    s = null;  // libère la mémoire
+  /* Rotate the singular vectors and values. */
+    /* x is now the location of the highest singular value. */
+    DoubleArraysPlus.rotateArray(Vt, x);
+    int d = Math.min(dim, nsig);
+    for (x = 0; x<d; x++) {
+      /* multiply by matrix B first */
+      A.opb(Vt[x], xv2);
+      double tmp0 = DoubleArraysPlus.dot(Vt[x], xv2);
+      for (int i = 0; i<cols; i++) xv2[i] -= tmp0*Vt[x][i];
+      tmp0 = Math.sqrt(tmp0);
+      double xnorm = Math.sqrt(DoubleArraysPlus.dot(xv2, xv2));
+      /* multiply by matrix A to get (scaled) left s-vector */
+      A.opa(Vt[x], Ut[x]);
+      double tmp1 = 1/tmp0;
+      for (int i = 0; i<rows; i++) Ut[x][i] *= tmp1;
+      xnorm *= tmp1;
+      //   bnd[i] = xnorm; bizarre ??
+      S[x] = tmp0;
+    }
+    xv2 = w2 = null;
+    return nsig;
+  }
+
+  private static void imtql2(int nm, int n, double d[], double[] e, double[][] z)
+          throws SparseSVDException {
+    /*   imtqlb() finds the eigenvalues  and eigenvectors of a symmetric tridiagonal
+    matrix by the implicit QL method.
+    Arguments 
+    (input)
+    nm     row dimension of the symmetric tridiagonal matrix   
+    n      order of the symmetric tridiagonal matrix   
+    d      contains the diagonal elements of the input matrix           
+    e      contains the subdiagonal elements of the input matrix in its
+    last n-1 positions.  e[0] is arbitrary
+    z      contains the identity matrix
+    (output)
+    d      contains the eigenvalues in ascending order.  if an error
+    exit is made, the eigenvalues are correct but unordered for
+    indices 0,1,...ierr.
+    e      has been destroyed.					    
+    z      contains orthonormal eigenvectors of the symmetric   
+    tridiagonal (or full) matrix.  if an error exit is made,
+    z contains the eigenvectors associated with the stored 
+    eigenvalues.					
+    throws a SparseSVDException(j) if the j-th eigenvalue has
+    not been determined after 30 iterations.		    
+     */
+    if (n==1) return;
+    for (int i = 1; i<n; i++) e[i-1] = e[i];
+    e[n-1] = 0.0;
+    int nnm = n*nm;
+    for (int l = 0; l<n; l++) {
+      /* look for small sub-diagonal element */
+      for (int iteration = 0; iteration<=30; iteration++) {
+        double p = d[l];
+        int m;
+        for (m = l; m<n-1; m++) {// test de convergence
+          double test = Math.abs(d[m])+Math.abs(d[m+1]);
+          if (test+Math.abs(e[m])==test) break;
+        }
+        if (m==l) break;
+        /* set error -- no convergence to an eigenvalue after
+         * 30 iterations. */
+        if (iteration==30) throw new SparseSVDException(CodeSVDException.CONVERGENCE_FAILURE, l);
+        /* form shift */
+        double g = (d[l+1]-p)/(2*e[l]);
+        double r = Math.hypot(g, 1);
+        g = d[m]-p+e[l]/(g+Math.copySign(r, g));
+        double s = 1;
+        double c = 1;
+        p = 0;
+        boolean underflow = false;
+        for (int i = m-1; i>=l; i--) {
+          double f = s*e[i];
+          double b = c*e[i];
+          r = Math.hypot(f, g);
+          e[i+1] = r;
+          if (r==0) {
+            /*........ recover from underflow .........*/
+            underflow = true;
+            d[i+1] -= p;
+            e[m] = 0.0;
+            break;
+          }
+          s = f/r;
+          c = g/r;
+          g = d[i+1]-p;
+          r = (d[i]-g)*s+2*c*b;
+          p = s*r;
+          d[i+1] = g+p;
+          g = c*r-b;
+          /* form vector */
+          for (int k = 0; k<nm; k++) {
+            f = z[i+1][k];
+            z[i+1][k] = s*z[i][k]+c*f;
+            z[i][k] = c*z[i][k]-s*f;
+          }
+        }
+        if (!underflow) {
+          d[l] -= p;
+          e[l] = g;
+          e[m] = 0.0;
+        }
+      }
+    }
+    /* order the eigenvalues and corresponding eigenvectors */
+    DoubleArraysPlus.sort2(d, z, n, 0);
+  }
+
+  /* ------------------------
+  Public Methods
+   * ------------------------ */
+  /** Return the left singular vectors
+  @return     U
+   */
+  public Matrix getU() {
+    return transpose ? (new Matrix(Vt, dim, cols)).transpose()
+            : (new Matrix(Ut, dim, rows)).transpose();
+  }
+
+  /** Return the right singular vectors
+  @return     V
+   */
+  public Matrix getV() {
+    return transpose ? (new Matrix(Ut, dim, rows)).transpose()
+            : (new Matrix(Vt, dim, cols)).transpose();
+  }
+
+  /** Return the one-dimensional array of singular values
+  @return     diagonal of S.
+   */
+  public double[] getSingularValues() {
+    return Arrays.copyOfRange(S, 0, dim);
+  }
+}

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/src/JamaPlus/SparseSVD.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/libs/xmlworker-5.5.8.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/libs/xmlworker-5.5.8.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.analec.rcp/libs/itextpdf-5.5.4.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/libs/itextpdf-5.5.4.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.analec.rcp/libs/glazedlists_java15-1.9.0.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/libs/glazedlists_java15-1.9.0.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.analec.rcp/libs/jcommon-xml-1.0.23.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/libs/jcommon-xml-1.0.23.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.analec.rcp/libs/itext-pdfa-5.5.8.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/libs/itext-pdfa-5.5.8.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.analec.rcp/libs/jcommon-1.0.23.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/libs/jcommon-1.0.23.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.analec.rcp/libs/itextpdf-5.5.8.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/libs/itextpdf-5.5.8.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.analec.rcp/libs/itext-xtra-5.5.8.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/libs/itext-xtra-5.5.8.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.analec.rcp/build.properties
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/build.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/build.properties	(revision 3653)
@@ -0,0 +1,10 @@
+output.. = bin/
+bin.includes = META-INF/,\
+				.,\
+               icons/,\
+               plugin.xml,\
+               libs/,\
+               OSGI-INF/,\
+               OSGI-INF/l10n/bundle.properties
+source..=src/
+#qualifier=svn

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/build.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/OSGI-INF/l10n/bundle.properties
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/OSGI-INF/l10n/bundle.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/OSGI-INF/l10n/bundle.properties	(revision 3653)
@@ -0,0 +1,54 @@
+#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
+#Properties file for AnalecRCP
+
+Bundle-Name = URS Annotation
+
+Bundle-Name.0 = org.txm.annotation.urs.rcp
+
+Bundle-Vendor = Textometrie.org
+
+PostTXMHOMEInstallationStep.description = Install URS Files
+
+command.label   = Import Glozz annotations (clear the current annotations)...
+command.label.0 = URS Annotations in XML-TEI URS format (-urs.xml, .aam)...
+command.label.1 = Texts and URS Units in Glozz format (.ac, .ac and .aam)...
+command.label.2 = XML-TEI Analec
+command.label.3 = URS
+command.name    = Load Annotation Structure
+command.name.0  = Edit Annotation Structure
+command.name.1  = Save Annotation Structure
+command.name.10 = Install
+command.name.11 = Import XML-TEI URS annotations...
+command.name.12 = Export to XML Glozz...
+command.name.13 = Export to XML-TEI URS...
+command.name.14 = XML-TEI Analec
+command.name.15 = Align Glozz annotations with TXM corpus words
+command.name.16 = Edit view
+command.name.17 = Restore annotations
+command.name.18 = ANR Democrat tools
+command.name.2  = Import Glozz model...
+command.name.3  = Load Corpus...
+command.name.4  = Save annotations
+command.name.5  = Load Vue
+command.name.6  = Save Vue
+command.name.7  = Export to Glozz model...
+command.name.8  = Glozz
+command.name.9  = Import Glozz annotations...
+
+menu.label      = URS
+menu.label.0    = URS
+menu.label.1    = Tools
+menu.label.2    = Annotation
+menu.label.3    = Verification
+menu.label.4    = Exploitation
+menu.label.5    = Export
+menu.label.6    = Export
+menu.mnemonic   = A
+menu.mnemonic.0 = A
+
+page.name   = URS
+page.name.0 = URS
+page.name.1 = URS
+
+view.name   = Properties
+view.name.0 = Search

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/OSGI-INF/l10n/bundle.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/OSGI-INF/l10n/bundle_fr.properties
===================================================================
--- TXM/trunk/bundles/org.txm.analec.rcp/OSGI-INF/l10n/bundle_fr.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.analec.rcp/OSGI-INF/l10n/bundle_fr.properties	(revision 3653)
@@ -0,0 +1,53 @@
+
+#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
+#Properties file for Annotations URSRCP
+Bundle-Name = Annotations URS
+
+Bundle-Name.0 = org.txm.annotation.urs.rcp
+
+Bundle-Vendor = Textometrie.org
+
+PostTXMHOMEInstallationStep.description = Installe les fichiers URS
+
+command.label   = Importer des annotations Glozz (supprime les annotations d\u00E9j\u00E0 existantes)...
+command.label.0 = Annotations URS au format XML-TEI URS (-urs.xml, .aam)...
+command.label.1 = Textes et Unit\u00E9s URS au format Glozz (.ac, .aa, .aam)...
+command.label.2 = XML-TEI Analec
+command.label.3 = URS
+command.name    = Charger une structure d'annotation...
+command.name.0  = Editer la structure d'annotation
+command.name.1  = Enregistrer la structure d'annotation
+command.name.10 = Installer
+command.name.11 = Importer des annotations XML-TEI URS...
+command.name.12 = Export XML Glozz...
+command.name.13 = Export XML-TEI URS...
+command.name.14 = XML-TEI Analec
+command.name.15 = Aligner les annotations Glozz avec les mots TXM
+command.name.16 = \u00C9diter la vue
+command.name.17 = Restaurer les annotations
+command.name.18 = Outils ANR Democrat
+command.name.2  = Importer un mod\u00E8le Glozz...
+command.name.3  = Charger le Corpus Analec...
+command.name.4  = Enregistrer les annotations URS
+command.name.5  = Charger une Vue
+command.name.6  = Enregistrer la Vue
+command.name.7  = Exporter vers un mod\u00E8le Glozz...
+command.name.8  = Glozz
+command.name.9  = Importer les annotations Glozz...
+
+menu.label      = URS
+menu.label.0    = URS
+menu.label.1    = Outils
+menu.label.2    = Annotation
+menu.label.3    = V\u00E9rification
+menu.label.4    = Exploitation
+menu.label.5    = Export
+menu.label.6    = Exporter
+menu.mnemonic   = U
+menu.mnemonic.0 = U
+
+page.name.0 = URS
+page.name.1 = URS
+
+view.name   = Propri\u00E9t\u00E9s
+view.name.0 = Chercher

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/OSGI-INF/l10n/bundle_fr.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.analec.rcp/icons/bullet_arrow_up.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/icons/bullet_arrow_up.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.analec.rcp/icons/clear.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/icons/clear.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.analec.rcp/icons/bullet_arrow_down.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/icons/bullet_arrow_down.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.analec.rcp/icons/pencil.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.analec.rcp/icons/pencil.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream


Property changes on: TXM/trunk/bundles/org.txm.analec.rcp
___________________________________________________________________
Added: svn:ignore
   + doc

target


Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/rcp/testers/IsCorpusDirty.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/rcp/testers/IsCorpusDirty.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/rcp/testers/IsCorpusDirty.java	(revision 3653)
@@ -0,0 +1,45 @@
+package org.txm.rcp.testers;
+
+import java.util.List;
+
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.PlatformUI;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.concordance.core.functions.Line;
+import org.txm.concordance.rcp.editors.ConcordanceEditor;
+import org.txm.core.results.TXMResult;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+
+
+public class IsCorpusDirty extends PropertyTester {
+	
+	@Override
+	public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
+				
+		if (receiver instanceof List) {
+			List list = (List) receiver;
+			if (list.size() == 0) return true;
+			receiver = list.get(0);
+		}
+		
+		if (receiver instanceof TXMResult) {
+			receiver = ((TXMResult) receiver).getFirstParent(MainCorpus.class);
+		}
+		
+		if (receiver instanceof Line) {
+			receiver = ((Line) receiver).getConcordance().getFirstParent(MainCorpus.class);
+		}
+		
+		if (receiver instanceof MainCorpus) {
+			return KRAnnotationEngine.needToSaveAnnotations(((MainCorpus) receiver));
+		}
+		
+		IEditorPart e = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
+		if (e instanceof ConcordanceEditor) {
+			KRAnnotationEngine.needToSaveAnnotations(((ConcordanceEditor) e).getCorpus().getMainCorpus());
+		}
+		
+		return false;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/rcp/testers/IsCorpusDirty.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/ExportStandoff.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/ExportStandoff.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/ExportStandoff.java	(revision 3653)
@@ -0,0 +1,156 @@
+// Copyright © 2010-2020 ENS de Lyon., University of Franche-Comté
+// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
+// Lyon 2, University of Franche-Comté, University of Nice
+// Sophia Antipolis, University of Paris 3.
+// 
+// The TXM platform 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 2 of the License, or (at your option) any
+// later version.
+// 
+// The TXM platform 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 the TXM platform. If not, see
+// http://www.gnu.org/licenses.
+// 
+// 
+// 
+// $LastChangedDate:$
+// $LastChangedRevision:$
+// $LastChangedBy:$ 
+//
+package org.txm.annotation.kr.rcp.commands;
+
+import java.io.File;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.Toolbox;
+import org.txm.annotation.kr.core.AnnotationManager;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.core.preferences.TBXPreferences;
+import org.txm.rcp.StatusLine;
+import org.txm.rcp.messages.TXMUIMessages;
+import org.txm.rcp.swt.dialog.LastOpened;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+// TODO: Auto-generated Javadoc
+/**
+ * Open a file in the TxtEditor @ author mdecorde.
+ */
+public class ExportStandoff extends AbstractHandler {
+
+	public static final String ID = ExportStandoff.class.getCanonicalName();
+	
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+
+		ISelection sel = (IStructuredSelection) HandlerUtil.getCurrentSelection(event);
+		if (!(sel instanceof IStructuredSelection)) return null;
+		IStructuredSelection selection = (IStructuredSelection) sel;
+
+		Object s = selection.getFirstElement();
+		if (!(s instanceof MainCorpus)) {
+			Log.warning(NLS.bind("Selection is not a Corpus: {0}. Aborting.", s));
+			return null;
+		}
+
+		Shell shell = HandlerUtil.getActiveWorkbenchWindowChecked(event).getShell();
+		//FileDialog dialog = new FileDialog(shell, SWT.SAVE);
+		FileDialog dialog = new FileDialog(shell, SWT.SAVE);
+		MainCorpus corpus = (MainCorpus) s;
+		String path = Toolbox.getTxmHomePath();
+		dialog.setFilterPath(path); //To set a specific path
+		dialog.setFileName(corpus.getID()+"_annotations.zip");
+		dialog.setFilterExtensions(new String[]{"*.zip"});
+		if (dialog.open() != null) {
+			StatusLine.setMessage(TXMUIMessages.exportingAnnotations);
+			String filepath = dialog.getFilterPath();
+			String filename = dialog.getFileName();
+
+			final File resultZipFile = new File(filepath, filename);
+			LastOpened.set(ID, resultZipFile.getParent(), resultZipFile.getName());
+			
+			try {
+				exportAnnotations(corpus, resultZipFile);
+			} catch (Exception e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+				return null;
+			}
+		}
+		return corpus;
+	}
+
+	public static boolean exportAnnotations(final MainCorpus corpus, final File resultZipFile) throws Exception {
+		final AnnotationManager am = KRAnnotationEngine.getAnnotationManager(corpus);
+		if (am == null) return true; // nothing to do
+		
+		JobHandler saveJob = SaveAnnotations.save(corpus);
+		if (saveJob != null)
+			try {
+				saveJob.join();
+			} catch (InterruptedException e1) {
+				// TODO Auto-generated catch block
+				e1.printStackTrace();
+			}
+		
+		JobHandler jobhandler = new JobHandler("Exporting annotations as standoff for "+corpus) { //$NON-NLS-1$
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				this.runInit(monitor);
+				try {
+					monitor.beginTask("Exporting annotations as standoff", 100);
+					
+					monitor.setTaskName("Writing annotations in XML-TXM stand-off files");
+					/*if (MessageDialog.openConfirm(Display.getCurrent().getActiveShell(), "Before saving annotations...", "All editors using this corpus are going to be closed. Continue ?")) {
+						return false;
+					}*/
+					
+					///lecture de tous les fichiers un par un
+					///chaque annotation est récupérée et selon l'annotateur, écrite dans un fichier spécifique à celui-ci
+
+					if (!am.exportAnnotationsToSyMoGIH(resultZipFile)) {
+						Log.warning("Error while saving stand-off annotations (see logs above).");
+						return Status.CANCEL_STATUS;
+					}
+					monitor.worked(30);
+					
+					Log.info("Done.");
+
+				} catch(Exception e) {
+					Log.warning(NLS.bind("Error while saving annotations: {0}.", e));
+					Log.printStackTrace(e);
+					return Status.CANCEL_STATUS;
+				}
+				return Status.OK_STATUS;
+			}
+		};
+
+		jobhandler.startJob(true);
+		return true;
+	}
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/ExportStandoff.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Delete.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Delete.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Delete.java	(revision 3653)
@@ -0,0 +1,138 @@
+// Copyright © 2010-2020 ENS de Lyon., University of Franche-Comté
+// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
+// Lyon 2, University of Franche-Comté, University of Nice
+// Sophia Antipolis, University of Paris 3.
+// 
+// The TXM platform 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 2 of the License, or (at your option) any
+// later version.
+// 
+// The TXM platform 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 the TXM platform. If not, see
+// http://www.gnu.org/licenses.
+// 
+// 
+// 
+// $LastChangedDate:$
+// $LastChangedRevision:$
+// $LastChangedBy:$ 
+//
+package org.txm.annotation.kr.rcp.commands.krview;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.KnowledgeRepository;
+import org.txm.annotation.kr.core.repository.KnowledgeRepositoryManager;
+import org.txm.annotation.kr.core.repository.LocalKnowledgeRepository;
+import org.txm.annotation.kr.core.repository.SQLKnowledgeRepository;
+import org.txm.annotation.kr.core.repository.TypedValue;
+import org.txm.annotation.kr.rcp.views.knowledgerepositories.KRView;
+import org.txm.utils.logger.Log;
+
+// TODO: Auto-generated Javadoc
+/**
+ * Copy KnowledgeRepository or AnnotationType toString() in clipboard
+ */
+public class Delete extends AbstractHandler {
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getCurrentSelection(event);
+//		System.out.println("Delete: "+selection);
+		delete(selection);
+
+		return null;
+	}
+
+	/**
+	 * Copy.
+	 *
+	 * @param selection the selection
+	 */
+	public static void delete(IStructuredSelection selection)
+	{
+		Object selectedItem = selection.getFirstElement();
+
+		if (selectedItem instanceof SQLKnowledgeRepository) {
+
+		} else if (selectedItem instanceof LocalKnowledgeRepository) {
+			LocalKnowledgeRepository kr = ((LocalKnowledgeRepository)selectedItem);
+			Log.info("Delete a LocalKnowledgeRepository...");
+			
+			//TODO: confirm message dialog to generate
+			KnowledgeRepositoryManager.deleteKnowledgeRepository(kr);
+			KRView.refresh();
+			
+		} else if (selectedItem instanceof AnnotationType) {
+			final AnnotationType t = ((AnnotationType)selectedItem);
+			KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(t.getKnowledgeRepository());
+			
+			if (kr instanceof LocalKnowledgeRepository) {
+				final LocalKnowledgeRepository lkr = ((LocalKnowledgeRepository)kr);
+				Log.info("Delete an AnnotationType...");
+				
+				/*JobHandler job = new JobHandler("Deleting all annotations for type : "+t) {
+					@Override
+					protected IStatus run(IProgressMonitor monitor) {
+						this.setCurrentMonitor(monitor);
+						try {*/
+							lkr.deleteType(t);
+							//TODO: For each corpus, get AnnotationManager and deleteAnnotations
+							//annotManager.deleteAnnotations(t, job);
+						/*} catch(Exception e) {
+							Log.severe("Error while deleting annotations "+e);
+							Log.printStackTrace(e);
+							return Status.CANCEL_STATUS;
+						}
+						return Status.OK_STATUS;
+					}
+				};
+				job.schedule();*/
+				
+				
+				//TODO: must delete corpus possible annotations
+				KRView.refresh();
+			}
+		} else if (selectedItem instanceof TypedValue) {
+			TypedValue v = (TypedValue) selectedItem;
+			TreeViewer tree = KRView.getTree();
+			
+			if (tree != null) {
+				TreeItem[] selItems = tree.getTree().getSelection();
+				if (selItems.length == 0) return;
+				TreeItem first = selItems[0];
+				Object o = first.getData();
+				if (o instanceof TypedValue) {
+					TypedValue selectedTypedValue = (TypedValue)o;
+					if (selectedTypedValue.getId().equals(v.getId())) {
+						TreeItem parentTreeItem = first.getParentItem();
+						Object o2 = parentTreeItem.getData();
+						if (o2 instanceof AnnotationType) {
+							AnnotationType t = (AnnotationType)o2;
+							KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(t.getKnowledgeRepository());
+							kr.deleteValue(v);
+							tree.refresh();
+						}
+					}
+				}
+			}
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Delete.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Reload.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Reload.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Reload.java	(revision 3653)
@@ -0,0 +1,68 @@
+// Copyright © 2010-2020 ENS de Lyon., University of Franche-Comté
+// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
+// Lyon 2, University of Franche-Comté, University of Nice
+// Sophia Antipolis, University of Paris 3.
+// 
+// The TXM platform 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 2 of the License, or (at your option) any
+// later version.
+// 
+// The TXM platform 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 the TXM platform. If not, see
+// http://www.gnu.org/licenses.
+// 
+// 
+// 
+// $LastChangedDate:$
+// $LastChangedRevision:$
+// $LastChangedBy:$ 
+//
+package org.txm.annotation.kr.rcp.commands.krview;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.annotation.kr.core.repository.KnowledgeRepository;
+import org.txm.annotation.kr.rcp.views.knowledgerepositories.KRView;
+
+/**
+ * Reloads a KnowledgeRepository
+ */
+public class Reload extends AbstractHandler {
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getCurrentSelection(event);
+//		System.out.println("Reload: "+selection);
+		reload(selection);
+
+		return null;
+	}
+
+	/**
+	 * Copy.
+	 *
+	 * @param selection the selection
+	 */
+	public static void reload(IStructuredSelection selection)
+	{
+		Object selectedItem = selection.getFirstElement();
+		if (selectedItem instanceof KnowledgeRepository) {
+			((KnowledgeRepository)selectedItem).reload();
+			KRView.refresh();
+		}
+	}
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Reload.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Add.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Add.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Add.java	(revision 3653)
@@ -0,0 +1,128 @@
+// Copyright © 2010-2020 ENS de Lyon., University of Franche-Comté
+// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
+// Lyon 2, University of Franche-Comté, University of Nice
+// Sophia Antipolis, University of Paris 3.
+// 
+// The TXM platform 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 2 of the License, or (at your option) any
+// later version.
+// 
+// The TXM platform 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 the TXM platform. If not, see
+// http://www.gnu.org/licenses.
+// 
+// 
+// 
+// $LastChangedDate:$
+// $LastChangedRevision:$
+// $LastChangedBy:$ 
+//
+package org.txm.annotation.kr.rcp.commands.krview;
+
+import java.io.File;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.KnowledgeRepository;
+import org.txm.annotation.kr.core.repository.KnowledgeRepositoryManager;
+import org.txm.annotation.kr.core.repository.LocalKnowledgeRepository;
+import org.txm.annotation.kr.core.repository.SQLKnowledgeRepository;
+import org.txm.annotation.kr.core.repository.TypedValue;
+import org.txm.annotation.kr.rcp.views.knowledgerepositories.KRView;
+import org.txm.utils.AsciiUtils;
+import org.txm.utils.logger.Log;
+
+// TODO: Auto-generated Javadoc
+/**
+ * Copy KnowledgeRepository or AnnotationType toString() in clipboard
+ */
+public class Add extends AbstractHandler {
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getCurrentSelection(event);
+//		System.out.println("Add: "+selection);
+		add(selection);
+
+		return null;
+	}
+
+	/**
+	 * Add a new annotation type or value.
+	 *
+	 * @param selection the selection
+	 */
+	public static void add(IStructuredSelection selection)
+	{
+		Object selectedItem = selection.getFirstElement();
+		if (selectedItem instanceof SQLKnowledgeRepository) {
+
+		} else if (selectedItem instanceof LocalKnowledgeRepository) {
+			LocalKnowledgeRepository kr = ((LocalKnowledgeRepository)selectedItem);
+			Shell shell = Display.getDefault().getActiveShell();
+			InputDialog dialog = new InputDialog(shell, "Type name", "Please enter the new type name", "", null);
+			if (dialog.open() == InputDialog.OK) {
+				String name = dialog.getValue();
+				String id = AsciiUtils.buildId(name);
+				
+				//Generate an URL page 
+				//String pathFile = KnowledgeRepositoryManager.generateLocalURLPage(kr.getName(), name, id);
+				String pathFile = null; //TODO build page for type or KR will be done in another version (after 0.7.9)
+				//System.out.println("URL for new type : "+pathFile);
+				AnnotationType at = kr.addType(name, id, pathFile);
+				KRView.refresh();
+				//kr.add(at);
+			} else {
+				Log.info("Creation aborted.");
+			}
+		} else if (selectedItem instanceof AnnotationType) {
+			AnnotationType t = ((AnnotationType)selectedItem);
+
+			String krname = t.getKnowledgeRepository();
+			
+			KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(krname);
+			if (kr instanceof LocalKnowledgeRepository) {
+				
+				LocalKnowledgeRepository lkr = ((LocalKnowledgeRepository)kr);
+
+				Shell shell = Display.getDefault().getActiveShell();
+				InputDialog dialog = new InputDialog(shell, "Value name", "Please enter the new value name", "", null);
+				if (dialog.open() == InputDialog.OK) {
+					String name = dialog.getValue();
+					String id = name;
+					/*String baseid = AsciiUtils.buildId(name);
+					String id = AsciiUtils.buildId(name);
+					int c = 1;
+					while (kr.getValue(t, id) != null) {
+						id = baseid+"_"+(c++);
+					}*/
+					TypedValue val = lkr.addValue(name, id, t.getId());
+					//t.addTypedValue(val);
+					KnowledgeRepositoryManager.generateLocalURLPage(lkr.getName(), t.getName(), t.getId());
+					KRView.refresh();
+				}
+			}
+		} else if (selectedItem instanceof TypedValue) {
+		
+
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Add.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Informations.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Informations.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Informations.java	(revision 3653)
@@ -0,0 +1,83 @@
+// Copyright © 2010-2020 ENS de Lyon., University of Franche-Comté
+// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
+// Lyon 2, University of Franche-Comté, University of Nice
+// Sophia Antipolis, University of Paris 3.
+// 
+// The TXM platform 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 2 of the License, or (at your option) any
+// later version.
+// 
+// The TXM platform 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 the TXM platform. If not, see
+// http://www.gnu.org/licenses.
+// 
+// 
+// 
+// $LastChangedDate:$
+// $LastChangedRevision:$
+// $LastChangedBy:$ 
+//
+package org.txm.annotation.kr.rcp.commands.krview;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.LocalKnowledgeRepository;
+import org.txm.annotation.kr.core.repository.SQLKnowledgeRepository;
+import org.txm.annotation.kr.core.repository.TypedValue;
+import org.txm.rcp.commands.OpenLocalizedWebPage;
+
+/**
+ * Shows a web page displaying informations about the current selection
+ */
+public class Informations extends AbstractHandler {
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getCurrentSelection(event);
+//		System.out.println("Informations: "+selection);
+		show(selection);
+
+		return null;
+	}
+
+	/**
+	 * Copy.
+	 *
+	 * @param selection the selection
+	 */
+	public static void show(IStructuredSelection selection)
+	{
+		Object selectedItem = selection.getFirstElement();
+		
+		String url = "";
+		if (selectedItem instanceof SQLKnowledgeRepository) {
+			url = ((SQLKnowledgeRepository)selectedItem).getURL();
+		} else if (selectedItem instanceof LocalKnowledgeRepository) {
+			LocalKnowledgeRepository kr = ((LocalKnowledgeRepository)selectedItem);
+			url = ((LocalKnowledgeRepository)selectedItem).getURL();
+		} else if (selectedItem instanceof AnnotationType) {
+			url = ((AnnotationType)selectedItem).getURL();
+		} else if (selectedItem instanceof TypedValue) {
+			url = ""; // TODO: see how to retrieve its KR
+		}
+		
+		if (url != null && url.length() > 0) {
+			OpenLocalizedWebPage.openfile(url);
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Informations.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/OpenKRView.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/OpenKRView.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/OpenKRView.java	(revision 3653)
@@ -0,0 +1,67 @@
+package org.txm.annotation.kr.rcp.commands.krview;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.rcp.views.knowledgerepositories.KRView;
+
+// extends org.eclipse.ui.views.showView
+public class OpenKRView extends AbstractHandler {
+	public static final String ID = OpenKRView.class.getCanonicalName(); // org.txm.rcp.commands.krview.OpenKRView
+
+	@Override
+	public final Object execute(final ExecutionEvent event)
+			throws ExecutionException {
+		IWorkbenchWindow window = HandlerUtil
+				.getActiveWorkbenchWindowChecked(event);
+
+		try {
+			openView(window);
+		} catch (PartInitException e) {
+			throw new ExecutionException("Part could not be initialized", e); //$NON-NLS-1$
+		}
+
+		return null;
+	}
+
+	/**
+	 * Opens the view with the given identifier.
+	 * 
+	 * @param viewId
+	 *            The view to open; must not be <code>null</code>
+	 * @throws PartInitException
+	 *             If the part could not be initialized.
+	 */
+	public static void openView(final IWorkbenchWindow activeWorkbenchWindow, AnnotationType type)
+					throws PartInitException {
+
+		final IWorkbenchPage activePage = activeWorkbenchWindow.getActivePage();
+		if (activePage == null) {
+			return;
+		}
+
+		activePage.showView(KRView.ID);
+		
+		if (type != null) {
+			KRView.showType(type);
+		}
+	}
+	
+	/**
+	 * Opens the view with the given identifier.
+	 * 
+	 * @param viewId
+	 *            The view to open; must not be <code>null</code>
+	 * @throws PartInitException
+	 *             If the part could not be initialized.
+	 */
+	public static void openView(final IWorkbenchWindow activeWorkbenchWindow)
+					throws PartInitException {
+		openView(activeWorkbenchWindow, null);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/OpenKRView.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Copy.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Copy.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Copy.java	(revision 3653)
@@ -0,0 +1,79 @@
+// Copyright © 2010-2020 ENS de Lyon., University of Franche-Comté
+// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
+// Lyon 2, University of Franche-Comté, University of Nice
+// Sophia Antipolis, University of Paris 3.
+// 
+// The TXM platform 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 2 of the License, or (at your option) any
+// later version.
+// 
+// The TXM platform 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 the TXM platform. If not, see
+// http://www.gnu.org/licenses.
+// 
+// 
+// 
+// $LastChangedDate:$
+// $LastChangedRevision:$
+// $LastChangedBy:$ 
+//
+package org.txm.annotation.kr.rcp.commands.krview;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.SQLKnowledgeRepository;
+import org.txm.annotation.kr.core.repository.TypedValue;
+import org.txm.rcp.utils.IOClipboard;
+
+// TODO: Auto-generated Javadoc
+/**
+ * Copy KnowledgeRepository or AnnotationType toString() in clipboard
+ */
+public class Copy extends AbstractHandler {
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getCurrentSelection(event);
+//		System.out.println("Copy: "+selection);
+		copy(selection);
+
+		return null;
+	}
+
+	/**
+	 * Copy.
+	 *
+	 * @param selection the selection
+	 */
+	public static void copy(IStructuredSelection selection)
+	{
+		Object selectedItem = selection.getFirstElement();
+		
+		String text = null;
+		if (selectedItem instanceof SQLKnowledgeRepository) {
+			text = ((SQLKnowledgeRepository)selectedItem).toHumanString();
+		} else if (selectedItem instanceof AnnotationType) {
+			text = ((AnnotationType)selectedItem).toHumanString();
+		} else if (selectedItem instanceof TypedValue) {
+			text = ((TypedValue)selectedItem).toHumanString();
+		}
+		if (text != null) {
+			IOClipboard.write(text);
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/krview/Copy.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/ExportTable.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/ExportTable.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/ExportTable.java	(revision 3653)
@@ -0,0 +1,147 @@
+// Copyright © 2010-2020 ENS de Lyon., University of Franche-Comté
+// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
+// Lyon 2, University of Franche-Comté, University of Nice
+// Sophia Antipolis, University of Paris 3.
+// 
+// The TXM platform 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 2 of the License, or (at your option) any
+// later version.
+// 
+// The TXM platform 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 the TXM platform. If not, see
+// http://www.gnu.org/licenses.
+// 
+// 
+// 
+// $LastChangedDate:$
+// $LastChangedRevision:$
+// $LastChangedBy:$ 
+//
+package org.txm.annotation.kr.rcp.commands;
+
+import java.io.File;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.Toolbox;
+import org.txm.annotation.kr.core.AnnotationManager;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.rcp.StatusLine;
+import org.txm.rcp.messages.TXMUIMessages;
+import org.txm.rcp.swt.dialog.LastOpened;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+/**
+ * Open a file in the TxtEditor 
+ * 
+ * @author mdecorde.
+ */
+public class ExportTable extends AbstractHandler {
+	
+	public static final String ID = ExportTable.class.getCanonicalName();
+	
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		
+		ISelection sel = (IStructuredSelection) HandlerUtil.getCurrentSelection(event);
+		if (!(sel instanceof IStructuredSelection)) return null;
+		IStructuredSelection selection = (IStructuredSelection) sel;
+		
+		Object s = selection.getFirstElement();
+		if (!(s instanceof MainCorpus)) {
+			Log.warning(NLS.bind("Selection is not a Corpus: {0}. Aborting.", s));
+			return null;
+		}
+		
+		Shell shell = HandlerUtil.getActiveWorkbenchWindowChecked(event).getShell();
+		//FileDialog dialog = new FileDialog(shell, SWT.SAVE);
+		FileDialog dialog = new FileDialog(shell, SWT.SAVE);
+		MainCorpus corpus = (MainCorpus) s;
+		String path = Toolbox.getTxmHomePath();
+		dialog.setFilterPath(path); //To set a specific path
+		dialog.setFileName(corpus.getID()+"_annotations.csv");
+		dialog.setFilterExtensions(new String[]{"*.csv", "*.tsv"});
+		if (dialog.open() != null) {
+			StatusLine.setMessage(TXMUIMessages.exportingAnnotations);
+			String filepath = dialog.getFilterPath();
+			String filename = dialog.getFileName();
+			
+			final File resultFile = new File(filepath, filename);
+			LastOpened.set(ID, resultFile.getParent(), resultFile.getName());
+			
+			try {
+				exportAnnotations(corpus, resultFile);
+			} catch (Exception e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+				return null;
+			}
+		}
+		return corpus;
+	}
+	
+	public static boolean exportAnnotations(final MainCorpus corpus, final File resultFile) throws Exception {
+		final AnnotationManager am = KRAnnotationEngine.getAnnotationManager(corpus);
+		if (am == null) return true; // nothing to do
+				
+		JobHandler jobhandler = new JobHandler("Exporting annotations in table for "+corpus) { //$NON-NLS-1$
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				this.runInit(monitor);
+				try {
+					monitor.beginTask("Exporting annotations as standoff", 100);
+					
+					monitor.setTaskName("Writing annotations in the table file: "+resultFile);
+					/*if (MessageDialog.openConfirm(Display.getCurrent().getActiveShell(), "Before saving annotations...", "All editors using this corpus are going to be closed. Continue ?")) {
+						return false;
+					}*/
+					
+					///lecture de tous les fichiers un par un
+					///chaque annotation est récupérée et selon l'annotateur, écrite dans un fichier spécifique à celui-ci
+					
+					if (!am.exportAnnotationsToTable(resultFile)) {
+						Log.warning("Error while exporting annotations (see logs above).");
+						return Status.CANCEL_STATUS;
+					}
+					monitor.worked(30);
+					
+					Log.info("Done.");
+					
+				} catch(Exception e) {
+					Log.warning(NLS.bind("Error while saving annotations: {0}.", e));
+					Log.printStackTrace(e);
+					return Status.CANCEL_STATUS;
+				}
+				return Status.OK_STATUS;
+			}
+		};
+		
+		jobhandler.startJob(true);
+		return true;
+	}
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/ExportTable.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/SaveAnnotations.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/SaveAnnotations.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/SaveAnnotations.java	(revision 3653)
@@ -0,0 +1,99 @@
+package org.txm.annotation.kr.rcp.commands;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.annotation.kr.core.AnnotationManager;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.rcp.messages.TXMUIMessages;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.rcp.utils.SWTEditorsUtils;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+public class SaveAnnotations extends AbstractHandler {
+	
+	public static final String ID = SaveAnnotations.class.getCanonicalName();
+	
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		
+		ISelection sel = HandlerUtil.getCurrentSelection(event);
+		if (!(sel instanceof IStructuredSelection)) return null;
+		IStructuredSelection selection = (IStructuredSelection) sel;
+		
+		Object s = selection.getFirstElement();
+		if (!(s instanceof MainCorpus))
+			return null;
+		MainCorpus corpus = (MainCorpus) s;
+		try {
+			JobHandler job = save(corpus);
+			if (job == null) {
+				return null;
+			}
+		}
+		catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+			return null;
+		}
+		
+		CorporaView.refresh();
+		
+		return corpus;
+	}
+	
+	public static JobHandler save(final MainCorpus corpus) throws Exception {
+		final AnnotationManager am = KRAnnotationEngine.getAnnotationManager(corpus);
+		if (am == null) return null; // nothing to do
+		
+		if (!KRAnnotationEngine.needToSaveAnnotations(corpus)) {
+			return null;
+		}
+		
+		JobHandler jobhandler = new JobHandler(NLS.bind("Saving annotations of {0}", corpus)) {
+			
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				this.runInit(monitor);
+				try {
+					
+					boolean rez = am.saveAnnotations(monitor);
+					monitor.worked(30);
+					
+					if (rez) {
+						Log.fine("Annotations are saved in XML-TXM files. Updating corpus indexes and editions");
+						// close all opened editors of all children corpus
+						SWTEditorsUtils.closeEditors(corpus.getProject(), true);
+					}
+					else {
+						Log.warning("** Error while saving annotations (see logs above).");
+					}
+				}
+				catch (Exception e) {
+					Log.warning(NLS.bind("Error while saving annotations: {0}", e));
+					Log.printStackTrace(e);
+					return Status.CANCEL_STATUS;
+				} catch(ThreadDeath ex) {
+					Log.info(TXMUIMessages.executionCanceled);
+					return Status.CANCEL_STATUS;
+				}
+				return Status.OK_STATUS;
+			}
+		};
+		
+		jobhandler.startJob(true);
+		jobhandler.join();
+		return jobhandler;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/SaveAnnotations.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/RecodeCorpus.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/RecodeCorpus.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/RecodeCorpus.java	(revision 3653)
@@ -0,0 +1,164 @@
+package org.txm.annotation.kr.rcp.commands;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.logging.Level;
+import java.util.regex.Pattern;
+
+import javax.xml.stream.XMLStreamException;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.kohsuke.args4j.Option;
+import org.txm.Toolbox;
+import org.txm.annotation.kr.core.conversion.CorpusRuledConvertion;
+import org.txm.annotation.kr.rcp.messages.KRAnnotationUIMessages;
+import org.txm.core.preferences.TBXPreferences;
+import org.txm.objects.Project;
+import org.txm.rcp.commands.CloseEditorsUsing;
+import org.txm.rcp.handlers.scripts.ExecuteImportScript;
+import org.txm.rcp.messages.TXMUIMessages;
+import org.txm.rcp.swt.widget.parameters.ParametersDialog;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.searchengine.cqp.corpus.Property;
+import org.txm.utils.logger.Log;
+
+public class RecodeCorpus extends AbstractHandler {
+	
+	public static final String ID = RecodeCorpus.class.getCanonicalName();
+	
+	@Option(name = "conversionFile", usage = "conversionFile", widget = "File", required = true, def = "conv.tsv")
+	protected File conversionFile;
+	
+	@Option(name = "oldType", usage = "oldType", widget = "String", required = true, def = "pos")
+	protected String oldType;
+	
+	@Option(name = "newType", usage = "newType", widget = "String", required = true, def = "pos2")
+	protected String newType;
+	
+	@Option(name = "gestionInconnus", usage = "how to manage failed conversion", widget = "String", required = true, def = "abandon")
+	protected String gestionInconnus;
+	
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		
+		ISelection isel = HandlerUtil.getCurrentSelection(event);
+		if (isel == null) return null;
+		if (!(isel instanceof IStructuredSelection)) return null;
+		IStructuredSelection selection = (IStructuredSelection) isel;
+		Object s = selection.getFirstElement();
+		if (!(s instanceof MainCorpus)) return null;
+		
+		final MainCorpus corpus = (MainCorpus) s;
+		
+		try {
+			if (ParametersDialog.open(this)) {
+				
+				JobHandler job = new JobHandler("Recode corpus " + corpus) {
+					
+					@Override
+					protected IStatus run(IProgressMonitor monitor) {
+						this.runInit(monitor);
+						
+						try {
+							recode(corpus, conversionFile, oldType, newType, monitor);
+						} catch (Exception e) {
+							Log.warning(NLS.bind("Fail to convert properties of the {0} corpus.", corpus));
+							e.printStackTrace();
+							return Status.CANCEL_STATUS;
+						} catch(ThreadDeath ex) {
+							Log.info(TXMUIMessages.executionCanceled);
+							return Status.CANCEL_STATUS;
+						}
+						return Status.OK_STATUS;
+					}
+				};
+				job.startJob();
+				return corpus;
+			}
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+		}
+		
+		return corpus;
+	}
+	
+	public static JobHandler recode(final MainCorpus corpus, CorpusRuledConvertion crc, String oldType, String newType, IProgressMonitor monitor) throws IOException, CqiClientException,
+			XMLStreamException {
+		
+		Project project = corpus.getProject();
+		if (!"xtz".equals(project.getImportModuleName())) {
+			Log.warning(NLS.bind("The {0} corpus was not imported with the XTZ import module", corpus));
+			return null;
+		}
+		
+		Property p1 = corpus.getProperty(oldType);
+		if (p1 == null) {
+			Log.warning(NLS.bind("The {0} corpus has no {1} property.", corpus, oldType));
+			return null;
+		}
+		
+		Log.info(NLS.bind("Recoding the {0} corpus properties: {1}.", corpus, oldType+" -> "+newType));
+		
+		monitor.beginTask("Recoding corpus properties...", 2);
+		monitor.setTaskName("Recoding XML-TXM files");
+		// apply conversion file
+		if (!crc.process(corpus)) {
+			Log.warning(NLS.bind("Failed to edit XML-TXM of the {0} corpus.", corpus));
+			return null;
+		}
+		monitor.worked(1);
+		
+		// update corpus indexes and edition
+		// String txmhome = Toolbox.getTxmHomePath();
+		
+		
+		project.setDoMultiThread(false); // too soon
+		project.setDoUpdate(true, false);
+		
+		// monitor.setTaskName("Updating corpus");
+		// File scriptDir = new File(txmhome, "scripts/groovy/user/org/txm/scripts/importer/xtz");
+		// File script = new File(scriptDir, "xtzLoader.groovy");
+		Log.info(NLS.bind(KRAnnotationUIMessages.updatingTheP0Corpus, corpus));
+		JobHandler ret = ExecuteImportScript.executeScript(project);
+		Display.getDefault().syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				CloseEditorsUsing.corpus(corpus);
+			}
+		});
+		monitor.worked(1);
+		return ret;
+	}
+	
+	public static JobHandler recode(final MainCorpus corpus, LinkedHashMap<Pattern, String> rules, String oldType, String newType, IProgressMonitor monitor) throws IOException, CqiClientException,
+			XMLStreamException {
+		
+		// apply conversion file
+		CorpusRuledConvertion crc = new CorpusRuledConvertion(rules, newType, oldType);
+		return recode(corpus, crc, oldType, newType, monitor);
+	}
+	
+	public static JobHandler recode(final MainCorpus corpus, File conversionFile, String oldType, String newType, IProgressMonitor monitor) throws IOException, CqiClientException, XMLStreamException {
+		Log.info(NLS.bind("Create CorpusRuledConvertion with the {0} conversion file.", conversionFile));
+		// apply conversion file
+		CorpusRuledConvertion crc = new CorpusRuledConvertion(conversionFile, oldType, newType);
+		
+		return recode(corpus, crc, oldType, newType, monitor);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/RecodeCorpus.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/SaveAnnotationsAndUpdateCorpus.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/SaveAnnotationsAndUpdateCorpus.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/SaveAnnotationsAndUpdateCorpus.java	(revision 3653)
@@ -0,0 +1,169 @@
+package org.txm.annotation.kr.rcp.commands;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.annotation.kr.core.preferences.KRAnnotationPreferences;
+import org.txm.concordance.rcp.editors.ConcordanceEditor;
+import org.txm.core.results.TXMResult;
+import org.txm.objects.Workspace;
+import org.txm.rcp.commands.workspace.UpdateCorpus;
+import org.txm.rcp.messages.TXMUIMessages;
+import org.txm.rcp.swt.dialog.UpdateCorpusDialog;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+public class SaveAnnotationsAndUpdateCorpus extends AbstractHandler {
+	
+	public static final String ID = SaveAnnotationsAndUpdateCorpus.class.getCanonicalName();
+	
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		
+		ISelection sel = HandlerUtil.getCurrentSelection(event);
+//		if (!(sel instanceof IStructuredSelection)) {
+//			Log.info("No available selection to target the corpus annotations to save");	
+//			return null;
+//		}
+		IStructuredSelection selection = (IStructuredSelection) sel;
+		
+		List<MainCorpus> corpora = Workspace.getInstance().getDeepChildren(MainCorpus.class);
+		Collections.sort(corpora);
+		ArrayList<MainCorpus> corpusWithAnnotationsToSave = new ArrayList<>();
+		for (MainCorpus corpus : corpora) {
+			if (KRAnnotationEngine.needToSaveAnnotations(corpus)) {
+				corpusWithAnnotationsToSave.add(corpus);
+			}
+		}
+
+//		if (HandlerUtil.getActiveEditor(event) instanceof ConcordanceEditor) {
+//			corpus = ((ConcordanceEditor) HandlerUtil.getActiveEditor(event)).getCorpus().getMainCorpus();
+//		} else {
+//			Object s = selection.getFirstElement();
+//			if (s == null) {
+//				Log.info("No available selection to target the corpus annotations to save");
+//				return null;
+//			} else if ((s instanceof MainCorpus)) {
+//				corpus = (MainCorpus) s;
+//			} else if (s instanceof TXMResult) {
+//				corpus = ((TXMResult) s).getFirstParent(MainCorpus.class);
+//			} else {
+//				Log.info("No available selection to target the corpus annotations to save");
+//				return null;
+//			}
+//		}
+		
+		if (corpusWithAnnotationsToSave.size() == 0) {
+			Log.info(NLS.bind("No CQP annotations found to save in the corpora: {0}", corpora));
+			return null;
+		}
+		
+		try {
+			
+			// System.out.println("DISPLAY="+Display.getDefault());
+			final Boolean[] doit = new Boolean[1];
+			doit[0] = true;
+			final MainCorpus[] corpus = new MainCorpus[1];
+			
+			final Boolean[] doupdateedition = new Boolean[1];
+			doupdateedition[0] = KRAnnotationPreferences.getInstance().getBoolean(KRAnnotationPreferences.UPDATE_EDITION);
+			
+			Display.getDefault().syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					UpdateCorpusDialog dialog = new UpdateCorpusDialog(Display.getDefault().getActiveShell());
+					dialog.setTitle("Before saving annotations...");
+					dialog.setMessages("Save Annotations and update the corpus.", dialog.getBottomMessage());
+					dialog.setDoForceUpdate(false);
+					dialog.setDoUpdateEdition(KRAnnotationPreferences.getInstance().getBoolean(KRAnnotationPreferences.UPDATE_EDITION));
+					if (selection.getFirstElement() != null && selection.getFirstElement() instanceof MainCorpus) {
+						dialog.setCorpusToUpdate((MainCorpus) selection.getFirstElement());
+					}
+					dialog.setCorporaToUpdate(corpusWithAnnotationsToSave);
+					
+					doit[0] = dialog.open() == Window.OK;
+					doupdateedition[0] = dialog.getDoUpdateEdition();
+					corpus[0] = dialog.getCorpustoUpdate();
+				}
+			});
+			if (doit[0] == false) {
+				return null;
+			}
+			
+			final MainCorpus fcorpus = corpus[0];
+			
+			Log.info(NLS.bind("Saving {0} annotations...", fcorpus.getName()));
+			JobHandler job = SaveAnnotations.save(fcorpus);
+			if (job == null) {
+				return null;
+			}
+
+			if (job.getState() == Status.OK_STATUS.getCode()) {
+				if (KRAnnotationPreferences.getInstance().getBoolean(KRAnnotationPreferences.UPDATE)) {
+					
+					JobHandler job2 = new JobHandler("Updating corpus editions and indexes", true) {
+						
+						@Override
+						protected IStatus run(IProgressMonitor monitor) {
+							this.runInit(monitor);
+							
+							try {
+								monitor.setTaskName("Updating corpus");
+								if (fcorpus != null && UpdateCorpus.update(fcorpus, false, doupdateedition[0]) != null) {
+									monitor.worked(50);
+									this.syncExec(new Runnable() {
+										
+										@Override
+										public void run() {
+											CorporaView.refreshObject(fcorpus);
+										}
+									});
+									return Status.OK_STATUS;
+								}
+								else {
+									monitor.worked(50);
+									Log.warning("Fail to update corpus. Aborting");
+									Log.warning("Fix XML-TXM files and call command 'UpdateCorpus'");
+									return Status.CANCEL_STATUS;
+								}
+							} catch(ThreadDeath ex) {
+								Log.info(TXMUIMessages.executionCanceled);
+								return Status.CANCEL_STATUS;
+							}
+						}
+					};
+					job2.schedule();
+				} else {
+					Log.warning("CQP indexes not updated. Only the XML-TXM files have been updated. Call Update corpus later to access the annotations");
+				}
+			}
+
+			CorporaView.refresh();
+			
+			return fcorpus;
+		}
+		catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+			return null;
+		}
+		
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/SaveAnnotationsAndUpdateCorpus.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/InitializeKnowledgeRepository.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/InitializeKnowledgeRepository.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/InitializeKnowledgeRepository.java	(revision 3653)
@@ -0,0 +1,89 @@
+package org.txm.annotation.kr.rcp.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.osgi.service.prefs.BackingStoreException;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.annotation.kr.core.repository.KnowledgeRepository;
+import org.txm.annotation.kr.core.repository.KnowledgeRepositoryManager;
+import org.txm.rcp.swt.dialog.UsernamePasswordDialog;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+public class InitializeKnowledgeRepository extends AbstractHandler {
+
+	public static final String ID = InitializeKnowledgeRepository.class.getCanonicalName();
+	
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		
+		ISelection sel = (IStructuredSelection) HandlerUtil.getCurrentSelection(event);
+		if (!(sel instanceof IStructuredSelection)) return null;
+		IStructuredSelection selection = (IStructuredSelection) sel;
+
+		Object s = selection.getFirstElement();
+		if (!(s instanceof MainCorpus))
+			return null;
+		
+		MainCorpus corpus = (MainCorpus) s;
+		return get(corpus);
+	}
+	
+	/**
+	 * Use this method to set eventual login+password needed by SQL knowledge repositories
+	 * 
+	 * @param corpus
+	 * @return
+	 */
+	public static List<KnowledgeRepository> get(MainCorpus corpus) {
+		List<KnowledgeRepository> ret = new ArrayList<KnowledgeRepository>();
+		
+		for (String kr_name : KRAnnotationEngine.getKnowledgeRepositoryNames(corpus)) {
+			KnowledgeRepository kr;
+			try {
+				kr = KRAnnotationEngine.getKnowledgeRepository(corpus, kr_name);
+				
+				if (kr == null) {
+					Log.warning(NLS.bind("Warning ''{0}'' KR is null. Please check KR configuration.", kr_name));
+					continue;
+				}
+				//System.out.println("IS CREDENTIAL NEEDED: "+kr_name+" "+corpus);
+				boolean[] must = KnowledgeRepositoryManager.mustLoginToKnowledgeRepository(kr_name, corpus);
+				
+				if (must[0] || must[1]) {
+					Log.info(NLS.bind("Asking credentials for {0} KR login.", kr_name));
+					UsernamePasswordDialog dialog = new UsernamePasswordDialog(Display.getCurrent().getActiveShell(), must, kr_name);
+					
+					if (dialog.open() == UsernamePasswordDialog.OK) {
+						Log.info("Temporary save login+password");
+						System.setProperty(KnowledgeRepository.LOGIN_KEY+kr_name, dialog.getUser());
+						System.setProperty(KnowledgeRepository.PASSWORD_KEY+kr_name, dialog.getPassword());
+					} else {
+						Log.info(NLS.bind("Cancelling login for {0} KR.", kr_name));
+						continue; // ignoring
+					}
+				}
+				
+				if (!kr.checkConnection()) {
+					Log.warning(NLS.bind("Error during connection to the ''{0}'' KR. Please check login, password and Internet connection.", kr_name));
+				} else {
+					ret.add(kr);
+				}
+			} catch (BackingStoreException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+			
+		}
+		return ret;
+	}
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/InitializeKnowledgeRepository.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/ImportTable.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/ImportTable.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/ImportTable.java	(revision 3653)
@@ -0,0 +1,147 @@
+// Copyright © 2010-2020 ENS de Lyon., University of Franche-Comté
+// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
+// Lyon 2, University of Franche-Comté, University of Nice
+// Sophia Antipolis, University of Paris 3.
+// 
+// The TXM platform 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 2 of the License, or (at your option) any
+// later version.
+// 
+// The TXM platform 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 the TXM platform. If not, see
+// http://www.gnu.org/licenses.
+// 
+// 
+// 
+// $LastChangedDate:$
+// $LastChangedRevision:$
+// $LastChangedBy:$ 
+//
+package org.txm.annotation.kr.rcp.commands;
+
+import java.io.File;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.Toolbox;
+import org.txm.annotation.kr.core.AnnotationManager;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.rcp.StatusLine;
+import org.txm.rcp.messages.TXMUIMessages;
+import org.txm.rcp.swt.dialog.LastOpened;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+/**
+ * Open a file in the TxtEditor 
+ * 
+ * @author mdecorde.
+ */
+public class ImportTable extends AbstractHandler {
+	
+	public static final String ID = ImportTable.class.getCanonicalName();
+	
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		
+		ISelection sel = (IStructuredSelection) HandlerUtil.getCurrentSelection(event);
+		if (!(sel instanceof IStructuredSelection)) return null;
+		IStructuredSelection selection = (IStructuredSelection) sel;
+		
+		Object s = selection.getFirstElement();
+		if (!(s instanceof MainCorpus)) {
+			Log.warning(NLS.bind("Selection is not a Corpus: {0}. Aborting.", s));
+			return null;
+		}
+		
+		Shell shell = HandlerUtil.getActiveWorkbenchWindowChecked(event).getShell();
+		//FileDialog dialog = new FileDialog(shell, SWT.SAVE);
+		FileDialog dialog = new FileDialog(shell, SWT.OPEN);
+		MainCorpus corpus = (MainCorpus) s;
+		String path = Toolbox.getTxmHomePath();
+		dialog.setFilterPath(path); //To set a specific path
+		dialog.setFileName(corpus.getID()+"_annotations.csv");
+		dialog.setFilterExtensions(new String[]{"*.csv", "*.tsv"});
+		if (dialog.open() != null) {
+			StatusLine.setMessage(TXMUIMessages.exportingAnnotations);
+			String filepath = dialog.getFilterPath();
+			String filename = dialog.getFileName();
+			
+			final File resultFile = new File(filepath, filename);
+			LastOpened.set(ID, resultFile.getParent(), resultFile.getName());
+			
+			try {
+				importAnnotations(corpus, resultFile);
+			} catch (Exception e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+				return null;
+			}
+		}
+		return corpus;
+	}
+	
+	public static boolean importAnnotations(final MainCorpus corpus, final File annotationsFile) throws Exception {
+		final AnnotationManager am = KRAnnotationEngine.getAnnotationManager(corpus);
+		if (am == null) return true; // nothing to do
+				
+		JobHandler jobhandler = new JobHandler("Importing annotations in table for "+corpus) { //$NON-NLS-1$
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				this.runInit(monitor);
+				try {
+					monitor.beginTask("Importing annotations as standoff", 100);
+					
+					monitor.setTaskName("Reading annotations in the table file: "+annotationsFile);
+					/*if (MessageDialog.openConfirm(Display.getCurrent().getActiveShell(), "Before saving annotations...", "All editors using this corpus are going to be closed. Continue ?")) {
+						return false;
+					}*/
+					
+					///lecture de tous les fichiers un par un
+					///chaque annotation est récupérée et selon l'annotateur, écrite dans un fichier spécifique à celui-ci
+					
+					if (!am.importAnnotationsFromTable(annotationsFile)) {
+						Log.warning("Error while importing annotations (see logs above).");
+						return Status.CANCEL_STATUS;
+					}
+					monitor.worked(30);
+					
+					Log.info("Done.");
+					
+				} catch(Exception e) {
+					Log.warning(NLS.bind("Error while importing annotations: {0}.", e));
+					Log.printStackTrace(e);
+					return Status.CANCEL_STATUS;
+				}
+				return Status.OK_STATUS;
+			}
+		};
+		
+		jobhandler.startJob(true);
+		return true;
+	}
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/commands/ImportTable.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/preferences/KRAnnotationPreferencePage.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/preferences/KRAnnotationPreferencePage.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/preferences/KRAnnotationPreferencePage.java	(revision 3653)
@@ -0,0 +1,114 @@
+// Copyright © 2010-2020 ENS de Lyon., University of Franche-Comté
+// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
+// Lyon 2, University of Franche-Comté, University of Nice
+// Sophia Antipolis, University of Paris 3.
+// 
+// The TXM platform 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 2 of the License, or (at your option) any
+// later version.
+// 
+// The TXM platform 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 the TXM platform. If not, see
+// http://www.gnu.org/licenses.
+// 
+// 
+// 
+// $LastChangedDate:$
+// $LastChangedRevision:$
+// $LastChangedBy:$ 
+//
+package org.txm.annotation.kr.rcp.preferences;
+
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.FieldEditor;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.IWorkbench;
+import org.txm.annotation.kr.core.preferences.KRAnnotationPreferences;
+import org.txm.rcp.IImageKeys;
+import org.txm.rcp.messages.TXMUIMessages;
+import org.txm.rcp.preferences.TXMPreferencePage;
+import org.txm.rcp.preferences.TXMPreferenceStore;
+/**
+ * This class represents a preference page that is contributed to the
+ * Preferences dialog. By subclassing <samp>FieldEditorPreferencePage</samp>, we
+ * can use the field support built into JFace that allows us to create a page
+ * that is small and knows how to save, restore and apply itself.
+ * <p>
+ * This page is used to modif y preferences only. They are stored in the
+ * preference store that belongs to the main plug-in class. That way,
+ * preferences can be accessed directly via the preference store.
+ */
+
+public class KRAnnotationPreferencePage extends TXMPreferencePage {
+	
+	private BooleanFieldEditor updateEditionField;
+	private BooleanFieldEditor updateCorpusField;
+	private Group updateGroup;
+
+	/**
+	 * Instantiates the preference page.
+	 */
+	public KRAnnotationPreferencePage() {
+		super();
+	}
+
+	/**
+	 * Creates the field editors. Field editors are abstractions of the common
+	 * GUI blocks needed to manipulate various types of preferences. Each field
+	 * editor knows how to save and restore itself.
+	 */
+	@Override
+	public void createFieldEditors() {
+		this.addField(new BooleanFieldEditor(KRAnnotationPreferences.PRESERVE_ANNOTATIONS, "Preserve annotations between TXM sessions", this.getFieldEditorParent()));
+		
+		updateCorpusField = new BooleanFieldEditor(KRAnnotationPreferences.UPDATE, "Update corpus after writing the annotations (warning the annotations won't be visible but saved in the XML-TXM files)" , this.getFieldEditorParent());
+		this.addField(updateCorpusField);
+		
+		updateGroup = new Group(getFieldEditorParent(), SWT.NONE);
+		updateGroup.setText("Update option");
+		GridData gridData2 = new GridData(SWT.FILL, SWT.FILL, true, false);
+		gridData2.horizontalSpan = 3;
+		gridData2.verticalIndent = 10;
+		updateGroup.setLayoutData(gridData2);
+		RowLayout rlayout = new RowLayout(SWT.VERTICAL);
+		rlayout.marginHeight = 5;
+		updateGroup.setLayout(rlayout);
+		
+		updateEditionField = new BooleanFieldEditor(KRAnnotationPreferences.UPDATE_EDITION, "Update editions" , updateGroup);
+		this.addField(updateEditionField);
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.jface.preference.FieldEditorPreferencePage#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
+	 */
+	@Override
+	public void propertyChange(PropertyChangeEvent event) {
+		if (((FieldEditor) event.getSource()).getPreferenceName().equals(KRAnnotationPreferences.UPDATE)) {
+			updateEditionField.setEnabled(updateCorpusField.getBooleanValue(), updateGroup);
+		}
+	}
+	
+	/*
+	 * 
+	 * @see
+	 * org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
+	 */
+	@Override
+	public void init(IWorkbench workbench) {
+		this.setPreferenceStore(new TXMPreferenceStore(KRAnnotationPreferences.getInstance().getPreferencesNodeQualifier()));
+		this.setImageDescriptor(IImageKeys.getImageDescriptor(IImageKeys.PENCIL));
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/preferences/KRAnnotationPreferencePage.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/messages/messages_fr.properties
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/messages/messages_fr.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/messages/messages_fr.properties	(revision 3653)
@@ -0,0 +1,51 @@
+#TXM messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+aboutAnnotations=À propos des annotations
+addANewCategory=Ajouter une nouvelle catégorie
+affect=Affecter
+AffectP0ToSelectionEqualsP1=Affectation de la valeur {0} à la propriété {1} pour {2} occurrences.
+all=Tous
+allLines=Toutes les lignes
+annotatingConcordanceSelection=Annotation de la sélection de la concordance...
+annotationCanceledByUser=Annotation annulée par l'utilisateur.
+availableAnnotationTypesColonP0=Types d''annotation disponibles\: {0}
+availableValuesForP0=Valeurs disponibles pour {0}
+category=Catégorie
+closeTheToolbarWithoutSaving=Fermer la barre d'outils sans enregistrer
+concordanceAnnotationArea=Zone d'annotation de concordance
+confirmAnnotationAffectation=Confirmer l'affectation de l'annotation
+couldNotAnnotateTheValueP0OnCertainSequences=** Impossible d''annoter la valeur {0} sur certaines séquences.
+delete=Supprimer
+enterAValueForAnId=Entrer une valeur d'identifiant
+errorColonNoSuitableKnowledgeRepositoryFound=** Aucun entrepôt de connaissance adéquat trouvé
+errorWhileAffectionAnnotationColonP0=** Erreur pendant l'affectation de l'annotation {0}
+errorWhileAnnotatingConcordanceColonP0=** Erreur lors de l''annotation de la concordance\: {0}
+errorWhileAnnotatingConcordanceSelectionColonP0=** Erreur lors de l''annotation de la sélection de concordance\: {0}
+errorWhileDeletingAnnotationColonP0=** Erreur lors de la suppression de l'annotation \: {0}
+keywordsAnnotation=Annotation du pivot
+listOfCategories=Liste de catégories
+lookingForTypedValueWithIdEqualsP0=Recherche de TypedValue avec id \= {0}
+motsPropritsInfDfaut=Annotation de mots
+newCategory=Nouvelle catégorie
+newValueP0ForCategoryP1=Nouvelle valeur ''{0}'' pour la catégorie {1}
+nomDeLaPropritPatternEqualsazaz09Plus=Patron de nom de propriété \: [a-z][-a-z0-9]+
+nouvelleProprit=Nouvelle propriété
+noValueFoundWithTheP0Id=Aucune valeur trouvée avec l''identifiant {0}.
+oK=OK
+openTheListOfCategories=Ouvrir la liste de catégories
+pleaseEnterTheNewTypeName=Entrer le nom de la nouvelle catégorie
+proceedToAnnotation=Passer à l'annotation
+property=Propriété
+saveTheAnnotations=Enregistrer les annotations
+selectAValueAmongTheList=Sélectionner une valeur dans la liste
+selectedLines=lignes sélectionnées
+squencesDeMotsCatgorie=Séquence de mots (catégorie)
+squencesDeMotsCatgorievaleur=Séquence de mots (catégorie/valeur)
+theEndOfAStructureP0AtP1P2=\  - la fin d'une structure {0} à [{1}-{2}] 
+theSequenceP0IsOverlappingWith=\ - La séquence {0} chevauche  
+theStartOfAStructureP0AtP1P2=\  - le début d'une structure {0} à [{1}-{2}]
+theValueP0IsNotAssociatedWithTheCategoryP1AssociateIt=La valeur {0} n''est pas associée à la catégorie {1}. L''associer ?
+updatingTheP0Corpus=Mise à jour du corpus {0}...
+valueEquals=value\=
+withTheCategory=avec la catégorie
+youAreAboutToAnnotateP0ElementsContinue=Vous êtes sur le point d''annoter {0} éléments. Continuer ?

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/messages/messages_fr.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/messages/KRAnnotationUIMessages.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/messages/KRAnnotationUIMessages.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/messages/KRAnnotationUIMessages.java	(revision 3653)
@@ -0,0 +1,77 @@
+package org.txm.annotation.kr.rcp.messages;
+
+import org.eclipse.osgi.util.NLS;
+import org.txm.utils.messages.Utf8NLS;
+
+
+/**
+ * KR annotation UI messages.
+ * 
+ * @author mdecorde
+ * @author sjacquot
+ *
+ */
+public class KRAnnotationUIMessages extends NLS {
+
+	private static final String BUNDLE_NAME = "org.txm.annotation.kr.rcp.messages.messages"; //$NON-NLS-1$
+	
+	static {
+		// initialize resource bundle
+		Utf8NLS.initializeMessages(BUNDLE_NAME, KRAnnotationUIMessages.class);
+	}
+
+	private KRAnnotationUIMessages() {
+	}
+
+	public static String availableValuesForP0; 
+	
+	public static String newValueP0ForCategoryP1; 
+	public static String theValueP0IsNotAssociatedWithTheCategoryP1AssociateIt; 
+	public static String addANewCategory; 
+	public static String proceedToAnnotation; 
+	public static String category; 
+	public static String keywordsAnnotation; 
+	public static String affect; 
+	public static String delete; 
+	public static String enterAValueForAnId; 
+	public static String selectedLines; 
+	public static String annotatingConcordanceSelection; 
+	public static String errorWhileAnnotatingConcordanceSelectionColonP0; 
+	public static String allLines; 
+	public static String errorWhileAnnotatingConcordanceColonP0; 
+	public static String errorWhileDeletingAnnotationColonP0; 
+	public static String lookingForTypedValueWithIdEqualsP0; 
+	public static String noValueFoundWithTheP0Id; 
+	public static String AffectP0ToSelectionEqualsP1; 
+	public static String couldNotAnnotateTheValueP0OnCertainSequences; 
+	public static String theSequenceP0IsOverlappingWith; 
+	public static String theEndOfAStructureP0AtP1P2; 
+	public static String theStartOfAStructureP0AtP1P2; 
+	public static String aboutAnnotations; 
+	public static String errorWhileAffectionAnnotationColonP0; 
+	public static String saveTheAnnotations; 
+	public static String openTheListOfCategories; 
+	public static String selectAValueAmongTheList; 
+	public static String valueEquals; 
+	public static String pleaseEnterTheNewTypeName; 
+	public static String newCategory; 
+	public static String withTheCategory; 
+	public static String oK; 
+	public static String confirmAnnotationAffectation; 
+	public static String youAreAboutToAnnotateP0ElementsContinue; 
+	public static String listOfCategories; 
+	public static String squencesDeMotsCatgorievaleur; 
+	public static String closeTheToolbarWithoutSaving; 
+	public static String annotationCanceledByUser; 
+	public static String availableAnnotationTypesColonP0; 
+	public static String errorColonNoSuitableKnowledgeRepositoryFound; 
+	public static String concordanceAnnotationArea; 
+	public static String squencesDeMotsCatgorie; 
+	public static String motsPropritsInfDfaut; 
+	public static String all; 
+	public static String nouvelleProprit; 
+	public static String nomDeLaPropritPatternEqualsazaz09Plus; 
+	public static String property;
+
+	public static String updatingTheP0Corpus; 
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/messages/KRAnnotationUIMessages.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/messages/messages.properties
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/messages/messages.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/messages/messages.properties	(revision 3653)
@@ -0,0 +1,51 @@
+#TXM messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+aboutAnnotations=About annotations
+addANewCategory=Add a new category
+affect=Assign
+AffectP0ToSelectionEqualsP1=Assign {0} to {1} for {1} elements.
+all=All
+allLines=all lines
+annotatingConcordanceSelection=Annotating concordance selection…
+annotationCanceledByUser=Annotation canceled by user.
+availableAnnotationTypesColonP0=Available annotation types\: {0}
+availableValuesForP0=Available values for {0}
+category=Category
+closeTheToolbarWithoutSaving=Close the toolbar without saving
+concordanceAnnotationArea=Concordance Annotation area
+confirmAnnotationAffectation=Confirm annotation assignment
+couldNotAnnotateTheValueP0OnCertainSequences=** Can not annotate the value {0} on certain sequences.
+delete=Delete
+enterAValueForAnId=Enter a value for an identifier
+errorColonNoSuitableKnowledgeRepositoryFound=** No suitable knowledge repository found
+errorWhileAffectionAnnotationColonP0=** Error while annotating {0}
+errorWhileAnnotatingConcordanceColonP0=** Error while annotating concordance\:  {0}
+errorWhileAnnotatingConcordanceSelectionColonP0=** Error while annotating concordance selection\: {0}
+errorWhileDeletingAnnotationColonP0=** Error while deleting annotation\: {0}
+keywordsAnnotation=Pivot annotation
+listOfCategories=List of categories
+lookingForTypedValueWithIdEqualsP0=Looking for TypedValue with id\={0}
+motsPropritsInfDfaut=Words annotation
+newCategory=New category
+newValueP0ForCategoryP1=New value ''{0}'' for category ''{1}''.
+nomDeLaPropritPatternEqualsazaz09Plus=Property name pattern\: [a-z][-a-z0-9]+
+nouvelleProprit=New property
+noValueFoundWithTheP0Id=No value found with the {0} identifier.
+oK=OK
+openTheListOfCategories=Open the list of categories
+pleaseEnterTheNewTypeName=Enter the name of the new category
+proceedToAnnotation=Proceed to annotation
+property=Property
+saveTheAnnotations=Save the annotations
+selectAValueAmongTheList=Select a value among the list
+selectedLines=selected lines
+squencesDeMotsCatgorie=Words sequence (category)
+squencesDeMotsCatgorievaleur=Words sequence (category/value)
+theEndOfAStructureP0AtP1P2=\  - the end of a structure {0} at [{1}-{2}] 
+theSequenceP0IsOverlappingWith=\ - The sequence {0} is overlapping with  
+theStartOfAStructureP0AtP1P2=\  - the start of a structure {0} at [{1}-{2}] 
+theValueP0IsNotAssociatedWithTheCategoryP1AssociateIt=The {0} value is not associated with the category {1}. Associate it?   
+updatingTheP0Corpus=Updating the {0} corpus...
+valueEquals=value\=
+withTheCategory=with the category
+youAreAboutToAnnotateP0ElementsContinue=You are about to annotate {0} elements. Continue ?

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/messages/messages.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/editors/imports/sections/AnnotationSection.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/editors/imports/sections/AnnotationSection.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/editors/imports/sections/AnnotationSection.java	(revision 3653)
@@ -0,0 +1,93 @@
+package org.txm.annotation.kr.rcp.editors.imports.sections;
+
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.forms.events.ExpansionAdapter;
+import org.eclipse.ui.forms.events.ExpansionEvent;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.eclipse.ui.forms.widgets.TableWrapData;
+import org.eclipse.ui.forms.widgets.TableWrapLayout;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.objects.Project;
+import org.txm.rcp.editors.imports.ImportFormEditor;
+import org.txm.rcp.editors.imports.sections.ImportEditorSection;
+
+public class AnnotationSection extends ImportEditorSection {
+	
+	private static final int SECTION_SIZE = 1;
+	
+	public static final String DEFAULTNAMESUFFIX = "KR";
+	
+	Text nameText;
+	
+	public AnnotationSection(ImportFormEditor editor, FormToolkit toolkit2, ScrolledForm form2, Composite parent, int style) {
+		super(editor, toolkit2, form2, parent, style, "annotation");
+		
+		this.section.setText("Annotation");
+		TableWrapLayout layout = new TableWrapLayout();
+		layout.makeColumnsEqualWidth = true;
+		this.section.setLayout(layout);
+		this.section.setLayoutData(getSectionGridData(SECTION_SIZE));
+		this.section.setEnabled(false);
+		
+		this.section.addExpansionListener(new ExpansionAdapter() {
+			
+			@Override
+			public void expansionStateChanged(ExpansionEvent e) {
+				form.layout(true);
+			}
+		});
+		
+		// filesection.setDescription("Select how to find source files");
+		Composite sectionClient = toolkit.createComposite(this.section);
+		TableWrapLayout slayout = new TableWrapLayout();
+		slayout.makeColumnsEqualWidth = false;
+		slayout.numColumns = 2;
+		sectionClient.setLayout(slayout);
+		this.section.setClient(sectionClient);
+		
+		Label l = toolkit.createLabel(sectionClient, "Knowledge repository name", SWT.WRAP);
+		l.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE));
+		
+		nameText = new Text(sectionClient, SWT.BORDER);
+	}
+	
+	@Override
+	public void updateFields(Project project) {
+		if (this.section.isDisposed()) return;
+		if (project == null) return;
+		
+		// List<String> values = KRAnnotationEngine.getKnowledgeRepositoryNames(project);
+		//
+		// String value = project.getName()+DEFAULTNAMESUFFIX;
+		// if (values.size() > 0) {
+		// value = values.get(0);
+		// }
+		// nameText.setText(value);
+	}
+	
+	@Override
+	public boolean saveFields(Project project) {
+		if (!this.section.isDisposed()) {
+			String value = nameText.getText();
+			
+			return true;
+		}
+		return false;
+	}
+	
+	@Override
+	public boolean checkFields() {
+		return true;
+	}
+	
+	@Override
+	public int getSectionSize() {
+		return SECTION_SIZE;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/editors/imports/sections/AnnotationSection.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/edition/EditionAnnotations.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/edition/EditionAnnotations.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/edition/EditionAnnotations.java	(revision 3653)
@@ -0,0 +1,234 @@
+package org.txm.annotation.kr.rcp.edition;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.TreeMap;
+
+import org.eclipse.osgi.util.NLS;
+import org.txm.annotation.kr.core.Annotation;
+import org.txm.annotation.kr.core.AnnotationManager;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.TypedValue;
+import org.txm.concordance.core.functions.Concordance;
+import org.txm.edition.rcp.editors.SynopticEditionEditor;
+import org.txm.objects.Match;
+import org.txm.objects.Match2P;
+import org.txm.searchengine.cqp.CQPSearchEngine;
+import org.txm.searchengine.cqp.corpus.CQPCorpus;
+import org.txm.searchengine.cqp.corpus.query.MatchUtils;
+import org.txm.utils.logger.Log;
+
+/**
+ * Annotation values to display in the current concordance shown lines
+ * 
+ * Call getStrings(conclines, from, to) 
+ * 
+ * @author mdecorde
+ *
+ */
+public class EditionAnnotations {
+	
+	SynopticEditionEditor editor;
+	
+	private AnnotationType viewAnnotation;
+	
+	public EditionAnnotations(SynopticEditionEditor editor) {
+		this.editor = editor;
+	}
+	
+	private boolean overlapAnnotation;
+
+	private HashMap<String, HashMap<String, String>> lines;
+
+	public void setAnnotationOverlap(boolean overlap) {
+		overlapAnnotation = overlap;
+	}
+	public boolean getAnnotationOverlap() {
+		return overlapAnnotation;
+	}
+	
+	public HashMap<String, HashMap<String, String>> computeStrings(String startID, String endID) throws Exception {
+
+		CQPCorpus corpus = this.editor.getCorpus();
+		
+		int[] indexes = CQPSearchEngine.getCqiClient().str2Id(corpus.getProperty("id").getQualifiedName(), new String[] {startID, endID});
+		int[] startEndPositions = CQPSearchEngine.getCqiClient().idList2Cpos(corpus.getProperty("id").getQualifiedName(), indexes);
+		int[] allPositions = MatchUtils.toPositions(startEndPositions[1], startEndPositions[0]);
+		String[] allWordIDS = CQPSearchEngine.getCqiClient().cpos2Str(corpus.getProperty("id").getQualifiedName(), allPositions);
+		
+		HashMap<Match, String> matches = new HashMap<Match, String>();
+		for (int i = 0 ; i < allWordIDS.length ; i++) {
+			matches.put(new Match2P(allPositions[i]), allWordIDS[i]);
+		}
+		ArrayList<Match> sorted_matches = new ArrayList<Match>(matches.keySet());
+		Collections.sort(sorted_matches);
+		
+		List<Annotation> ann = getAnnotationForMatches(sorted_matches, overlapAnnotation);
+		lines = new HashMap<String, HashMap<String, String>>();
+		
+		for (int i = 0 ; i < ann.size() ; i++) {
+			Annotation a = ann.get(i);
+			HashMap<String, String> aline = new HashMap<String, String>();
+			TypedValue annotation = getAnnotationTypedValue(a);
+			aline.put(annotation.getTypeID(), annotation.getId());
+			lines.put(matches.get(sorted_matches.get(i)), aline);
+		}
+		
+		return lines; // TODO find a way to add with lazy method
+	}
+	
+	private String findAnnotationForString(Match match, List<Annotation> annots, boolean overlap) {
+		String annotationValue = "";
+		if (annots!=null) {
+			if (!annots.isEmpty()) {
+				for (Annotation annot : annots) {
+					if (overlap) {
+						if ((annot.getStart()<=match.getStart() && annot.getEnd()>=match.getEnd()) || (annot.getStart()>match.getStart() && annot.getEnd()<match.getEnd())
+								) {
+							annotationValue = annot.getValue(); 
+							// use the first Annotation found, the one stored in the temporary HSQL database
+							//should be modified to display a list of annotation values corresponding to the match positions (or wrapped if overlap is admitted)
+						}
+					} else {
+						if (annot.getStart()==match.getStart() && annot.getEnd()==match.getEnd()) {
+							annotationValue = annot.getValue(); 
+							// use the first Annotation found, the one stored in the temporary HSQL database
+						}
+					}
+				}
+			}
+		}
+		return annotationValue;
+	}
+	
+	public TypedValue getAnnotationTypedValue(Annotation annotation) { 
+
+		TypedValue annotationValue = null;
+		if (annotation!=null) {
+			annotationValue = viewAnnotation.getTypedValue(annotation.getValue());
+			if (annotationValue == null) { // the annotation is not stored in the KR type -> the annotation is surely built with the CQPAnnotationManager
+				//System.out.println("WARNING: no annotation value found for value id="+annotation.getValue()+" - will be created.");
+				annotationValue = new TypedValue(annotation.getValue(), annotation.getValue(), annotation.getType());
+			}
+		}
+		
+		return annotationValue;
+	}
+
+	/**
+	 * 
+	 * @return the current annotation type
+	 */
+	public AnnotationType getViewAnnotation() {
+		return viewAnnotation;
+	}
+
+
+	private List<Annotation> prepareAnnotationsList(List<Match> matches, List<Annotation> annotations, boolean overlap){
+		List<Annotation> annotsList = new ArrayList<Annotation>();
+
+		int iMatch = 0;
+		int iAnnotation = 0;
+		int nMatch = matches.size();
+		int nAnnotations = annotations.size();
+
+		while (iMatch < nMatch && iAnnotation < nAnnotations) {
+			if (overlap) {
+				if (matches.get(iMatch).getEnd() < annotations.get(iAnnotation).getStart()) {
+					iMatch++;
+					annotsList.add(null); // nothing for this match
+				} else if (annotations.get(iAnnotation).getEnd() < matches.get(iMatch).getStart()) {
+					iAnnotation++;
+				} else {
+					annotsList.add(annotations.get(iAnnotation));
+					iMatch++;
+				}
+			} else {
+				if (matches.get(iMatch).getEnd() < annotations.get(iAnnotation).getStart()) {
+					iMatch++;
+					annotsList.add(null); // nothing for this match
+				} else if (annotations.get(iAnnotation).getEnd() < matches.get(iMatch).getStart()) {
+					iAnnotation++;
+				} else if (annotations.get(iAnnotation).getStart() == matches.get(iMatch).getStart() && 
+						annotations.get(iAnnotation).getEnd() == matches.get(iMatch).getEnd()) {
+					annotsList.add(annotations.get(iAnnotation));
+					iMatch++;
+					iAnnotation++;
+				} else {
+					iAnnotation++;
+				}
+			}
+		}
+
+		while (annotsList.size() < matches.size() ) annotsList.add(null); // fill matches that were not process due to no more annotations
+
+		return annotsList;
+	}
+
+	private HashMap<Match, Annotation> prepareAnnotationsMap(List<Match> matches, List<Annotation> annots, boolean overlap){
+		HashMap<Match, Annotation> annotsList = new HashMap<Match, Annotation>();
+		for (Match m : matches) {
+			boolean hasAnnotations = false;
+			if (annots!=null) {
+				if (!annots.isEmpty()) {
+					for (Annotation annot : annots) {
+						if (overlap){
+							if ((annot.getStart() <= m.getStart() && m.getStart() <= annot.getEnd() && m.getEnd() >= annot.getEnd()) || 
+									(annot.getStart() <= m.getEnd() && m.getEnd() <= annot.getEnd() && m.getStart() <= annot.getStart()) 
+									|| !(annot.getEnd() < m.getStart() || annot.getStart() > m.getEnd())){
+								annotsList.put(m, annot);
+								hasAnnotations = true;
+							}
+						} else {
+							if (annot.getStart()==m.getStart() && annot.getEnd()==m.getEnd()) {
+								annotsList.put(m, annot); 
+								hasAnnotations = true;
+							}
+						}
+					}
+				}
+			}
+			if (!hasAnnotations) {
+				annotsList.put(m, null);
+			}
+		}
+		return annotsList;
+	}
+
+	public List<Annotation> getAnnotationForMatches(List<Match> subsetMatch, boolean overlapAnnotation) throws Exception {
+		
+		AnnotationManager am = KRAnnotationEngine.getAnnotationManager(editor.getCorpus());
+		
+		//List<Annotation> allAnnotations = null;
+		List<Annotation> annotationsPerMatch = new ArrayList<Annotation>();
+		if (viewAnnotation != null && am != null) {
+			try {
+				annotationsPerMatch = am.getAnnotationsForMatches(viewAnnotation, subsetMatch, overlapAnnotation);
+				//System.out.println("annotationsPerMatch: "+annotationsPerMatch);
+			} catch (Exception e) {
+				Log.warning(NLS.bind("Error while reading annotation {0} and with {1} matches", viewAnnotation, subsetMatch.size()));
+				Log.printStackTrace(e);
+			}
+		}
+		return annotationsPerMatch;
+	}
+
+	public void setViewAnnotation(AnnotationType type) {
+		viewAnnotation = type;
+	}
+	
+	/**
+	 * 
+	 * @param i the relative position of the HashMap<String, String> in the lines list
+	 * 
+	 * @return the HashMap<String, String> pointed by 'i'. May return null if i is wrong.
+	 */
+	public HashMap<String, String> getAnnotationsString(String line) {
+		if (lines == null) return null;
+		if (!lines.containsKey(line)) return null;
+		return lines.get(line);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/edition/EditionAnnotations.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/edition/WordAnnotationToolbar.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/edition/WordAnnotationToolbar.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/edition/WordAnnotationToolbar.java	(revision 3653)
@@ -0,0 +1,936 @@
+package org.txm.annotation.kr.rcp.edition;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Vector;
+import java.util.logging.Level;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.TypedEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.ListDialog;
+import org.txm.annotation.kr.core.Annotation;
+import org.txm.annotation.kr.core.AnnotationManager;
+import org.txm.annotation.kr.core.DatabasePersistenceManager;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.annotation.kr.core.preferences.KRAnnotationPreferences;
+import org.txm.annotation.kr.core.repository.AnnotationEffect;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.KnowledgeRepository;
+import org.txm.annotation.kr.core.repository.KnowledgeRepositoryManager;
+import org.txm.annotation.kr.core.repository.LocalKnowledgeRepository;
+import org.txm.annotation.kr.core.repository.TypedValue;
+import org.txm.annotation.kr.rcp.commands.InitializeKnowledgeRepository;
+import org.txm.annotation.kr.rcp.commands.SaveAnnotations;
+import org.txm.annotation.kr.rcp.concordance.ConcordanceAnnotations;
+import org.txm.annotation.kr.rcp.messages.KRAnnotationUIMessages;
+import org.txm.annotation.kr.rcp.views.knowledgerepositories.KRView;
+import org.txm.annotation.rcp.editor.AnnotationArea;
+import org.txm.annotation.rcp.editor.AnnotationExtension;
+import org.txm.concordance.core.functions.Concordance;
+import org.txm.concordance.rcp.messages.ConcordanceUIMessages;
+import org.txm.core.messages.TXMCoreMessages;
+import org.txm.core.results.TXMResult;
+import org.txm.edition.rcp.editors.SynopticEditionEditor;
+import org.txm.objects.Match;
+import org.txm.objects.Match2P;
+import org.txm.objects.Page;
+import org.txm.rcp.IImageKeys;
+import org.txm.rcp.editors.TXMEditor;
+import org.txm.rcp.swt.GLComposite;
+import org.txm.rcp.swt.dialog.ConfirmDialog;
+import org.txm.rcp.swt.provider.SimpleLabelProvider;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.searchengine.cqp.CQPSearchEngine;
+import org.txm.searchengine.cqp.corpus.CQPCorpus;
+import org.txm.searchengine.cqp.corpus.WordProperty;
+import org.txm.utils.AsciiUtils;
+import org.txm.utils.logger.Log;
+
+public class WordAnnotationToolbar extends AnnotationArea {
+	
+	/**
+	 * the limit number of annotation when a confirm dialog box is shown
+	 */
+	protected static final int NALERTAFFECTANNOTATIONS = 100;
+	
+	public static final String EMPTYTEXT = ""; //$NON-NLS-1$
+	
+	/** The annotation service */
+	protected AnnotationManager annotManager;
+	
+	protected SynopticEditionEditor editor;
+	
+	/**
+	 * The concordance annotations to show in the concordance column table
+	 */
+	private EditionAnnotations annotations = null;
+	
+	/**
+	 * All available annotation types
+	 */
+	protected List<TypedValue> typeValuesList;
+	
+	protected ComboViewer annotationTypesCombo;
+	
+	protected Label equalLabel;
+	
+	protected Text annotationValuesText;
+	
+	protected Button affectAnnotationButton;
+	
+	protected Button deleteAnnotationButton;
+	
+	protected KnowledgeRepository currentKnowledgeRepository = null;
+	
+	protected Vector<AnnotationType> typesList = new Vector<>();
+	
+	protected AnnotationType tagAnnotationType; // the tag annotation type if annotation mode is simple
+	
+	protected TypedValue value_to_add;
+	
+	//protected Concordance concordance;
+	
+	private CQPCorpus corpus;
+	
+	private TableViewerColumn annotationColumnViewer;
+	
+	private Font annotationColummnFont;
+	
+	private Font defaultColummnFont;
+	
+	private Button addAnnotationTypeLink;
+	
+	private Button addTypedValueLink;
+	
+	@Override
+	public String getName() {
+		return KRAnnotationUIMessages.motsPropritsInfDfaut;
+	}
+	
+	@Override
+	public boolean allowMultipleAnnotations() {
+		return true;
+	}
+	
+	public WordAnnotationToolbar() {}
+	
+	protected AnnotationType getSelectedAnnotationType() {
+		return annotations.getViewAnnotation();
+	}
+	
+	public void updateAnnotationWidgetStates() {
+		if (annotationArea == null) return; // :)
+		
+		if (getSelectedAnnotationType() != null) {
+			annotationValuesText.setEnabled(true);
+			affectAnnotationButton.setEnabled(true);
+			deleteAnnotationButton.setEnabled(true);
+		}
+		else {
+			annotationValuesText.setEnabled(false);
+			affectAnnotationButton.setEnabled(false);
+			deleteAnnotationButton.setEnabled(false);
+		}
+	}
+	
+	protected void affectAnnotationToSelection(String[] word_selection) {
+		
+		ArrayList<Match> matches = new ArrayList<>();
+
+		try {
+			int[] indexes = CQPSearchEngine.getCqiClient().str2Id(corpus.getProperty("id").getQualifiedName(), word_selection);
+			int[] allPositions = CQPSearchEngine.getCqiClient().idList2Cpos(corpus.getProperty("id").getQualifiedName(), indexes);
+			for (int p : allPositions) {
+				matches.add(new Match2P(p));
+			}
+			affectAnnotationsToMatches(matches);
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+	
+	protected void affectAnnotationValues(final List<? extends Match> matches, final AnnotationType type, final String svalue, JobHandler job) {
+		value_to_add = null; // reset
+		if (matches == null || matches.size() == 0) {
+			Log.warning("No line selected. Aborting.");
+			return;
+		}
+		if (type == null) return; // no type, no annotation
+		
+		job.syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				if (matches.size() > NALERTAFFECTANNOTATIONS) {
+					ConfirmDialog dialog = new ConfirmDialog(Display.getCurrent().getActiveShell(),
+							"confirm_annotate",  //$NON-NLS-1$
+							KRAnnotationUIMessages.confirmAnnotationAffectation,
+							NLS.bind(KRAnnotationUIMessages.youAreAboutToAnnotateP0ElementsContinue, matches.size()));
+					
+					if (dialog.open() == ConfirmDialog.CANCEL) {
+						Log.info("Annotation aborted by user.");
+						matches.clear();
+					}
+				}
+			}
+		});
+		
+		// get value from combo text value
+		Log.fine(NLS.bind(KRAnnotationUIMessages.lookingForTypedValueWithIdEqualsP0, svalue));
+		final KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(type.getKnowledgeRepository());
+		value_to_add = kr.getValue(type, svalue);
+		
+		
+		if (value_to_add == null && kr instanceof LocalKnowledgeRepository) { // create or not the annotation is simple mode
+			value_to_add = kr.addValue(svalue, svalue, type.getId());
+		}
+		
+		if (value_to_add == null) {
+			job.syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					String mess = KRAnnotationUIMessages.bind(KRAnnotationUIMessages.noValueFoundWithTheP0Id, svalue);
+					Log.warning(mess);
+					MessageDialog.openError(Display.getCurrent().getActiveShell(), "Annotation canceled", mess);
+				}
+			});
+			return;
+		}
+		
+		Log.info(TXMCoreMessages.bind(KRAnnotationUIMessages.AffectP0ToSelectionEqualsP1, value_to_add.getId(), value_to_add.getTypeID(), matches.size()));
+		
+		// finally we can 'try' to create the annotations \o/
+		try {
+			HashMap<Match, List<Annotation>> existingAnnots = annotManager.createAnnotations(type, value_to_add, matches, job);
+			
+			// did we had problems ?
+			if (existingAnnots != null && existingAnnots.size() > 0) {
+				String message = NLS.bind(KRAnnotationUIMessages.couldNotAnnotateTheValueP0OnCertainSequences, value_to_add.getStandardName());
+				for (Match m : existingAnnots.keySet()) {
+					message += NLS.bind(KRAnnotationUIMessages.theSequenceP0IsOverlappingWith, m);
+					
+					for (Annotation existingAnnot : existingAnnots.get(m)) {
+						if (existingAnnot.getStart() < m.getStart()) {
+							message += TXMCoreMessages.bind(KRAnnotationUIMessages.theEndOfAStructureP0AtP1P2, existingAnnot.getType(), existingAnnot.getStart(), existingAnnot.getEnd());
+						}
+						else {
+							message += TXMCoreMessages.bind(KRAnnotationUIMessages.theStartOfAStructureP0AtP1P2, existingAnnot.getType(), existingAnnot.getStart(), existingAnnot.getEnd());
+						}
+					}
+				}
+				final String final_message = message;
+				job.syncExec(new Runnable() {
+					
+					@Override
+					public void run() {
+						MessageDialog.openInformation(editor.getSite().getShell(), KRAnnotationUIMessages.aboutAnnotations, final_message);
+					}
+				});
+			}
+			// if (history != null && !history.get(type).contains(value_to_add))
+			// history.get(type).add(value_to_add);
+			
+			if (Log.getLevel().intValue() < Level.INFO.intValue() && annotManager != null) {
+				annotManager.checkData();
+			}
+			// concordance.reloadCurrentLines();
+		}
+		catch (Exception e1) {
+			Log.warning(NLS.bind(KRAnnotationUIMessages.errorWhileAffectionAnnotationColonP0, e1));
+			Log.printStackTrace(e1);
+			return;
+		}
+		
+		job.syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				try {
+					editor.refresh(false);
+				}
+				catch (Exception e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+			}
+		});
+	}
+	
+	protected void deleteAnnotationValues(String[] word_selection) {
+		
+		ArrayList<Match> matches = new ArrayList<>();
+		try {
+			int[] indexes = CQPSearchEngine.getCqiClient().str2Id(corpus.getProperty("id").getQualifiedName(), word_selection);
+			int[] allPositions = CQPSearchEngine.getCqiClient().idList2Cpos(corpus.getProperty("id").getQualifiedName(), indexes);
+			for (int p : allPositions) {
+				matches.add(new Match2P(p));
+			}
+			deleteAnnotationValues(matches);
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+		}
+		
+	}
+	
+	protected void deleteAnnotationValues(final List<Match> matches) {
+		final AnnotationType type = getSelectedAnnotationType();
+		
+		JobHandler job = new JobHandler(KRAnnotationUIMessages.annotatingConcordanceSelection, true) {
+			
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				this.runInit(monitor);
+				try {
+					deleteAnnotationValues(matches, type, this);
+				}
+				catch (Exception e) {
+					Log.severe(NLS.bind(KRAnnotationUIMessages.errorWhileAnnotatingConcordanceSelectionColonP0, e));
+					Log.printStackTrace(e);
+					return Status.CANCEL_STATUS;
+				}
+				catch (ThreadDeath td) {
+					Log.info(KRAnnotationUIMessages.annotationCanceledByUser);
+					return Status.CANCEL_STATUS;
+				}
+				
+				return Status.OK_STATUS;
+			}
+		};
+		job.startJob(true);
+	}
+	
+	protected void deleteAnnotationValues(List<Match> matches, AnnotationType type, JobHandler job) {
+		
+		if (matches.size() == 0) {
+			Log.warning("No lines selected. Aborting.");
+			return;
+		}
+		
+		if (type == null) {
+			return;
+		}
+		
+		try {
+			if (annotManager != null && annotManager.deleteAnnotations(type, matches, job)) {
+				if (Log.getLevel().intValue() < Level.INFO.intValue()) annotManager.checkData();
+				
+			}
+			else {
+				return;
+			}
+		}
+		catch (Exception e1) {
+			Log.warning(NLS.bind(KRAnnotationUIMessages.errorWhileDeletingAnnotationColonP0, e1));
+			Log.printStackTrace(e1);
+			return;
+		}
+		
+		job.syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				try {
+					editor.refresh(false);
+				}
+				catch (Exception e) {
+					Log.printStackTrace(e);
+				}
+			}
+		});
+	}
+	
+	protected void affectAnnotationsToMatches(final List<? extends Match> matches) {
+		final AnnotationType type = getSelectedAnnotationType();
+		final String svalue = annotationValuesText.getText();
+		
+		JobHandler job = new JobHandler(KRAnnotationUIMessages.annotatingConcordanceSelection, true) {
+			
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				this.runInit(monitor);
+				try {
+					affectAnnotationValues(matches, type, svalue, this);
+				}
+				catch (Exception e) {
+					Log.severe(NLS.bind(KRAnnotationUIMessages.errorWhileAnnotatingConcordanceSelectionColonP0, e));
+					Log.printStackTrace(e);
+					return Status.CANCEL_STATUS;
+				}
+				catch (ThreadDeath td) {
+					Log.info(KRAnnotationUIMessages.annotationCanceledByUser);
+					return Status.CANCEL_STATUS;
+				}
+				
+				return Status.OK_STATUS;
+			}
+		};
+		job.startJob(true);
+	}
+	
+	@Override
+	public boolean install(TXMEditor<? extends TXMResult> txmeditor, AnnotationExtension ext, Composite parent, int position) throws Exception {
+		
+		this.extension = ext;
+		this.editor = (SynopticEditionEditor) txmeditor;
+		this.corpus = editor.getCorpus();
+		this.annotManager = KRAnnotationEngine.getAnnotationManager(corpus);
+		this.annotations = new EditionAnnotations(this.editor);
+		
+		// TODO install browser listeners here
+		
+		List<KnowledgeRepository> krs = InitializeKnowledgeRepository.get(corpus.getMainCorpus());
+		typesList.clear();
+		Log.fine("Corpus KRs: " + krs); //$NON-NLS-1$
+		
+		currentKnowledgeRepository = KnowledgeRepositoryManager.getKnowledgeRepository(corpus.getMainCorpus().getName());
+		if (currentKnowledgeRepository == null) {
+			HashMap<String, HashMap<String, ?>> conf = new HashMap<>();
+			HashMap<String, String> access = new HashMap<>();
+			conf.put(KRAnnotationEngine.KNOWLEDGE_ACCESS, access);
+			HashMap<String, HashMap<String, String>> fields = new HashMap<>();
+			conf.put(KRAnnotationEngine.KNOWLEDGE_TYPES, fields);
+			HashMap<String, HashMap<String, String>> strings = new HashMap<>();
+			conf.put(KRAnnotationEngine.KNOWLEDGE_STRINGS, strings);
+			
+			access.put("mode", DatabasePersistenceManager.ACCESS_FILE); //$NON-NLS-1$
+			access.put("version", "0"); //$NON-NLS-1$ //$NON-NLS-2$
+			currentKnowledgeRepository = KnowledgeRepositoryManager.createKnowledgeRepository(corpus.getMainCorpus().getName(), conf);
+			KnowledgeRepositoryManager.registerKnowledgeRepository(currentKnowledgeRepository);
+			// KRAnnotationEngine.registerKnowledgeRepositoryName(corpus, corpus.getMainCorpus().getName());
+		}
+		
+		List<WordProperty> wordProperties = corpus.getProperties();
+		for (WordProperty p : wordProperties) {
+			if (p.getName().equals("id")) continue; //$NON-NLS-1$
+			AnnotationType type = currentKnowledgeRepository.getType(p.getName());
+			if (type == null) {
+				AnnotationType t = currentKnowledgeRepository.addType(p.getName(), p.getName());
+				t.setEffect(AnnotationEffect.TOKEN);
+			}
+			else if (type != null) {
+				type.setEffect(AnnotationEffect.TOKEN);
+			}
+		}
+		
+		Log.fine("KR: " + currentKnowledgeRepository); //$NON-NLS-1$
+		List<AnnotationType> krtypes = currentKnowledgeRepository.getAllAnnotationTypes();
+		for (AnnotationType type : krtypes) {
+			if (type.getEffect().equals(AnnotationEffect.TOKEN)) {
+				typesList.add(type);
+			}
+		}
+		
+		Log.fine(NLS.bind(KRAnnotationUIMessages.availableAnnotationTypesColonP0, typesList));
+		
+		annotationArea = new GLComposite(parent, SWT.NONE, KRAnnotationUIMessages.concordanceAnnotationArea);
+		annotationArea.getLayout().numColumns = 12;
+		annotationArea.getLayout().horizontalSpacing = 2;
+		annotationArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+		
+		GridData gdata = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+		gdata.widthHint = 90;
+		
+		new Label(annotationArea, SWT.NONE).setText(TXMCoreMessages.common_property);
+		
+		// Display combo with list of Annotation Type
+		annotationTypesCombo = new ComboViewer(annotationArea, SWT.READ_ONLY);
+		annotationTypesCombo.setContentProvider(new ArrayContentProvider());
+		annotationTypesCombo.setLabelProvider(new SimpleLabelProvider() {
+			
+			@Override
+			public String getColumnText(Object element, int columnIndex) {
+				return ((AnnotationType) element).getName();
+			}
+			
+			@Override
+			public String getText(Object element) {
+				return ((AnnotationType) element).getName();
+			}
+		});
+		// annotationTypesCombo.getCombo().addKeyListener(new KeyListener() {
+		//
+		// @Override
+		// public void keyReleased(KeyEvent e) {
+		// if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+		// String name = annotationTypesCombo.getCombo().getText();
+		// if (currentKnowledgeRepository.getType(name) == null) {
+		// createNewType(e, name);
+		// } else {
+		// for (AnnotationType type : typesList) {
+		// if (name.equals(type.getId())) {
+		// StructuredSelection selection = new StructuredSelection(type);
+		// annotationTypesCombo.setSelection(selection, true);
+		// break;
+		// }
+		// }
+		// }
+		// }
+		// }
+		//
+		// @Override
+		// public void keyPressed(KeyEvent e) { }
+		// });
+		
+		gdata = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+		gdata.widthHint = 200;
+		
+		annotationTypesCombo.getCombo().setLayoutData(gdata);
+		annotationTypesCombo.setInput(typesList);
+		annotationTypesCombo.getCombo().select(0);
+		annotations.setViewAnnotation(typesList.get(0));
+		// for (int i = 0 ; i < typesList.size(); i++) {
+		// String name = typesList.get(i).getName();
+		// if ("word".equals(name)) {
+		// annotations.setViewAnnotation(typesList.get(i));
+		// annotationColumn.setText(name);
+		// }
+		// }
+		
+		annotationTypesCombo.addSelectionChangedListener(new ISelectionChangedListener() {
+			
+			@Override
+			public void selectionChanged(SelectionChangedEvent event) {
+				onAnnotationTypeSelected(event);
+			}
+		});
+		
+		addAnnotationTypeLink = new Button(annotationArea, SWT.PUSH);
+		addAnnotationTypeLink.setToolTipText(KRAnnotationUIMessages.addANewCategory);
+		addAnnotationTypeLink.setImage(IImageKeys.getImage(IImageKeys.ACTION_ADD));
+		addAnnotationTypeLink.setEnabled(true);
+		addAnnotationTypeLink.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		addAnnotationTypeLink.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (currentKnowledgeRepository == null) return;
+				if (!(currentKnowledgeRepository instanceof LocalKnowledgeRepository)) return;
+				
+				LocalKnowledgeRepository kr = (LocalKnowledgeRepository) currentKnowledgeRepository;
+				
+				InputDialog dialog = new InputDialog(e.widget.getDisplay().getActiveShell(), "New property", "Enter the new property name", "", null);
+				if (dialog.open() == InputDialog.OK) {
+					String name = dialog.getValue();
+					if (name.trim().length() == 0) return;
+					String id = AsciiUtils.buildId(name);
+					AnnotationType existingType = kr.getType(id);
+					if (existingType != null) {
+						Log.warning(NLS.bind("The ''{0}'' annotation type already exists. Please use another name ({1}).", id, name));
+						annotationTypesCombo.setSelection(new StructuredSelection(existingType));
+						return;
+					}
+					AnnotationType type = kr.addType(name, id, "", AnnotationEffect.TOKEN); //$NON-NLS-1$
+					typesList.add(type);
+					
+					if (annotationTypesCombo != null) annotationTypesCombo.refresh();
+					if (typesList.size() == 1) {
+						if (annotationTypesCombo != null) annotationTypesCombo.getCombo().select(typesList.size() - 1);
+						
+						annotations.setViewAnnotation(type);
+						annotations.setAnnotationOverlap(true);
+						try {
+							editor.refresh(false);
+						}
+						catch (Exception e1) {
+							// TODO Auto-generated catch block
+							e1.printStackTrace();
+						}
+						annotationArea.layout(true);
+						
+					}
+					else {
+						if (typesList.size() > 1) {
+							if (annotationTypesCombo != null) {
+								annotationTypesCombo.setSelection(new StructuredSelection(typesList.get(typesList.size() - 1)));
+							}
+						}
+					}
+					annotations.setViewAnnotation(type);
+					annotationTypesCombo.setSelection(new StructuredSelection(typesList.get(typesList.size() - 1)));
+					annotationArea.layout(true);
+					KRView.refresh();
+					updateAnnotationWidgetStates();
+				}
+				else {
+					Log.info("Creation aborted.");
+				}
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		equalLabel = new Label(annotationArea, SWT.NONE);
+		equalLabel.setText("="); //$NON-NLS-1$
+		equalLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		
+		annotationValuesText = new Text(annotationArea, SWT.BORDER);
+		annotationValuesText.setToolTipText(KRAnnotationUIMessages.enterAValueForAnId);
+		GridData gdata2 = new GridData(SWT.FILL, SWT.CENTER, false, false);
+		gdata2.widthHint = 200;
+		annotationValuesText.setLayoutData(gdata2);
+		annotationValuesText.addKeyListener(new KeyListener() {
+			
+			@Override
+			public void keyReleased(KeyEvent e) {
+				if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+					affectAnnotationToSelection(editor.getEditionPanel(0).getWordSelection());
+				}
+			}
+			
+			@Override
+			public void keyPressed(KeyEvent e) {}
+		});
+		
+		addTypedValueLink = new Button(annotationArea, SWT.PUSH);
+		addTypedValueLink.setText("..."); //$NON-NLS-1$
+		addTypedValueLink.setToolTipText(KRAnnotationUIMessages.selectAValueAmongTheList);
+		addTypedValueLink.setEnabled(true);
+		addTypedValueLink.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		addTypedValueLink.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (currentKnowledgeRepository == null) return;
+				if (!(currentKnowledgeRepository instanceof LocalKnowledgeRepository)) return;
+				
+				AnnotationType type = getSelectedAnnotationType();
+				if (type == null) return;
+				
+				LocalKnowledgeRepository kr = (LocalKnowledgeRepository) currentKnowledgeRepository;
+				
+				ListDialog dialog = new ListDialog(e.widget.getDisplay().getActiveShell());
+				String title = currentKnowledgeRepository.getString(editor.getCorpus().getLang(), "ConcordancesEditor_100"); //$NON-NLS-1$
+				if (title == null) title = KRAnnotationUIMessages.availableValuesForP0;
+				dialog.setTitle(ConcordanceUIMessages.bind(title, type.getName()));// +"valeurs de "+type.getName());
+				dialog.setContentProvider(new ArrayContentProvider());
+				dialog.setLabelProvider(new SimpleLabelProvider() {
+					
+					@Override
+					public String getColumnText(Object element, int columnIndex) {
+						if (element instanceof TypedValue) {
+							return ((TypedValue) element).getId();
+						}
+						return element.toString();
+					}
+				});
+				List<TypedValue> values;
+				try {
+					values = kr.getValues(type);
+				}
+				catch (Exception e1) {
+					e1.printStackTrace();
+					return;
+				}
+				dialog.setInput(values);
+				if (dialog.open() == InputDialog.OK) {
+					TypedValue value = (TypedValue) dialog.getResult()[0];
+					String name = value.getId();
+					if (name.trim().length() == 0) return;
+					
+					annotationValuesText.setText(name);
+				}
+				else {
+					
+				}
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		new Label(annotationArea, SWT.NONE).setText(" ");
+		
+		affectAnnotationButton = new Button(annotationArea, SWT.PUSH);
+		affectAnnotationButton.setText(KRAnnotationUIMessages.oK);
+		affectAnnotationButton.setToolTipText(KRAnnotationUIMessages.proceedToAnnotation);
+		affectAnnotationButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		affectAnnotationButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				affectAnnotationToSelection(editor.getEditionPanel(0).getWordSelection());
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		deleteAnnotationButton = new Button(annotationArea, SWT.PUSH);
+		deleteAnnotationButton.setText(KRAnnotationUIMessages.delete);
+		deleteAnnotationButton.setToolTipText(KRAnnotationUIMessages.delete);
+		deleteAnnotationButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		deleteAnnotationButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				deleteAnnotationValues(editor.getEditionPanel(0).getWordSelection());
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		Button closeButton = new Button(annotationArea, SWT.PUSH);
+		closeButton.setToolTipText(KRAnnotationUIMessages.closeTheToolbarWithoutSaving);
+		closeButton.setImage(IImageKeys.getImage(IImageKeys.ACTION_DELETE));
+		
+		closeButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				extension.closeArea(WordAnnotationToolbar.this, true);
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		updateAnnotationWidgetStates();
+		editor.layout(true);
+//		ext.getSaveButton().setEnabled(true);
+		return true;
+	}
+	
+	protected void onAnnotationTypeSelected(SelectionChangedEvent event) {
+		
+		IStructuredSelection sel = (IStructuredSelection) annotationTypesCombo.getSelection();
+		AnnotationType type = (AnnotationType) sel.getFirstElement();
+		if (type == null) return;
+		
+		if (type.getSize() != AnnotationType.ValuesSize.LARGE) {
+			try {
+				KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(type.getKnowledgeRepository());
+				typeValuesList = kr.getValues(type);
+			}
+			catch (Exception e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+		
+		annotations.setViewAnnotation(type);
+		annotations.setAnnotationOverlap(true);
+		try {
+			editor.refresh(false);
+		}
+		catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+		updateAnnotationWidgetStates();
+	}
+	
+	protected void createNewType(TypedEvent e, String typeName) {
+		
+		if (currentKnowledgeRepository == null) return;
+		if (!(currentKnowledgeRepository instanceof LocalKnowledgeRepository)) return;
+		
+		LocalKnowledgeRepository kr = (LocalKnowledgeRepository) currentKnowledgeRepository;
+		if (typeName == null) typeName = ""; //$NON-NLS-1$
+		InputDialog dialog = new InputDialog(e.widget.getDisplay().getActiveShell(), KRAnnotationUIMessages.nouvelleProprit, KRAnnotationUIMessages.nomDeLaPropritPatternEqualsazaz09Plus, typeName,
+				null);
+		if (dialog.open() == InputDialog.OK) {
+			String name = dialog.getValue();
+			if (name.trim().length() == 0) return;
+			String baseid = AsciiUtils.buildId(name);
+			String id = AsciiUtils.buildId(name);
+			int c = 1;
+			while (kr.getType(id) != null) {
+				id = baseid + "_" + (c++); //$NON-NLS-1$
+			}
+			AnnotationType type = kr.addType(name, id, "", AnnotationEffect.TOKEN); //$NON-NLS-1$
+			typesList.add(type);
+			annotationTypesCombo.refresh();
+			StructuredSelection selection = new StructuredSelection(type);
+			annotationTypesCombo.setSelection(selection, true);
+			
+			// if (annotationTypesCombo != null) annotationTypesCombo.refresh();
+			// if (typesList.size() == 1) {
+			// if (annotationTypesCombo != null) annotationTypesCombo.getCombo().select(0);
+			// annotations.setViewAnnotation(type);
+			// annotations.setAnnotationOverlap(true);
+			// try {
+			// editor.refresh(false);
+			// } catch (Exception e1) {
+			// // TODO Auto-generated catch block
+			// e1.printStackTrace();
+			// }
+			// annotationArea.layout(true);
+			// } else {
+			// if (typesList.size() > 1) {
+			// if (annotationTypesCombo != null) {
+			// annotationTypesCombo.getCombo().select(typesList.size()-1);
+			// }
+			// }
+			// }
+			// KRView.refresh();
+			// updateAnnotationWidgetStates();
+			
+			// onAnnotationTypeSelected(null);
+		}
+		else {
+			Log.info("Creation aborted.");
+		}
+	}
+	
+	@Override
+	public boolean save() {
+		try {
+			AnnotationManager am = KRAnnotationEngine.getAnnotationManager(WordAnnotationToolbar.this.corpus);
+			if (am != null && am.hasChanges()) {
+				// && MessageDialog.openConfirm(e.display.getActiveShell(), "Confirm annotation save", "Saving annotation will close this editor. Are you sure you want to save annotations right now
+				// ?")
+				JobHandler saveJob = SaveAnnotations.save(WordAnnotationToolbar.this.corpus.getMainCorpus());
+				if (saveJob == null || saveJob.getResult() == Status.CANCEL_STATUS) {
+					Log.warning("Fail to save annotations of the corpus.");
+					return false;
+				}
+				else {
+					return true; // something was saved
+				}
+			}
+			else {
+				return false;
+			}
+		}
+		catch (Exception ex) {
+			ex.printStackTrace();
+			return false;
+		}
+	}
+	
+	@Override
+	public boolean hasChanges() {
+		AnnotationManager am;
+		try {
+			am = KRAnnotationEngine.getAnnotationManager(corpus);
+			if (am != null && am.hasChanges()) {
+				return am.hasChanges();
+			}
+			else {
+				return false;
+			}
+		}
+		catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+			return false;
+		}
+	}
+	
+	@Override
+	public boolean notifyStartOfCompute() throws Exception {
+		if (annotationArea == null) return false;
+		if (annotationArea.isDisposed()) return false;
+		
+		AnnotationType type = getSelectedAnnotationType();
+		if (type != null) {
+			annotations.setViewAnnotation(type);
+			annotations.setAnnotationOverlap(true);
+		}
+		
+		return true;
+	}
+	
+	@Override
+	public boolean notifyEndOfCompute() throws Exception {
+		return true;
+	}
+	
+	@Override
+	public boolean isAnnotationEnable() {
+		return annotationArea != null;
+	}
+	
+	@Override
+	public void notifyStartOfRefresh() throws Exception {
+		if (annotationArea == null) return;
+		if (annotationArea.isDisposed()) return;
+		
+		Page currentPage = editor.getEditionPanel(0).getCurrentPage();
+		if (currentPage == null) return;
+		
+		String startID = currentPage.getWordId();
+		Page nextPage = currentPage.getEdition().getNextPage(currentPage);
+		String endID = nextPage.getWordId();
+		
+		annotations.computeStrings(startID, endID);
+		
+		updateAnnotationWidgetStates();
+		
+	}
+	
+	@Override
+	protected void _close() {
+		if (!annotationArea.isDisposed()) annotationArea.dispose();
+		extension.layout();
+	}
+	
+	@Override
+	public void notifyEndOfRefresh() throws Exception {
+		// TODO Auto-generated method stub
+	}
+	
+	@Override
+	public void notifyStartOfCreatePartControl() throws Exception {
+		// TODO Auto-generated method stub
+	}
+	
+	@Override
+	public Class<? extends TXMResult> getAnnotatedTXMResultClass() {
+		return org.txm.objects.Text.class;
+	}
+	
+	@Override
+	public boolean isDirty() {
+		if (annotManager != null) {
+			return annotManager.isDirty();
+		}
+		return false;
+	}
+	
+	@Override
+	public boolean discardChanges() {
+		return false;
+	}
+	
+	@Override
+	public boolean needToUpdateIndexes() {
+		return KRAnnotationPreferences.getInstance().getBoolean(KRAnnotationPreferences.UPDATE);
+	}
+	
+	@Override
+	public boolean needToUpdateEditions() {
+		return KRAnnotationPreferences.getInstance().getBoolean(KRAnnotationPreferences.UPDATE_EDITION);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/edition/WordAnnotationToolbar.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/views/knowledgerepositories/KRView.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/views/knowledgerepositories/KRView.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/views/knowledgerepositories/KRView.java	(revision 3653)
@@ -0,0 +1,385 @@
+// Copyright © 2010-2020 ENS de Lyon., University of Franche-Comté
+// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
+// Lyon 2, University of Franche-Comté, University of Nice
+// Sophia Antipolis, University of Paris 3.
+// 
+// The TXM platform 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 2 of the License, or (at your option) any
+// later version.
+// 
+// The TXM platform 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 the TXM platform. If not, see
+// http://www.gnu.org/licenses.
+// 
+// 
+// 
+// $LastChangedDate:$
+// $LastChangedRevision:$
+// $LastChangedBy:$ 
+//
+package org.txm.annotation.kr.rcp.views.knowledgerepositories;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Arrays;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.part.ViewPart;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.KnowledgeRepository;
+import org.txm.annotation.kr.core.repository.KnowledgeRepositoryManager;
+import org.txm.annotation.kr.core.repository.LocalKnowledgeRepository;
+import org.txm.annotation.kr.core.repository.SQLKnowledgeRepository;
+import org.txm.annotation.kr.core.repository.TypedValue;
+import org.txm.annotation.kr.rcp.commands.InitializeKnowledgeRepository;
+import org.txm.annotation.kr.rcp.commands.krview.Copy;
+import org.txm.annotation.kr.rcp.commands.krview.Informations;
+import org.txm.annotation.kr.rcp.commands.krview.Reload;
+import org.txm.rcp.IImageKeys;
+import org.txm.rcp.messages.TXMUIMessages;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.corpus.CorpusManager;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+/**
+ * Display the Knowledge repositories currently loaded
+ * 
+ * author mdecorde.
+ */
+public class KRView extends ViewPart {
+
+	/** The empty list to filled the view at startup. */
+	ArrayList<Object> empty = new ArrayList<Object>();
+
+	/** The composites. */
+	Control[] composites = new Control[3];
+
+	/** The tv. */
+	TreeViewer tv;
+
+	/** The ID. */
+	public static String ID = KRView.class.getName();
+
+	/**
+	 * Instantiates a new queries view.
+	 */
+	public KRView() {
+	}
+
+	/**
+	 * Refresh.
+	 */
+	public static void refresh() {
+		KRView baseView = (KRView) PlatformUI.getWorkbench()
+				.getActiveWorkbenchWindow().getActivePage().findView(
+						KRView.ID);
+		if (baseView != null)
+			baseView.tv.refresh();
+	}
+
+	/**
+	 * Reload.
+	 */
+	public static void reload() {
+		KRView baseView = (KRView) PlatformUI.getWorkbench()
+				.getActiveWorkbenchWindow().getActivePage().findView(
+						KRView.ID);
+		if (baseView != null)
+			baseView._reload();
+	}
+
+	/**
+	 * _reload.
+	 */
+	public void _reload() {
+		
+		KnowledgeRepository[] repos = KnowledgeRepositoryManager.getKnowledgeRepositories();
+		if (repos == null) return;
+		if (tv != null) { 
+			tv.setInput(repos);
+			refresh();
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
+	 */
+	@Override
+	public void createPartControl(Composite parent) {
+
+		parent.setLayout(new GridLayout(1, true));
+		Button refresh = new Button(parent, SWT.PUSH);
+		refresh.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true,
+				false));
+		refresh.setText("⟲");
+		refresh.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent arg0) {
+				// force loading KR of all corpora
+				try {
+					for (MainCorpus corpus : CorpusManager.getCorpusManager().getCorpora().values()) {
+						for (KnowledgeRepository kr : InitializeKnowledgeRepository.get(corpus.getMainCorpus())) {
+							kr.checkConnection();
+						}
+					}
+				} catch (Exception e) {
+					e.printStackTrace();
+					return;
+				}
+
+				_reload();
+			}
+
+			@Override
+			public void widgetDefaultSelected(SelectionEvent arg0) { }
+		});
+
+		tv = new TreeViewer(parent);
+		tv.getTree().setLayoutData(
+				new GridData(GridData.FILL, GridData.FILL, true, true));
+		
+		tv.setContentProvider(new KRTreeProvider());
+		tv.setLabelProvider(new KRLabelProvider());
+		
+		_reload();
+
+		tv.addDoubleClickListener(new IDoubleClickListener() {
+			@Override
+			public void doubleClick(DoubleClickEvent event) {
+				TreeSelection selection = (TreeSelection) tv.getSelection();
+				Informations.show(selection);
+			}
+		});
+
+//		TreeViewerColumn name = new TreeViewerColumn(tv, SWT.NONE);
+//		name.getColumn().setText("name");
+//		TreeViewerColumn desc = new TreeViewerColumn(tv, SWT.NONE);
+//		desc.getColumn().setText("desc");
+		
+		MenuManager menuManager = new MenuManager();
+		Menu menu = menuManager.createContextMenu(tv.getTree());
+
+		// Set the MenuManager
+		tv.getTree().setMenu(menu);
+		getSite().registerContextMenu(menuManager, tv);
+		// Make the selection available
+		getSite().setSelectionProvider(tv);
+		
+		IContextService contextService = (IContextService)getSite().getService(IContextService.class);
+		contextService.activateContext("org.txm.rcp.annotation.krview");
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
+	 */
+	@Override
+	public void setFocus() {
+		
+	}
+
+	/**
+	 * The Class TxmObjectLabelProvider.
+	 */
+	public class KRLabelProvider extends LabelProvider {
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
+		 */
+		@Override
+		public String getText(Object element) {
+			if (element instanceof KnowledgeRepository)
+				return ((KnowledgeRepository) element).getName();
+			else if (element instanceof AnnotationType)
+				return ((AnnotationType) element).getId()+((AnnotationType) element).getEffect().toSuffix();
+			else if (element instanceof TypedValue)
+				return ((TypedValue) element).getStandardName();
+			return NLS.bind(TXMUIMessages.errorWithElementP0, element);
+		}
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.jface.viewers.LabelProvider#getImage(java.lang.Object)
+		 */
+		@Override
+		public final Image getImage(Object element) {
+			if (element instanceof SQLKnowledgeRepository)
+				return IImageKeys.getImage(IImageKeys.WORLD);
+			return null;
+		}
+	}
+
+	/**
+	 * The Class TxmObjectTreeProvider.
+	 */
+	public class KRTreeProvider implements ITreeContentProvider {
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
+		 */
+		@Override
+		public Object[] getChildren(Object element) {
+			if (element instanceof KnowledgeRepository) {
+				KnowledgeRepository kr = ((KnowledgeRepository) element);
+				List<AnnotationType> types = kr.getAllAnnotationTypes();
+
+				return types.toArray();
+			} else if (element instanceof AnnotationType) {
+				AnnotationType t = ((AnnotationType) element);
+				KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(t.getKnowledgeRepository());
+				if (kr instanceof LocalKnowledgeRepository) {
+					LocalKnowledgeRepository krl = (LocalKnowledgeRepository) kr;
+					try {
+						return krl.getValues(t).toArray();
+					} catch (Exception e) {
+						Log.warning(NLS.bind("Error while reading the {0} KR values for the {1} type.", kr, t));
+						Log.printStackTrace(e);
+					}
+				}
+				return new Object[0];
+			} else {
+				return new Object[0];
+			}
+		}
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
+		 */
+		@Override
+		public Object getParent(Object element) {
+			if (element instanceof KnowledgeRepository) {
+				return null;
+			} else if (element instanceof AnnotationType) {
+				return ((AnnotationType)element).getKnowledgeRepository();
+			} else {
+				return null;
+			}
+		}
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
+		 */
+		@Override
+		public boolean hasChildren(Object element) {
+			if (element instanceof KnowledgeRepository) {
+				KnowledgeRepository kr = ((KnowledgeRepository) element);
+				List<AnnotationType> types = kr.getAllAnnotationTypes();
+				return types.size() > 0;
+			} else if (element instanceof KnowledgeRepository[]) {
+				return ((KnowledgeRepository[])element).length > 0;
+			} else if (element instanceof AnnotationType) {
+				AnnotationType t = ((AnnotationType) element);
+				KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(t.getKnowledgeRepository());
+				
+				if (kr instanceof LocalKnowledgeRepository) {
+					LocalKnowledgeRepository krl = (LocalKnowledgeRepository) kr;
+					try {
+						return krl.hasValues(t);
+					} catch (Exception e) {
+						Log.warning(NLS.bind("Error while reading the {0} KR values for the {1} type.", kr, t));
+						Log.printStackTrace(e);
+					}
+				}
+				return false;
+			}  else {
+				return false;
+			}
+		}
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
+		 */
+		@Override
+		public Object[] getElements(Object element) {
+			if (element instanceof KnowledgeRepository) {
+				KnowledgeRepository kr = ((KnowledgeRepository) element);
+				List<AnnotationType> types = kr.getAllAnnotationTypes();
+				return types.toArray();
+			} else if (element instanceof KnowledgeRepository[]) {
+				return ((KnowledgeRepository[])element);
+			} else {
+				return new Object[0];
+			}
+		}
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
+		 */
+		@Override
+		public void dispose() { }
+
+		/* (non-Javadoc)
+		 * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
+		 */
+		@Override
+		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {	}
+	}
+
+	public static void showType(AnnotationType type) {
+		
+		TreeViewer tv = getTree();
+		if (tv != null) {
+			StructuredSelection selection = new StructuredSelection(type);
+			tv.expandToLevel(selection, AbstractTreeViewer.ALL_LEVELS);
+			tv.setSelection(selection);
+		} else {
+			// call org.eclipse.ui.handlers.ShowViewHandler
+			// extends the command to select the type ?
+		}
+	}
+
+	public static TreeViewer getTree() {
+		KRView baseView = (KRView) PlatformUI.getWorkbench()
+				.getActiveWorkbenchWindow().getActivePage().findView(
+						KRView.ID);
+		if (baseView != null)
+			return baseView.tv;
+		
+		return null;
+	}
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/views/knowledgerepositories/KRView.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/SimpleKRAnnotation.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/SimpleKRAnnotation.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/SimpleKRAnnotation.java	(revision 3653)
@@ -0,0 +1,818 @@
+package org.txm.annotation.kr.rcp.concordance;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Vector;
+import java.util.logging.Level;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.ListDialog;
+import org.txm.annotation.kr.core.Annotation;
+import org.txm.annotation.kr.core.AnnotationManager;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.annotation.kr.core.preferences.KRAnnotationPreferences;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.KnowledgeRepository;
+import org.txm.annotation.kr.core.repository.KnowledgeRepositoryManager;
+import org.txm.annotation.kr.core.repository.LocalKnowledgeRepository;
+import org.txm.annotation.kr.core.repository.TypedValue;
+import org.txm.annotation.kr.rcp.commands.InitializeKnowledgeRepository;
+import org.txm.annotation.kr.rcp.commands.SaveAnnotations;
+import org.txm.annotation.kr.rcp.messages.KRAnnotationUIMessages;
+import org.txm.annotation.kr.rcp.views.knowledgerepositories.KRView;
+import org.txm.annotation.rcp.editor.AnnotationArea;
+import org.txm.annotation.rcp.editor.AnnotationExtension;
+import org.txm.concordance.core.functions.Concordance;
+import org.txm.concordance.core.functions.Line;
+import org.txm.concordance.rcp.editors.ConcordanceEditor;
+import org.txm.concordance.rcp.editors.ConcordanceEditor.ConcordanceColumnSizeControlListener;
+import org.txm.concordance.rcp.messages.ConcordanceUIMessages;
+import org.txm.core.messages.TXMCoreMessages;
+import org.txm.core.results.TXMResult;
+import org.txm.objects.Match;
+import org.txm.rcp.IImageKeys;
+import org.txm.rcp.editors.TXMEditor;
+import org.txm.rcp.swt.GLComposite;
+import org.txm.rcp.swt.dialog.ConfirmDialog;
+import org.txm.rcp.swt.provider.SimpleLabelProvider;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.CQPCorpus;
+import org.txm.utils.logger.Log;
+
+/**
+ * TODO merge some methods with the KRannotationToolbar
+ * 
+ * @author mdecorde
+ *
+ */
+public class SimpleKRAnnotation extends AnnotationArea {
+	
+	ConcordanceEditor editor;
+	
+	public SimpleKRAnnotation() {
+		
+	}
+	
+	/**
+	 * the limit number of annotation when a confirm dialog box is shown
+	 */
+	protected static final int NALERTAFFECTANNOTATIONS = 100;
+	
+	public static final String EMPTYTEXT = ""; //$NON-NLS-1$
+	
+	/** The annotation service */
+	protected AnnotationManager annotManager;
+	
+	// boolean annotation_expert_mode = TxmPreferences.getBoolean(AnnotationPreferencePage.MODE, false);
+	
+	protected Point annotationSize;
+	
+	protected Text annotationValuesText;
+	
+	protected ComboViewer annotationTypesCombo;
+	
+	protected TableColumn annotationColumn;
+	
+	protected Combo addRemoveCombo;
+	
+	protected Combo affectCombo;
+	
+	protected Button affectAnnotationButton;
+	
+	protected KnowledgeRepository currentKnowledgeRepository = null;
+	
+	protected Vector<AnnotationType> typesList = new Vector<>();
+	
+	protected Label withLabel;
+	
+	protected AnnotationType tagAnnotationType; // the tag annotation type if annotation mode is simple
+	
+	//protected TypedValue value_to_add;
+	
+	protected Concordance concordance;
+	
+	private CQPCorpus corpus;
+	
+	private ConcordanceAnnotations annotations = null;
+	
+	private Button addTypedValueLink;
+
+	private TableViewerColumn annotationColumnViewer;
+	
+	@Override
+	public String getName() {
+		return KRAnnotationUIMessages.squencesDeMotsCatgorie;
+	}
+	
+	@Override
+	public boolean install(TXMEditor<? extends TXMResult> txmeditor, AnnotationExtension ext, Composite parent, int position) throws Exception {
+		
+		this.extension = ext;
+		this.editor = (ConcordanceEditor) txmeditor;
+		this.concordance = this.editor.getConcordance();
+		this.corpus = concordance.getCorpus();
+		this.annotations = new ConcordanceAnnotations(this.editor.getConcordance());
+		annotations.computeLines(this.editor.getConcordance().getLines()); // pre-compute the annotation lines ot avoid breaking the sort and co.
+		this.annotManager = KRAnnotationEngine.getAnnotationManager(corpus);
+		
+		TableViewer viewer = this.editor.getLineTableViewer();
+		
+		// RESULT
+		
+		if (position < 0) {
+			position = 3 + extension.getNumberOfAnnotationArea(); // after keyword column and previous annotation columns
+		}
+		
+		this.annotationColumnViewer = new TableViewerColumn(viewer, SWT.CENTER, position);
+		annotationColumn = annotationColumnViewer.getColumn();
+		annotationColumn.setText(KRAnnotationUIMessages.category);
+		annotationColumn.setToolTipText(KRAnnotationUIMessages.keywordsAnnotation);
+		annotationColumn.pack();
+		annotationColumn.setAlignment(SWT.CENTER);
+		
+		annotationColumn.addControlListener(new ConcordanceColumnSizeControlListener(annotationColumn));
+		annotationColumnViewer.setLabelProvider(new ColumnLabelProvider() {
+			
+			@Override
+			public String getText(Object element) {
+				Line line = (Line) element;
+				AnnotationLine annotationLine = annotations.getAnnotationLine(line);
+				if (annotationLine == null) return EMPTYTEXT;
+				if (annotationLine.getAnnotation() != null) {
+					String value = annotationLine.getAnnotationValue().getStandardName();
+					Annotation a = annotationLine.getAnnotation();
+					if (value == null) value = a.getValue();
+					
+					if (a.getStart() < line.matchGetStart() - line.getLeftContextSize()) {
+						value = "… " + value; //$NON-NLS-1$
+					}
+					
+					if (a.getEnd() > line.matchGetEnd() + line.getRightContextSize()) {
+						value = value + " …"; //$NON-NLS-1$
+					}
+					return value;
+				}
+				else {
+					return EMPTYTEXT;
+				}
+			}
+		});
+		
+		List<KnowledgeRepository> krs = InitializeKnowledgeRepository.get(corpus.getMainCorpus());
+		typesList.clear();
+		Log.fine("Corpus KRs: " + krs); //$NON-NLS-1$
+		
+		KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(corpus.getMainCorpus().getName());
+		if (kr == null) {
+			HashMap<String, HashMap<String, ?>> conf = new HashMap<>();
+			kr = KnowledgeRepositoryManager.createKnowledgeRepository(corpus.getMainCorpus().getName(), conf);
+		}
+		
+		currentKnowledgeRepository = kr;
+		Log.fine(" KR: " + kr); //$NON-NLS-1$
+		List<AnnotationType> krtypes = kr.getAllAnnotationTypes();
+		
+		boolean createTagAnnotationType = true;
+		for (AnnotationType type : krtypes) {
+			if (type.getName().equals("span")) { //$NON-NLS-1$
+				createTagAnnotationType = false;
+			}
+		}
+		if (createTagAnnotationType) {
+			tagAnnotationType = kr.addType("span", "span");// corresponds to an "undef" type //$NON-NLS-1$ //$NON-NLS-2$
+			typesList.add(tagAnnotationType);
+		}
+		else {
+			tagAnnotationType = kr.getType("span"); //$NON-NLS-1$
+		}
+		annotations.setViewAnnotation(tagAnnotationType);
+		
+		Log.fine(NLS.bind(KRAnnotationUIMessages.availableAnnotationTypesColonP0, typesList));
+		
+		annotationArea = new GLComposite(parent, SWT.NONE, KRAnnotationUIMessages.concordanceAnnotationArea);
+		annotationArea.getLayout().numColumns = 12;
+		annotationArea.getLayout().horizontalSpacing = 2;
+		annotationArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+		
+		addRemoveCombo = new Combo(annotationArea, SWT.READ_ONLY);
+		String affectLabel = currentKnowledgeRepository.getString(getLocale(), "ConcordancesEditor_22"); //$NON-NLS-1$
+		if (affectLabel == null) affectLabel = KRAnnotationUIMessages.affect;
+		String removeLabel = currentKnowledgeRepository.getString(getLocale(), "ConcordancesEditor_24"); //$NON-NLS-1$
+		if (removeLabel == null) removeLabel = KRAnnotationUIMessages.delete;
+		String items[] = { affectLabel, removeLabel };
+		addRemoveCombo.setItems(items);
+		addRemoveCombo.select(0);
+		addRemoveCombo.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (addRemoveCombo.getSelectionIndex() == 0) { // add
+					annotationValuesText.setEnabled(true);
+					String withLabelText = currentKnowledgeRepository.getString(getLocale(), "ConcordancesEditor_83"); //$NON-NLS-1$
+					if (withLabelText == null) withLabelText = KRAnnotationUIMessages.withTheCategory;
+					withLabel.setText(withLabelText);
+				}
+				else { // remove
+					annotationValuesText.setEnabled(false);
+					withLabel.setText(""); //$NON-NLS-1$
+				}
+				withLabel.redraw();
+				annotationArea.layout();
+				updateAnnotationWidgetStates();
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		GridData gdata = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+		//gdata.widthHint = 100;
+		addRemoveCombo.setLayoutData(gdata);
+		
+		withLabel = new Label(annotationArea, SWT.NONE);
+		String withLabelText = currentKnowledgeRepository.getString(getLocale(), "ConcordancesEditor_83"); //$NON-NLS-1$
+		if (withLabelText == null) withLabelText = KRAnnotationUIMessages.withTheCategory;
+		withLabel.setText(withLabelText);
+		withLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		
+		annotationValuesText = new Text(annotationArea, SWT.BORDER);
+		annotationValuesText.setToolTipText(KRAnnotationUIMessages.enterAValueForAnId);
+		GridData gdata2 = new GridData(SWT.FILL, SWT.CENTER, false, false);
+		gdata2.widthHint = 200;
+		annotationValuesText.setLayoutData(gdata2);
+		annotationValuesText.addKeyListener(new KeyListener() {
+			
+			@Override
+			public void keyReleased(KeyEvent e) {
+				if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+					affectAnnotationToSelection(editor.getLineTableViewer().getSelection());
+				}
+			}
+			
+			@Override
+			public void keyPressed(KeyEvent e) {}
+		});
+		
+		if (currentKnowledgeRepository instanceof LocalKnowledgeRepository) {
+			addTypedValueLink = new Button(annotationArea, SWT.PUSH);
+			addTypedValueLink.setText("..."); //$NON-NLS-1$
+			addTypedValueLink.setToolTipText(KRAnnotationUIMessages.openTheListOfCategories);
+			addTypedValueLink.setEnabled(true);
+			addTypedValueLink.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+			addTypedValueLink.addSelectionListener(new SelectionListener() {
+				
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					if (currentKnowledgeRepository == null) return;
+					if (!(currentKnowledgeRepository instanceof LocalKnowledgeRepository)) return;
+					
+					AnnotationType type = getSelectedAnnotationType();
+					if (type == null) return;
+					
+					LocalKnowledgeRepository kr = (LocalKnowledgeRepository) currentKnowledgeRepository;
+					
+					ListDialog dialog = new ListDialog(e.widget.getDisplay().getActiveShell());
+					dialog.setTitle(KRAnnotationUIMessages.listOfCategories);// +"valeurs de "+type.getName());
+					dialog.setContentProvider(new ArrayContentProvider());
+					dialog.setLabelProvider(new SimpleLabelProvider() {
+						
+						@Override
+						public String getColumnText(Object element, int columnIndex) {
+							if (element instanceof TypedValue)
+								return ((TypedValue) element).getId();
+							return element.toString();
+						}
+					});
+					List<TypedValue> values;
+					try {
+						values = kr.getValues(type);
+					}
+					catch (Exception e1) {
+						e1.printStackTrace();
+						return;
+					}
+					dialog.setInput(values);
+					if (dialog.open() == InputDialog.OK) {
+						TypedValue value = (TypedValue) dialog.getResult()[0];
+						String name = value.getId();
+						if (name.trim().length() == 0) return;
+						
+						annotationValuesText.setText(name);
+					}
+					else {
+						
+					}
+				}
+				
+				@Override
+				public void widgetDefaultSelected(SelectionEvent e) {}
+			});
+		}
+		
+		affectCombo = new Combo(annotationArea, SWT.READ_ONLY);
+		affectCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		String items2[] = { KRAnnotationUIMessages.selectedLines, KRAnnotationUIMessages.allLines };
+		affectCombo.setItems(items2);
+		affectCombo.select(0);
+		gdata = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+		//gdata.widthHint = 200;
+		affectCombo.setLayoutData(gdata);
+		
+		affectAnnotationButton = new Button(annotationArea, SWT.PUSH);
+		affectAnnotationButton.setText(KRAnnotationUIMessages.oK);
+		affectAnnotationButton.setToolTipText(KRAnnotationUIMessages.proceedToAnnotation);
+		affectAnnotationButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		affectAnnotationButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				int isel = affectCombo.getSelectionIndex();
+				if (isel == 0) { // selected line
+					affectAnnotationToSelection(editor.getLineTableViewer().getSelection());
+				}
+				else { // all
+					try {
+						List<? extends Match> matches = concordance.getMatches();
+						affectMatchesToSelection(matches);
+					}
+					catch (Exception e1) {
+						Log.severe(NLS.bind(KRAnnotationUIMessages.errorWhileAnnotatingConcordanceColonP0, e1.getLocalizedMessage()));
+						Log.printStackTrace(e1);
+						return;
+					}
+				}
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		Button closeButton = new Button(annotationArea, SWT.PUSH);
+		closeButton.setToolTipText(KRAnnotationUIMessages.closeTheToolbarWithoutSaving);
+		closeButton.setImage(IImageKeys.getImage(IImageKeys.ACTION_DELETE));
+		closeButton.setLayoutData(new GridData(GridData.END, GridData.CENTER, true, false));
+		closeButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				extension.closeArea(SimpleKRAnnotation.this, true);
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		updateAnnotationWidgetStates();
+		editor.layout(true);
+		
+//		ext.getSaveButton().setEnabled(true);
+		return true;
+	}
+	
+	protected void affectAnnotationToSelection(ISelection selection) {
+		
+		final IStructuredSelection lineSelection = (IStructuredSelection) selection;
+		List<Line> lines = lineSelection.toList();
+		ArrayList<Match> matches = new ArrayList<>();
+		for (Line l : lines) {
+			matches.add(l.getMatch());
+		}
+		
+		affectMatchesToSelection(matches);
+	}
+	
+	protected AnnotationType getSelectedAnnotationType() {
+		if (annotationTypesCombo != null) {
+			IStructuredSelection isel = (IStructuredSelection) annotationTypesCombo.getSelection();
+			if (isel.isEmpty()) {
+				return null;
+			}
+			return (AnnotationType) isel.getFirstElement();
+		}
+		else { // simple mode
+			return tagAnnotationType;
+		}
+	}
+	
+	protected void affectMatchesToSelection(final List<? extends Match> matches) {
+		final AnnotationType type = getSelectedAnnotationType();
+		final String svalue = annotationValuesText.getText();
+		final boolean doAffect = addRemoveCombo.getSelectionIndex() == 0; // add is default
+		
+		JobHandler job = new JobHandler(KRAnnotationUIMessages.annotatingConcordanceSelection, true) {
+			
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				this.runInit(monitor);
+				try {
+					if (doAffect) {
+						affectAnnotationValues(matches, type, svalue, this);
+					}
+					else {
+						deleteAnnotationValues(matches, type, this);
+					}
+				}
+				catch (Exception e) {
+					Log.severe(NLS.bind(KRAnnotationUIMessages.errorWhileAnnotatingConcordanceSelectionColonP0, e));
+					Log.printStackTrace(e);
+					return Status.CANCEL_STATUS;
+				}
+				catch (ThreadDeath td) {
+					Log.info(KRAnnotationUIMessages.annotationCanceledByUser);
+					return Status.CANCEL_STATUS;
+				}
+				
+				return Status.OK_STATUS;
+			}
+		};
+		job.startJob(true);
+	}
+	
+	public void updateAnnotationWidgetStates() {
+		if (annotationArea == null) return; // :)
+		annotationArea.getDisplay().syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				if (addRemoveCombo.getSelectionIndex() == 0) { // add is default
+					
+					if (getSelectedAnnotationType() != null) {
+						annotationValuesText.setEnabled(true);
+						
+						affectAnnotationButton.setEnabled(true);
+						affectCombo.setEnabled(true);
+					}
+					else {
+						annotationValuesText.setEnabled(false);
+						
+						affectAnnotationButton.setEnabled(false);
+						affectCombo.setEnabled(false);
+					}
+				}
+				else {
+					annotationValuesText.setEnabled(false);
+					
+					if (getSelectedAnnotationType() != null) {
+						affectAnnotationButton.setEnabled(true);
+						affectCombo.setEnabled(true);
+					}
+					else {
+						affectAnnotationButton.setEnabled(false);
+						affectCombo.setEnabled(false);
+					}
+				}
+				
+				
+				if (addTypedValueLink != null) {
+					addTypedValueLink.setEnabled(getSelectedAnnotationType() != null);
+				}
+			}
+		});
+	}
+	
+	protected void deleteAnnotationValues(List<? extends Match> matches, AnnotationType type, JobHandler job) {
+		
+		if (matches.size() == 0) {
+			Log.warning("No lines selected. Aborting.");
+			return;
+		}
+		
+		if (type == null) {
+			return;
+		}
+		
+		try {
+			if (annotManager != null && annotManager.deleteAnnotations(type, matches, job)) {
+				if (Log.getLevel().intValue() < Level.INFO.intValue()) annotManager.checkData();
+				// editor.fillDisplayArea(false);
+			}
+			else {
+				return;
+			}
+		}
+		catch (Exception e1) {
+			Log.warning(NLS.bind(KRAnnotationUIMessages.errorWhileDeletingAnnotationColonP0, e1));
+			Log.printStackTrace(e1);
+			return;
+		}
+		
+		job.syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				try {
+					notifyStartOfRefresh();
+					annotationColumnViewer.getViewer().refresh();
+				}
+				catch (Exception e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+			}
+		});
+	}
+	
+	protected void affectAnnotationValues(final List<? extends Match> matches, final AnnotationType type, final String svalue, JobHandler job) {
+		TypedValue value_to_add = null; // reset
+		if (matches == null || matches.size() == 0) {
+			Log.warning("No line selected. Aborting.");
+			return;
+		}
+		if (type == null) return; // no type, no annotation
+		
+		job.syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				if (matches.size() > NALERTAFFECTANNOTATIONS) {
+					ConfirmDialog dialog = new ConfirmDialog(Display.getCurrent().getActiveShell(),
+							"confirm_annotate",  //$NON-NLS-1$
+							KRAnnotationUIMessages.confirmAnnotationAffectation,
+							NLS.bind(KRAnnotationUIMessages.youAreAboutToAnnotateP0ElementsContinue, matches.size()));
+					
+					if (dialog.open() == ConfirmDialog.CANCEL) {
+						Log.info("Annotation aborted by user.");
+						matches.clear();
+					}
+				}
+			}
+		});
+		
+		// get value from combo text value
+		Log.fine(NLS.bind(KRAnnotationUIMessages.lookingForTypedValueWithIdEqualsP0, svalue));
+		final KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(type.getKnowledgeRepository());
+		value_to_add = kr.getValue(type, svalue);
+		
+		
+		if (value_to_add == null && kr instanceof LocalKnowledgeRepository) { // create or not the annotation is simple mode
+			job.syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					String title = kr.getString(getLocale(), "ConcordancesEditor_110"); //$NON-NLS-1$
+					String content = kr.getString(getLocale(), "ConcordancesEditor_112"); //$NON-NLS-1$
+					if (title == null) title = KRAnnotationUIMessages.newValueP0ForCategoryP1;
+					if (content == null) content = KRAnnotationUIMessages.theValueP0IsNotAssociatedWithTheCategoryP1AssociateIt;
+					ConfirmDialog dialog = new ConfirmDialog(Display.getCurrent().getActiveShell(),
+							"create_value", //$NON-NLS-1$
+							ConcordanceUIMessages.bind(title, svalue, type.getName()),
+							ConcordanceUIMessages.bind(content, svalue, type.getName()));
+					if (dialog.open() == ConfirmDialog.CANCEL) {
+						Log.info("Annotation aborted by user.");
+						return;
+					}
+					else {
+						kr.addValue(svalue, svalue, type.getId());
+						KRView.refresh();
+					}
+				}
+			});
+		}
+		
+		value_to_add = kr.getValue(type, svalue);
+		
+		if (value_to_add == null && kr instanceof LocalKnowledgeRepository) return; // canceled
+		
+		if (value_to_add == null) {
+			job.syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					String mess = ConcordanceUIMessages.bind(KRAnnotationUIMessages.noValueFoundWithTheP0Id, svalue);
+					Log.warning(mess);
+					MessageDialog.openError(Display.getCurrent().getActiveShell(), "Annotation canceled", mess);
+				}
+			});
+			return;
+		}
+		
+		Log.info(TXMCoreMessages.bind(KRAnnotationUIMessages.AffectP0ToSelectionEqualsP1, value_to_add.getId(), value_to_add.getTypeID(), matches.size()));
+		
+		// finally we can 'try' to create the annotations \o/
+		try {
+			HashMap<Match, List<Annotation>> existingAnnots = annotManager.createAnnotations(type, value_to_add, matches, job);
+			
+			// did we had problems ?
+			if (existingAnnots != null && existingAnnots.size() > 0) {
+				String message = NLS.bind(KRAnnotationUIMessages.couldNotAnnotateTheValueP0OnCertainSequences, value_to_add.getStandardName());
+				for (Match m : existingAnnots.keySet()) {
+					message += NLS.bind(KRAnnotationUIMessages.theSequenceP0IsOverlappingWith, m);
+					
+					for (Annotation existingAnnot : existingAnnots.get(m)) {
+						if (existingAnnot.getStart() < m.getStart()) {
+							message += TXMCoreMessages.bind(KRAnnotationUIMessages.theEndOfAStructureP0AtP1P2, existingAnnot.getType(), existingAnnot.getStart(), existingAnnot.getEnd());
+						}
+						else {
+							message += TXMCoreMessages.bind(KRAnnotationUIMessages.theStartOfAStructureP0AtP1P2, existingAnnot.getType(), existingAnnot.getStart(), existingAnnot.getEnd());
+						}
+					}
+				}
+				final String final_message = message;
+				job.syncExec(new Runnable() {
+					
+					@Override
+					public void run() {
+						MessageDialog.openInformation(editor.getSite().getShell(), KRAnnotationUIMessages.aboutAnnotations, final_message);
+					}
+				});
+			}
+			
+			if (Log.getLevel().intValue() < Level.INFO.intValue() && annotManager != null) {
+				annotManager.checkData();
+			}
+		}
+		catch (Exception e1) {
+			Log.warning(NLS.bind(KRAnnotationUIMessages.errorWhileAffectionAnnotationColonP0, e1));
+			Log.printStackTrace(e1);
+			return;
+		}
+		
+		job.syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				try {
+					notifyStartOfRefresh();
+					annotationColumnViewer.getViewer().refresh();
+					CorporaView.refreshObject(corpus);
+				}
+				catch (Exception e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+			}
+		});
+	}
+	
+	@Override
+	public boolean notifyStartOfCompute() throws Exception {
+		if (annotationArea != null) {
+			annotationArea.getDisplay().syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					AnnotationType type = getSelectedAnnotationType();
+					if (type != null) {
+						annotations.setViewAnnotation(type);
+						annotations.setAnnotationOverlap(true);
+					}
+				}
+			});
+			
+		}
+		return true;
+	}
+	
+	@Override
+	public boolean notifyEndOfCompute() throws Exception {
+		updateAnnotationWidgetStates();
+		
+		// update annotation column width
+		if (annotationArea != null) {
+			annotationArea.getDisplay().syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					annotationColumn.pack();
+					annotationColumn.setResizable(true);
+				}
+			});
+		}
+		else {
+			annotationColumn.setWidth(0);
+		}
+		
+		return true;
+	}
+	
+	
+	@Override
+	public boolean isAnnotationEnable() {
+		return annotationArea != null;
+	}
+	
+	@Override
+	public void notifyStartOfRefresh() throws Exception {
+		List<Line> lines = concordance.getLines(concordance.getTopIndex(), concordance.getTopIndex() + concordance.getNLinePerPage());
+		annotations.computeLines(lines);
+	}
+	
+	@Override
+	public boolean save() {
+		try {
+			AnnotationManager am = KRAnnotationEngine.getAnnotationManager(corpus);
+			if (am != null && am.hasChanges()) {
+				// && MessageDialog.openConfirm(e.display.getActiveShell(), "Confirm annotation save", "Saving annotation will close this editor. Are you sure you want to save annotations right now
+				// ?")
+				JobHandler saveJob = SaveAnnotations.save(corpus.getMainCorpus());
+				if (saveJob == null || saveJob.getResult() == Status.CANCEL_STATUS) {
+					// update editor corpus
+					Log.warning("Fail to save annotations of the corpus.");
+					return false;
+				}
+				else {
+					if (annotationColumn != null && !annotationColumn.isDisposed()) {
+						annotationColumn.setText(annotations.getViewAnnotation().getName());
+					}
+					return true; // something was saved
+				}
+			}
+			else {
+				return false;
+			}
+		}
+		catch (Exception ex) {
+			ex.printStackTrace();
+			return false;
+		}
+	}
+	
+	@Override
+	protected void _close() {
+		if (!annotationColumn.isDisposed()) annotationColumn.dispose();
+		if (!annotationArea.isDisposed()) annotationArea.dispose();
+		extension.layout();
+	}
+	
+	@Override
+	public boolean hasChanges() {
+		AnnotationManager am;
+		try {
+			am = KRAnnotationEngine.getAnnotationManager(corpus);
+			if (am != null && am.hasChanges()) {
+				return am.hasChanges();
+			}
+			else {
+				return false;
+			}
+		}
+		catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+			return false;
+		}
+	}
+	
+	@Override
+	public void notifyEndOfRefresh() throws Exception {
+		// TODO Auto-generated method stub
+	}
+	
+	@Override
+	public void notifyStartOfCreatePartControl() throws Exception {
+		// TODO Auto-generated method stub
+		
+	}
+	
+	@Override
+	public Class<? extends TXMResult> getAnnotatedTXMResultClass() {
+		return Concordance.class;
+	}
+	
+	@Override
+	public boolean isDirty() {
+		return annotManager.isDirty();
+	}
+	
+	@Override
+	public boolean discardChanges() {
+		return false;
+	}
+	
+	@Override
+	public boolean needToUpdateIndexes() {
+		return KRAnnotationPreferences.getInstance().getBoolean(KRAnnotationPreferences.UPDATE);
+	}
+	
+	@Override
+	public boolean needToUpdateEditions() {
+		return KRAnnotationPreferences.getInstance().getBoolean(KRAnnotationPreferences.UPDATE_EDITION);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/SimpleKRAnnotation.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/AnnotationLine.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/AnnotationLine.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/AnnotationLine.java	(revision 3653)
@@ -0,0 +1,26 @@
+package org.txm.annotation.kr.rcp.concordance;
+
+import org.txm.annotation.kr.core.Annotation;
+import org.txm.annotation.kr.core.repository.TypedValue;
+
+public class AnnotationLine {
+
+	private TypedValue annotationValue;
+
+	private Annotation annotation;
+	
+	public AnnotationLine(Annotation annotation, TypedValue annotationValue) {
+		this.annotation = annotation;
+		this.annotationValue = annotationValue; 
+	}
+	
+
+	public Annotation getAnnotation() {
+		return annotation;
+	}
+	
+
+	public TypedValue getAnnotationValue() {
+		return annotationValue;
+	}
+}
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/AnnotationLine.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/AnnotationLineDecorator.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/AnnotationLineDecorator.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/AnnotationLineDecorator.java	(revision 3653)
@@ -0,0 +1,30 @@
+package org.txm.annotation.kr.rcp.concordance;
+
+import org.txm.annotation.kr.core.Annotation;
+import org.txm.concordance.core.functions.Line;
+import org.txm.concordance.core.functions.LineDecorator;
+
+public class AnnotationLineDecorator extends LineDecorator {
+	ConcordanceAnnotations annotations;
+	
+	public AnnotationLineDecorator(ConcordanceAnnotations annotations) {
+		this.annotations = annotations;
+	}
+	
+	/**
+	 * Add "<" or ">" depending of the current position of the match and the annotation start end positions
+	 */
+	@Override
+	public String decorate(Line i, int currentPos, String str) {
+		Annotation annotation = annotations.getAnnotationLine(i).getAnnotation();
+		
+		if (annotation != null) {
+			if (currentPos == annotation.getStart()) {
+				return "< "+str;
+			} else if (currentPos == annotation.getEnd()) {
+				return str+" >";
+			}
+		}
+		return str;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/AnnotationLineDecorator.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/KRAnnotation.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/KRAnnotation.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/KRAnnotation.java	(revision 3653)
@@ -0,0 +1,1083 @@
+package org.txm.annotation.kr.rcp.concordance;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Vector;
+import java.util.logging.Level;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.dialogs.ListDialog;
+import org.txm.annotation.kr.core.Annotation;
+import org.txm.annotation.kr.core.AnnotationManager;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.annotation.kr.core.preferences.KRAnnotationPreferences;
+import org.txm.annotation.kr.core.repository.AnnotationEffect;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.KnowledgeRepository;
+import org.txm.annotation.kr.core.repository.KnowledgeRepositoryManager;
+import org.txm.annotation.kr.core.repository.LocalKnowledgeRepository;
+import org.txm.annotation.kr.core.repository.SQLKnowledgeRepository;
+import org.txm.annotation.kr.core.repository.TypedValue;
+import org.txm.annotation.kr.rcp.commands.InitializeKnowledgeRepository;
+import org.txm.annotation.kr.rcp.commands.SaveAnnotations;
+import org.txm.annotation.kr.rcp.commands.krview.OpenKRView;
+import org.txm.annotation.kr.rcp.messages.KRAnnotationUIMessages;
+import org.txm.annotation.kr.rcp.views.knowledgerepositories.KRView;
+import org.txm.annotation.rcp.editor.AnnotationArea;
+import org.txm.annotation.rcp.editor.AnnotationExtension;
+import org.txm.concordance.core.functions.Concordance;
+import org.txm.concordance.core.functions.Line;
+import org.txm.concordance.rcp.editors.ConcordanceEditor;
+import org.txm.concordance.rcp.editors.ConcordanceEditor.ConcordanceColumnSizeControlListener;
+import org.txm.concordance.rcp.messages.ConcordanceUIMessages;
+import org.txm.core.messages.TXMCoreMessages;
+import org.txm.core.results.TXMResult;
+import org.txm.objects.Match;
+import org.txm.rcp.IImageKeys;
+import org.txm.rcp.commands.OpenBrowser;
+import org.txm.rcp.editors.TXMEditor;
+import org.txm.rcp.swt.GLComposite;
+import org.txm.rcp.swt.dialog.ConfirmDialog;
+import org.txm.rcp.swt.provider.SimpleLabelProvider;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.rcp.views.corpora.CorporaView;
+import org.txm.searchengine.cqp.corpus.CQPCorpus;
+import org.txm.utils.AsciiUtils;
+import org.txm.utils.logger.Log;
+
+public class KRAnnotation extends AnnotationArea {
+	
+	/**
+	 * the limit number of annotation when a confirm dialog box is shown
+	 */
+	protected static final int NALERTAFFECTANNOTATIONS = 100;
+	
+	public static final String EMPTYTEXT = ""; //$NON-NLS-1$
+	
+	/** The annotation service */
+	protected AnnotationManager annotManager;
+	
+	// boolean annotation_expert_mode = TxmPreferences.getBoolean(AnnotationPreferencePage.MODE, false);
+	
+	protected Point annotationSize;
+	
+	/** The annot btn : starts the annotation */
+	private Button addAnnotationTypeLink;
+	
+	protected Text annotationValuesText;
+	
+	protected ComboViewer annotationTypesCombo;
+	
+	protected List<TypedValue> typeValuesList;
+	
+	protected TableColumn annotationColumn;
+	
+	protected Combo addRemoveCombo;
+	
+	protected Combo affectCombo;
+	
+	protected Button affectAnnotationButton;
+	
+	protected Button infosAnnotTypeSelectedLink;
+	
+	protected KnowledgeRepository currentKnowledgeRepository = null;
+	
+	protected Vector<AnnotationType> typesList = new Vector<>();
+	
+	protected Button addTypedValueLink;
+	
+	protected Label withLabel;
+	
+	protected Label equalLabel;
+	
+	//protected TypedValue value_to_add;
+	
+	protected Concordance concordance;
+	
+	private CQPCorpus corpus;
+	
+	private ConcordanceAnnotations annotations = null;
+	
+	ConcordanceEditor editor;
+
+	private TableViewerColumn annotationColumnViewer;
+	
+	public KRAnnotation() {
+		
+	}
+	
+	@Override
+	public String getName() {
+		return KRAnnotationUIMessages.squencesDeMotsCatgorievaleur;
+	}
+	
+	@Override
+	public boolean install(TXMEditor<? extends TXMResult> txmeditor, AnnotationExtension ext, Composite parent, int position) throws Exception {
+		
+		this.extension = ext;
+		this.editor = (ConcordanceEditor) txmeditor;
+		this.concordance = this.editor.getConcordance();
+		this.corpus = concordance.getCorpus();
+		this.annotations = new ConcordanceAnnotations(this.editor.getConcordance());
+		annotations.computeLines(this.editor.getConcordance().getLines()); // pre-compute the annotation lines ot avoid breaking the sort and co.
+		this.annotManager = KRAnnotationEngine.getAnnotationManager(corpus);
+		
+		TableViewer viewer = this.editor.getLineTableViewer();
+		
+		// RESULT
+		
+		if (position < 0) {
+			position = 3 + extension.getNumberOfAnnotationArea(); // after keyword column and previous annotation columns
+		}
+		
+		this.annotationColumnViewer = new TableViewerColumn(viewer, SWT.CENTER, position);
+		annotationColumn = annotationColumnViewer.getColumn();
+		annotationColumn.setText(KRAnnotationUIMessages.category);
+		annotationColumn.setToolTipText(KRAnnotationUIMessages.keywordsAnnotation);
+		annotationColumn.setAlignment(SWT.CENTER);
+		annotationColumn.pack();
+		annotationColumn.addControlListener(new ConcordanceColumnSizeControlListener(annotationColumn));
+		annotationColumnViewer.setLabelProvider(new ColumnLabelProvider() {
+			
+			@Override
+			public String getText(Object element) {
+				Line line = (Line) element;
+				AnnotationLine annotationLine = annotations.getAnnotationLine(line);
+				if (annotationLine == null) return EMPTYTEXT;
+				if (annotationLine.getAnnotation() != null) {
+					String value = annotationLine.getAnnotationValue().getStandardName();
+					Annotation a = annotationLine.getAnnotation();
+					if (value == null) value = a.getValue();
+					
+					if (a.getStart() < line.matchGetStart() - line.getLeftContextSize()) {
+						value = "… " + value; //$NON-NLS-1$
+					}
+					
+					if (a.getEnd() > line.matchGetEnd() + line.getRightContextSize()) {
+						value = value + " …"; //$NON-NLS-1$
+					}
+					return value;
+				}
+				else {
+					return EMPTYTEXT;
+				}
+			}
+		});
+		
+//		ext.getSaveButton().setEnabled(true);
+		return composeAnnotationArea(parent);
+	}
+	
+	public boolean initialiseInput(ConcordanceEditor editor) throws Exception {
+		
+		this.editor = editor;
+		concordance = editor.getConcordance();
+		annotations = new ConcordanceAnnotations(concordance);
+		annotations.computeLines(this.editor.getConcordance().getLines()); // pre-compute the annotation lines ot avoid breaking the sort and co.
+		corpus = concordance.getCorpus();
+		
+		CQPCorpus corpus = editor.getCorpus();
+		
+		this.annotManager = KRAnnotationEngine.getAnnotationManager(corpus);
+		
+		return true;
+	}
+	
+	private boolean composeAnnotationArea(final Composite parent) {
+		
+		List<KnowledgeRepository> krs = InitializeKnowledgeRepository.get(corpus.getMainCorpus());
+		typesList.clear();
+		Log.fine("Corpus KRs: " + krs); //$NON-NLS-1$
+		
+		for (KnowledgeRepository kr : krs) {
+			if (kr == null) continue;
+			
+			currentKnowledgeRepository = kr;
+			Log.fine(" KR: " + kr); //$NON-NLS-1$
+			List<AnnotationType> krtypes = kr.getAllAnnotationTypes();
+			for (AnnotationType type : krtypes) {
+				if (type.getEffect().equals(AnnotationEffect.SEGMENT)) {
+					typesList.add(type);
+				}
+			}
+			
+			Log.fine(NLS.bind(KRAnnotationUIMessages.availableAnnotationTypesColonP0, typesList));
+			break;
+		}
+		
+		if (currentKnowledgeRepository == null) {
+			Log.warning(KRAnnotationUIMessages.errorColonNoSuitableKnowledgeRepositoryFound);
+			return false;
+		}
+		
+		annotationArea = new GLComposite(parent, SWT.NONE, KRAnnotationUIMessages.concordanceAnnotationArea);
+		annotationArea.getLayout().numColumns = 12;
+		annotationArea.getLayout().horizontalSpacing = 2;
+		annotationArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+		
+		addRemoveCombo = new Combo(annotationArea, SWT.READ_ONLY);
+		String affectLabel = currentKnowledgeRepository.getString(editor.getLocale(), "ConcordancesEditor_22"); //$NON-NLS-1$
+		if (affectLabel == null) affectLabel = KRAnnotationUIMessages.affect;
+		String removeLabel = currentKnowledgeRepository.getString(editor.getLocale(), "ConcordancesEditor_24"); //$NON-NLS-1$
+		if (removeLabel == null) removeLabel = KRAnnotationUIMessages.delete;
+		String items[] = { affectLabel, removeLabel };
+		addRemoveCombo.setItems(items);
+		addRemoveCombo.select(0);
+		addRemoveCombo.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (addRemoveCombo.getSelectionIndex() == 0) { // add
+					annotationValuesText.setEnabled(true);
+					String withLabelText = currentKnowledgeRepository.getString(editor.getLocale(), "ConcordancesEditor_83"); //$NON-NLS-1$
+					if (withLabelText == null) withLabelText = KRAnnotationUIMessages.withTheCategory;
+					withLabel.setText(withLabelText);
+					if (equalLabel != null) equalLabel.setText("="); //$NON-NLS-1$
+				}
+				else { // remove
+					annotationValuesText.setEnabled(false);
+					withLabel.setText(""); //$NON-NLS-1$
+					if (equalLabel != null) equalLabel.setText(""); //$NON-NLS-1$
+				}
+				withLabel.redraw();
+				annotationArea.layout();
+				updateAnnotationWidgetStates();
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		GridData gdata = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+		//gdata.widthHint = 90;
+		addRemoveCombo.setLayoutData(gdata);
+		
+		withLabel = new Label(annotationArea, SWT.NONE);
+		String withLabelText = currentKnowledgeRepository.getString(editor.getLocale(), "ConcordancesEditor_83"); //$NON-NLS-1$
+		if (withLabelText == null) withLabelText = KRAnnotationUIMessages.withTheCategory;
+		withLabel.setText(withLabelText);
+		withLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		
+		equalLabel = new Label(annotationArea, SWT.NONE);
+		equalLabel.setText("="); //$NON-NLS-1$
+		equalLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		
+		// Display combo with list of Annotation Type
+		annotationTypesCombo = new ComboViewer(annotationArea, SWT.READ_ONLY);
+		annotationTypesCombo.setContentProvider(new ArrayContentProvider());
+		annotationTypesCombo.setLabelProvider(new SimpleLabelProvider() {
+			
+			@Override
+			public String getColumnText(Object element, int columnIndex) {
+				return ((AnnotationType) element).getName();
+			}
+			
+			@Override
+			public String getText(Object element) {
+				return ((AnnotationType) element).getName();
+			}
+		});
+		gdata = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+		gdata.widthHint = 200;
+		
+		annotationTypesCombo.getCombo().setLayoutData(gdata);
+		annotationTypesCombo.setInput(typesList);
+		if (typesList.size() > 0) {
+			annotationTypesCombo.getCombo().select(0);
+			annotations.setViewAnnotation(typesList.get(0));
+		}
+		
+		annotationTypesCombo.addSelectionChangedListener(new ISelectionChangedListener() {
+			
+			@Override
+			public void selectionChanged(SelectionChangedEvent event) {
+				AnnotationType type = getSelectedAnnotationType();
+				if (type == null) return;
+				if (type.getSize() != AnnotationType.ValuesSize.LARGE) {
+					try {
+						KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(type.getKnowledgeRepository());
+						typeValuesList = kr.getValues(type);
+					}
+					catch (Exception e) {
+						// TODO Auto-generated catch block
+						e.printStackTrace();
+					}
+				}
+				
+				annotationColumn.setText(type.getName());
+				if (concordance != null) {
+					annotations.setViewAnnotation(type);
+					annotations.setAnnotationOverlap(true);
+					try {
+						notifyStartOfRefresh();
+						annotationColumnViewer.getViewer().refresh();
+					}
+					catch (Exception e) {
+						// TODO Auto-generated catch block
+						e.printStackTrace();
+					}
+				}
+				
+				updateAnnotationWidgetStates();
+			}
+		});
+		
+		if (currentKnowledgeRepository instanceof SQLKnowledgeRepository) {
+			infosAnnotTypeSelectedLink = new Button(annotationArea, SWT.PUSH);
+			infosAnnotTypeSelectedLink.setImage(IImageKeys.getImage(IImageKeys.ACTION_INFO));
+			infosAnnotTypeSelectedLink.setEnabled(true);
+			infosAnnotTypeSelectedLink.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+			infosAnnotTypeSelectedLink.addSelectionListener(new SelectionListener() {
+				
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					AnnotationType type = getSelectedAnnotationType();
+					if (type == null) return;
+					
+					String typedValueURL = type.getURL(); // may be null/empty
+					if (typedValueURL != null && typedValueURL.length() > 0) {
+						KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(type.getKnowledgeRepository());
+						kr.getTypeURL(type);
+					}
+					if (typedValueURL != null && typedValueURL.length() > 0) {
+						OpenBrowser.openfile(typedValueURL, new File(typedValueURL).getName());
+					}
+					else {
+						IWorkbenchWindow window = editor.getSite().getWorkbenchWindow();
+						try {
+							OpenKRView.openView(window, type);
+						}
+						catch (PartInitException e1) {
+							e1.printStackTrace();
+						}
+					}
+				}
+				
+				@Override
+				public void widgetDefaultSelected(SelectionEvent e) {}
+			});
+		}
+		
+		if (currentKnowledgeRepository instanceof LocalKnowledgeRepository) {
+			addAnnotationTypeLink = new Button(annotationArea, SWT.PUSH);
+			addAnnotationTypeLink.setToolTipText(KRAnnotationUIMessages.addANewCategory);
+			addAnnotationTypeLink.setImage(IImageKeys.getImage(IImageKeys.ACTION_ADD));
+			addAnnotationTypeLink.setEnabled(true);
+			addAnnotationTypeLink.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+			addAnnotationTypeLink.addSelectionListener(new SelectionListener() {
+				
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					if (currentKnowledgeRepository == null) return;
+					if (!(currentKnowledgeRepository instanceof LocalKnowledgeRepository)) return;
+					
+					LocalKnowledgeRepository kr = (LocalKnowledgeRepository) currentKnowledgeRepository;
+					
+					InputDialog dialog = new InputDialog(e.widget.getDisplay().getActiveShell(), KRAnnotationUIMessages.newCategory, KRAnnotationUIMessages.pleaseEnterTheNewTypeName, "", null); //$NON-NLS-1$
+					if (dialog.open() == InputDialog.OK) {
+						String name = dialog.getValue();
+						if (name.trim().length() == 0) return;
+						String id = AsciiUtils.buildId(name);
+						AnnotationType existingType = kr.getType(id);
+						if (existingType != null) {
+							Log.warning(NLS.bind("The ''{0}'' annotation type already exists. Please use another name ({1}).", id, name));
+							annotationTypesCombo.setSelection(new StructuredSelection(existingType));
+							return;
+						}
+						AnnotationType type = kr.addType(name, id, ""); //$NON-NLS-1$
+						type.setEffect(AnnotationEffect.SEGMENT);
+						typesList.add(type);
+						
+						if (annotationTypesCombo != null) annotationTypesCombo.refresh();
+						
+						// if (typesList.size() == 1) {
+						// if (annotationTypesCombo != null) annotationTypesCombo.getCombo().select(0);
+						// if (concordance != null) {
+						// annotations.setAnnotationOverlap(true);
+						// try {
+						// annotationColumn.setText(type.getId());
+						// editor.refresh(false);
+						// }
+						// catch (Exception e1) {
+						// // TODO Auto-generated catch block
+						// e1.printStackTrace();
+						// }
+						// }
+						// annotationArea.layout(true);
+						// }
+						// else {
+						// if (typesList.size() > 1) {
+						// if (annotationTypesCombo != null) {
+						// annotationTypesCombo.getCombo().select(typesList.size() - 1);
+						// }
+						// }
+						// }
+						
+						annotations.setViewAnnotation(type);
+						annotationTypesCombo.setSelection(new StructuredSelection(typesList.get(typesList.size() - 1))); // select the new annotation
+						annotationArea.layout(true);
+						
+						KRView.refresh();
+						updateAnnotationWidgetStates();
+					}
+					else {
+						Log.warning("Creation aborted.");
+					}
+				}
+				
+				@Override
+				public void widgetDefaultSelected(SelectionEvent e) {}
+			});
+		}
+		
+		Label valueLabel = new Label(annotationArea, SWT.NONE);
+		String valueLabelText = currentKnowledgeRepository.getString(editor.getLocale(), "ConcordancesEditor_80"); //$NON-NLS-1$
+		if (valueLabelText == null) {
+			valueLabelText = KRAnnotationUIMessages.valueEquals;
+		}
+		valueLabel.setText(valueLabelText);
+		valueLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		
+		annotationValuesText = new Text(annotationArea, SWT.BORDER);
+		annotationValuesText.setToolTipText(KRAnnotationUIMessages.enterAValueForAnId);
+		GridData gdata2 = new GridData(SWT.FILL, SWT.CENTER, false, false);
+		gdata2.widthHint = 200;
+		annotationValuesText.setLayoutData(gdata2);
+		annotationValuesText.addKeyListener(new KeyListener() {
+			
+			@Override
+			public void keyReleased(KeyEvent e) {
+				if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+					affectAnnotationToSelection(editor.getLineTableViewer().getSelection());
+				}
+			}
+			
+			@Override
+			public void keyPressed(KeyEvent e) {}
+		});
+		
+		if (currentKnowledgeRepository instanceof LocalKnowledgeRepository) {
+			
+			addTypedValueLink = new Button(annotationArea, SWT.PUSH);
+			addTypedValueLink.setText("..."); //$NON-NLS-1$
+			addTypedValueLink.setToolTipText(KRAnnotationUIMessages.selectAValueAmongTheList);
+			addTypedValueLink.setEnabled(true);
+			addTypedValueLink.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+			addTypedValueLink.addSelectionListener(new SelectionListener() {
+				
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					if (currentKnowledgeRepository == null) return;
+					if (!(currentKnowledgeRepository instanceof LocalKnowledgeRepository)) return;
+					
+					AnnotationType type = getSelectedAnnotationType();
+					if (type == null) return;
+					
+					LocalKnowledgeRepository kr = (LocalKnowledgeRepository) currentKnowledgeRepository;
+					
+					ListDialog dialog = new ListDialog(e.widget.getDisplay().getActiveShell());
+					String title = currentKnowledgeRepository.getString(editor.getLocale(), "ConcordancesEditor_100"); //$NON-NLS-1$
+					if (title == null) title = KRAnnotationUIMessages.availableValuesForP0;
+					dialog.setTitle(ConcordanceUIMessages.bind(title, type.getName()));// +"valeurs de "+type.getName());
+					dialog.setContentProvider(new ArrayContentProvider());
+					dialog.setLabelProvider(new SimpleLabelProvider() {
+						
+						@Override
+						public String getColumnText(Object element, int columnIndex) {
+							if (element instanceof TypedValue)
+								return ((TypedValue) element).getId();
+							return element.toString();
+						}
+					});
+					List<TypedValue> values;
+					try {
+						values = kr.getValues(type);
+					}
+					catch (Exception e1) {
+						e1.printStackTrace();
+						return;
+					}
+					dialog.setInput(values);
+					if (dialog.open() == InputDialog.OK) {
+						TypedValue value = (TypedValue) dialog.getResult()[0];
+						String name = value.getId();
+						if (name.trim().length() == 0) return;
+						
+						annotationValuesText.setText(name);
+					}
+					else {
+						
+					}
+				}
+				
+				@Override
+				public void widgetDefaultSelected(SelectionEvent e) {}
+			});
+		}
+		
+		affectCombo = new Combo(annotationArea, SWT.READ_ONLY);
+		affectCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		String items2[] = { KRAnnotationUIMessages.selectedLines, KRAnnotationUIMessages.allLines };
+		affectCombo.setItems(items2);
+		affectCombo.select(0);
+		gdata = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+		//gdata.widthHint = 140;
+		affectCombo.setLayoutData(gdata);
+		
+		affectAnnotationButton = new Button(annotationArea, SWT.PUSH);
+		affectAnnotationButton.setText(KRAnnotationUIMessages.oK);
+		affectAnnotationButton.setToolTipText(KRAnnotationUIMessages.proceedToAnnotation);
+		affectAnnotationButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		affectAnnotationButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				int isel = affectCombo.getSelectionIndex();
+				if (isel == 0) { // selected line
+					affectAnnotationToSelection(editor.getLineTableViewer().getSelection());
+				}
+				else { // all
+					try {
+						List<? extends Match> matches = concordance.getMatches();
+						affectMatchesToSelection(matches);
+					}
+					catch (Exception e1) {
+						Log.severe(NLS.bind(KRAnnotationUIMessages.errorWhileAnnotatingConcordanceColonP0, e1.getLocalizedMessage()));
+						Log.printStackTrace(e1);
+						return;
+					}
+				}
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		// Button saveAnnotationButton = new Button(annotationArea, SWT.PUSH);
+		// saveAnnotationButton.setToolTipText(KRAnnotationUIMessages.saveTheAnnotations);
+		// saveAnnotationButton.setImage(IImageKeys.getImage(IImageKeys.PENCIL_SAVE));
+		//
+		// saveAnnotationButton.addSelectionListener(new SelectionListener() {
+		// @Override
+		// public void widgetSelected(SelectionEvent e) {
+		//
+		// try {
+		// AnnotationManager am = KRAnnotationEngine.getAnnotationManager(corpus);
+		// if (am != null && am.hasChanges()) {
+		// // && MessageDialog.openConfirm(e.display.getActiveShell(), "Confirm annotation save", "Saving annotation will close this editor. Are you sure you want to save annotations right now ?")
+		// JobHandler saveJob = SaveAnnotations.save(corpus.getMainCorpus());
+		//
+		// if (saveJob == null || saveJob.getResult() == Status.CANCEL_STATUS) {
+		// // update editor corpus
+		// System.out.println("Fail to save annotations of the corpus."); //$NON-NLS-1$
+		// }
+		//
+		// CorporaView.refresh();
+		// }
+		// } catch(Exception ex) {
+		// ex.printStackTrace();
+		// }
+		// }
+		//
+		// @Override
+		// public void widgetDefaultSelected(SelectionEvent e) { }
+		// });
+		
+		Button closeButton = new Button(annotationArea, SWT.PUSH);
+		closeButton.setToolTipText(KRAnnotationUIMessages.closeTheToolbarWithoutSaving);
+		closeButton.setImage(IImageKeys.getImage(IImageKeys.ACTION_DELETE));
+		closeButton.setLayoutData(new GridData(GridData.END, GridData.CENTER, true, false));
+		closeButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				extension.closeArea(KRAnnotation.this, true);
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		updateAnnotationWidgetStates();
+		editor.layout(true);
+		
+		return true;
+	}
+	
+	@Override
+	public boolean hasChanges() {
+		AnnotationManager am;
+		try {
+			am = KRAnnotationEngine.getAnnotationManager(corpus);
+			if (am != null && am.hasChanges()) {
+				return am.hasChanges();
+			}
+			else {
+				return false;
+			}
+		}
+		catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+			return false;
+		}
+	}
+	
+	protected void affectAnnotationToSelection(ISelection selection) {
+		
+		final IStructuredSelection lineSelection = (IStructuredSelection) selection;
+		List<Line> lines = lineSelection.toList();
+		ArrayList<Match> matches = new ArrayList<>();
+		for (Line l : lines) {
+			matches.add(l.getMatch());
+		}
+		
+		affectMatchesToSelection(matches);
+	}
+	
+	protected AnnotationType getSelectedAnnotationType() {
+		if (annotationTypesCombo.getCombo().isDisposed()) return null;
+		
+		IStructuredSelection isel = (IStructuredSelection) annotationTypesCombo.getSelection();
+		if (isel.isEmpty()) {
+			return null;
+		}
+		return (AnnotationType) isel.getFirstElement();
+	}
+	
+	protected void affectMatchesToSelection(final List<? extends Match> matches) {
+		final AnnotationType type = getSelectedAnnotationType();
+		final String svalue = annotationValuesText.getText();
+		final boolean doAffect = addRemoveCombo.getSelectionIndex() == 0; // add is default
+		
+		JobHandler job = new JobHandler(KRAnnotationUIMessages.annotatingConcordanceSelection, true) {
+			
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				this.runInit(monitor);
+				try {
+					if (doAffect) {
+						affectAnnotationValues(matches, type, svalue, this);
+					}
+					else {
+						deleteAnnotationValues(matches, type, this);
+					}
+				}
+				catch (Exception e) {
+					Log.severe(NLS.bind(KRAnnotationUIMessages.errorWhileAnnotatingConcordanceSelectionColonP0, e));
+					Log.printStackTrace(e);
+					return Status.CANCEL_STATUS;
+				}
+				catch (ThreadDeath td) {
+					Log.info(KRAnnotationUIMessages.annotationCanceledByUser);
+					return Status.CANCEL_STATUS;
+				}
+				
+				return Status.OK_STATUS;
+			}
+		};
+		job.startJob(true);
+	}
+	
+	public void updateAnnotationWidgetStates() {
+		if (annotationArea == null) return; // :)
+		if (annotationArea.isDisposed()) return;
+		
+		annotationArea.getDisplay().syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				if (addRemoveCombo.getSelectionIndex() == 0) { // add is default
+					
+					if (getSelectedAnnotationType() != null) {
+						
+						annotationValuesText.setEnabled(true);
+						affectAnnotationButton.setEnabled(true);
+						affectCombo.setEnabled(true);
+					}
+					else {
+						
+						annotationValuesText.setEnabled(false);
+						affectAnnotationButton.setEnabled(false);
+						affectCombo.setEnabled(false);
+					}
+				}
+				else {
+					annotationValuesText.setEnabled(false);
+					
+					if (getSelectedAnnotationType() != null) {
+						affectAnnotationButton.setEnabled(true);
+						affectCombo.setEnabled(true);
+					}
+					else {
+						affectAnnotationButton.setEnabled(false);
+						affectCombo.setEnabled(false);
+					}
+				}
+				
+				if (infosAnnotTypeSelectedLink != null) {
+					infosAnnotTypeSelectedLink.setEnabled(getSelectedAnnotationType() != null);
+				}
+				if (addTypedValueLink != null) {
+					addTypedValueLink.setEnabled(getSelectedAnnotationType() != null);
+				}
+				
+				if (concordance == null) {
+					affectAnnotationButton.setEnabled(false);
+					affectCombo.setEnabled(false);
+				}
+			}
+		});
+	}
+	
+	protected void deleteAnnotationValues(List<? extends Match> matches, AnnotationType type, JobHandler job) {
+		if (concordance == null) {
+			return;
+		}
+		
+		if (matches.size() == 0) {
+			Log.warning("No lines selected. Aborting."); 
+			return;
+		}
+		
+		if (type == null) {
+			return;
+		}
+		
+		if (concordance != null) {
+			try {
+				if (annotManager != null && annotManager.deleteAnnotations(type, matches, job)) {
+					if (Log.getLevel().intValue() < Level.INFO.intValue()) annotManager.checkData();
+					//concordance.reloadLines(editor.getTopLine(), editor.getBottomLine() + 1);
+				}
+				else {
+					return;
+				}
+			}
+			catch (Exception e1) {
+				Log.warning(NLS.bind(KRAnnotationUIMessages.errorWhileDeletingAnnotationColonP0, e1));
+				Log.printStackTrace(e1);
+				return;
+			}
+			
+			job.syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					try {
+						notifyStartOfRefresh();
+						annotationColumnViewer.getViewer().refresh();
+					}
+					catch (Exception e) {
+						// TODO Auto-generated catch block
+						e.printStackTrace();
+					}
+					CorporaView.refreshObject(corpus);
+				}
+			});
+		}
+	}
+	
+	protected void affectAnnotationValues(final List<? extends Match> matches, final AnnotationType type, final String svalue, JobHandler job) {
+		
+		TypedValue value_to_add = null; // reset
+		if (concordance == null) {
+			Log.info("No concordance done. Aborting.");
+			return;
+		}
+		if (matches.size() == 0) {
+			Log.warning("No line selected. Aborting.");
+			return;
+		}
+		if (type == null) return; // no type, no annotation
+		
+		job.syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				if (matches.size() > NALERTAFFECTANNOTATIONS) {
+					ConfirmDialog dialog = new ConfirmDialog(Display.getCurrent().getActiveShell(),
+							"confirm_annotate",  //$NON-NLS-1$
+							KRAnnotationUIMessages.confirmAnnotationAffectation,
+							NLS.bind(KRAnnotationUIMessages.youAreAboutToAnnotateP0ElementsContinue, matches.size()));
+					
+					if (dialog.open() == ConfirmDialog.CANCEL) {
+						Log.info("Annotation aborted by user.");
+						matches.clear();
+					}
+				}
+			}
+		});
+		
+		// get value from combo text value
+		Log.fine(NLS.bind(KRAnnotationUIMessages.lookingForTypedValueWithIdEqualsP0, svalue));
+		final KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(type.getKnowledgeRepository());
+		value_to_add = kr.getValue(type, svalue);
+		
+		
+		if (value_to_add == null && kr instanceof LocalKnowledgeRepository) { // create or not the annotation is simple mode
+			job.syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					String title = kr.getString(editor.getLocale(), "ConcordancesEditor_110"); //$NON-NLS-1$
+					String content = kr.getString(editor.getLocale(), "ConcordancesEditor_112"); //$NON-NLS-1$
+					if (title == null) title = KRAnnotationUIMessages.newValueP0ForCategoryP1;
+					if (content == null) content = KRAnnotationUIMessages.theValueP0IsNotAssociatedWithTheCategoryP1AssociateIt;
+					ConfirmDialog dialog = new ConfirmDialog(Display.getCurrent().getActiveShell(),
+							"create_value", //$NON-NLS-1$
+							ConcordanceUIMessages.bind(title, svalue, type.getName()),
+							ConcordanceUIMessages.bind(content, svalue, type.getName()));
+					if (dialog.open() == ConfirmDialog.CANCEL) {
+						Log.info("Annotation aborted by user.");
+						return;
+					}
+					else {
+						kr.addValue(svalue, svalue, type.getId());
+						KRView.refresh();
+					}
+				}
+			});
+		}
+		
+		value_to_add = kr.getValue(type, svalue); // re-initialize value_to_add if the value was created
+		
+		if (value_to_add == null && kr instanceof LocalKnowledgeRepository) return; // canceled
+		
+		if (value_to_add == null) {
+			job.syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					String mess = ConcordanceUIMessages.bind(KRAnnotationUIMessages.noValueFoundWithTheP0Id, svalue);
+					Log.warning(mess);
+					MessageDialog.openError(Display.getCurrent().getActiveShell(), "Annotation canceled", mess); //$NON-NLS-1$
+				}
+			});
+			return;
+		}
+		
+		// Log.info("AFFECT "+value_to_add+" to SELECTION="+matches); //$NON-NLS-1$ //$NON-NLS-1$
+		
+		// finally we can 'try' to create the annotations \o/
+		try {
+			HashMap<Match, List<Annotation>> existingAnnots = annotManager.createAnnotations(type, value_to_add, matches, job);
+			
+			// did we had problems ?
+			if (existingAnnots != null && existingAnnots.size() > 0) {
+				String message = NLS.bind(KRAnnotationUIMessages.couldNotAnnotateTheValueP0OnCertainSequences, value_to_add.getStandardName());
+				for (Match m : existingAnnots.keySet()) {
+					message += NLS.bind(KRAnnotationUIMessages.theSequenceP0IsOverlappingWith, m);
+					
+					for (Annotation existingAnnot : existingAnnots.get(m)) {
+						if (existingAnnot.getStart() < m.getStart()) {
+							message += TXMCoreMessages.bind(KRAnnotationUIMessages.theEndOfAStructureP0AtP1P2, existingAnnot.getType(), existingAnnot.getStart(), existingAnnot.getEnd());
+						}
+						else {
+							message += TXMCoreMessages.bind(KRAnnotationUIMessages.theStartOfAStructureP0AtP1P2, existingAnnot.getType(), existingAnnot.getStart(), existingAnnot.getEnd());
+						}
+					}
+				}
+				final String final_message = message;
+				job.syncExec(new Runnable() {
+					
+					@Override
+					public void run() {
+						MessageDialog.openInformation(editor.getSite().getShell(), KRAnnotationUIMessages.aboutAnnotations, final_message);
+					}
+				});
+			}
+			// if (history != null && !history.get(type).contains(value_to_add))
+			// history.get(type).add(value_to_add);
+			
+			if (Log.getLevel().intValue() < Level.INFO.intValue() && annotManager != null) {
+				annotManager.checkData();
+			}
+			//concordance.reloadCurrentLines();
+		}
+		catch (Exception e1) {
+			Log.warning(NLS.bind(KRAnnotationUIMessages.errorWhileAffectionAnnotationColonP0, e1));
+			Log.printStackTrace(e1);
+			return;
+		}
+		
+		job.syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				try {
+					notifyStartOfRefresh();
+					annotationColumnViewer.getViewer().refresh();
+					CorporaView.refreshObject(corpus);
+				}
+				catch (Exception e) {
+					e.printStackTrace();
+				}
+			}
+		});
+		
+	}
+	
+	@Override
+	public boolean notifyStartOfCompute() throws Exception {
+		if (annotationArea == null) return false;
+		if (annotationArea.isDisposed()) return false;
+		
+		annotationArea.getDisplay().syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				AnnotationType type = getSelectedAnnotationType();
+				if (type != null) {
+					annotations.setViewAnnotation(type);
+					annotations.setAnnotationOverlap(true);
+				}
+			}
+		});
+		
+		return true;
+	}
+	
+	@Override
+	public boolean notifyEndOfCompute() throws Exception {
+		updateAnnotationWidgetStates();
+		if (annotationArea == null) return false;
+		if (annotationArea.isDisposed()) return false;
+		
+		// update annotation column width
+		if (annotationArea != null) {
+			annotationArea.getDisplay().syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					annotationColumn.pack();
+					annotationColumn.setResizable(true);
+				}
+			});
+		}
+		else {
+			annotationColumn.setWidth(0);
+		}
+		
+		return true;
+	}
+	
+	
+	@Override
+	public boolean isAnnotationEnable() {
+		return annotationArea != null;
+	}
+	
+	@Override
+	public boolean save() {
+		try {
+			AnnotationManager am = KRAnnotationEngine.getAnnotationManager(corpus);
+			if (am != null && am.hasChanges()) {
+				// && MessageDialog.openConfirm(e.display.getActiveShell(), "Confirm annotation save", "Saving annotation will close this editor. Are you sure you want to save annotations right now
+				// ?")
+				JobHandler saveJob = SaveAnnotations.save(corpus.getMainCorpus());
+				if (saveJob == null || saveJob.getResult() == Status.CANCEL_STATUS) {
+					// update editor corpus
+					Log.warning("Fail to save annotations of the corpus.");
+					return false;
+				}
+				else {
+					if (annotationColumn != null && !annotationColumn.isDisposed()) {
+						annotationColumn.setText(annotations.getViewAnnotation().getName());
+					}
+					return true; // something was saved
+				}
+			}
+			else {
+				return false;
+			}
+		}
+		catch (Exception ex) {
+			ex.printStackTrace();
+			return false;
+		}
+	}
+	
+	@Override
+	protected void _close() {
+		if (!annotationColumn.isDisposed()) annotationColumn.dispose();
+		if (!annotationArea.isDisposed()) {
+			annotationArea.dispose();
+		}
+		extension.layout();
+	}
+	
+	@Override
+	public void notifyEndOfRefresh() throws Exception {
+		// TODO Auto-generated method stub
+		
+	}
+	
+	@Override
+	public void notifyStartOfCreatePartControl() throws Exception {
+		// TODO Auto-generated method stub
+		
+	}
+	
+	@Override
+	public void notifyStartOfRefresh() throws Exception {
+		List<Line> lines = concordance.getLines(concordance.getTopIndex(), concordance.getTopIndex() + concordance.getNLinePerPage());
+		annotations.computeLines(lines);
+	}
+	
+	@Override
+	public Class<? extends TXMResult> getAnnotatedTXMResultClass() {
+		return Concordance.class;
+	}
+	
+	@Override
+	public boolean isDirty() {
+		return annotManager != null && annotManager.isDirty();
+	}
+	
+	@Override
+	public boolean discardChanges() {
+		return false;
+	}
+	
+	@Override
+	public boolean needToUpdateIndexes() {
+		return KRAnnotationPreferences.getInstance().getBoolean(KRAnnotationPreferences.UPDATE);
+	}
+	
+	@Override
+	public boolean needToUpdateEditions() {
+		return KRAnnotationPreferences.getInstance().getBoolean(KRAnnotationPreferences.UPDATE_EDITION);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/KRAnnotation.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/WordAnnotationToolbar.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/WordAnnotationToolbar.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/WordAnnotationToolbar.java	(revision 3653)
@@ -0,0 +1,1075 @@
+package org.txm.annotation.kr.rcp.concordance;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Vector;
+import java.util.logging.Level;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.TypedEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.ListDialog;
+import org.txm.annotation.kr.core.Annotation;
+import org.txm.annotation.kr.core.AnnotationManager;
+import org.txm.annotation.kr.core.CQPAnnotation;
+import org.txm.annotation.kr.core.DatabasePersistenceManager;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.annotation.kr.core.preferences.KRAnnotationPreferences;
+import org.txm.annotation.kr.core.repository.AnnotationEffect;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.KnowledgeRepository;
+import org.txm.annotation.kr.core.repository.KnowledgeRepositoryManager;
+import org.txm.annotation.kr.core.repository.LocalKnowledgeRepository;
+import org.txm.annotation.kr.core.repository.TypedValue;
+import org.txm.annotation.kr.rcp.commands.InitializeKnowledgeRepository;
+import org.txm.annotation.kr.rcp.commands.SaveAnnotations;
+import org.txm.annotation.kr.rcp.messages.KRAnnotationUIMessages;
+import org.txm.annotation.kr.rcp.views.knowledgerepositories.KRView;
+import org.txm.annotation.rcp.editor.AnnotationArea;
+import org.txm.annotation.rcp.editor.AnnotationExtension;
+import org.txm.concordance.core.functions.Concordance;
+import org.txm.concordance.core.functions.Line;
+import org.txm.concordance.rcp.editors.ConcordanceEditor;
+import org.txm.concordance.rcp.editors.ConcordanceEditor.ConcordanceColumnSizeControlListener;
+import org.txm.concordance.rcp.messages.ConcordanceUIMessages;
+import org.txm.core.messages.TXMCoreMessages;
+import org.txm.core.results.TXMResult;
+import org.txm.objects.Match;
+import org.txm.rcp.IImageKeys;
+import org.txm.rcp.editors.TXMEditor;
+import org.txm.rcp.swt.GLComposite;
+import org.txm.rcp.swt.dialog.ConfirmDialog;
+import org.txm.rcp.swt.provider.SimpleLabelProvider;
+import org.txm.rcp.utils.JobHandler;
+import org.txm.searchengine.cqp.corpus.CQPCorpus;
+import org.txm.searchengine.cqp.corpus.WordProperty;
+import org.txm.utils.AsciiUtils;
+import org.txm.utils.logger.Log;
+
+public class WordAnnotationToolbar extends AnnotationArea {
+	
+	/**
+	 * the limit number of annotation when a confirm dialog box is shown
+	 */
+	protected static final int NALERTAFFECTANNOTATIONS = 100;
+	
+	public static final String EMPTYTEXT = ""; //$NON-NLS-1$
+	
+	/** The annotation service */
+	protected AnnotationManager annotManager;
+	
+	protected ConcordanceEditor editor;
+	
+	/**
+	 * The concordance annotations to show in the concordance column table
+	 */
+	private ConcordanceAnnotations annotations = null;
+	
+	/**
+	 * All available annotation types
+	 */
+	protected List<TypedValue> typeValuesList;
+	
+	/**
+	 * display the annotation values of the current shown concordance lines
+	 */
+	protected TableColumn annotationColumn;
+	
+	protected ComboViewer annotationTypesCombo;
+	
+	/** add a new type of annotation */
+	private Button addAnnotationTypeButton;
+	
+	protected Label equalLabel;
+	
+	protected Text annotationValuesText;
+	
+	protected Button affectAnnotationButton;
+	
+	protected Button deleteAnnotationButton;
+	
+	private Button affectAllAnnotationButton;
+	
+	protected KnowledgeRepository currentKnowledgeRepository = null;
+	
+	protected Vector<AnnotationType> typesList = new Vector<>();
+	
+	protected AnnotationType tagAnnotationType; // the tag annotation type if annotation mode is simple
+	
+	//protected TypedValue value_to_add;
+	
+	protected Concordance concordance;
+	
+	private CQPCorpus corpus;
+	
+	private TableViewerColumn annotationColumnViewer;
+	
+	private Font annotationColummnFont;
+	
+	private Font defaultColummnFont;
+	
+	private Button addAnnotationTypeLink;
+	
+	private Button addTypedValueLink;
+	
+	@Override
+	public String getName() {
+		return KRAnnotationUIMessages.motsPropritsInfDfaut;
+	}
+	
+	@Override
+	public boolean allowMultipleAnnotations() {
+		return true;
+	}
+	
+	public WordAnnotationToolbar() {}
+	
+	protected AnnotationType getSelectedAnnotationType() {
+		return annotations.getViewAnnotation();
+	}
+	
+	public void updateAnnotationWidgetStates() {
+		if (annotationArea == null) return; // :)
+		
+		if (getSelectedAnnotationType() != null) {
+			annotationValuesText.setEnabled(true);
+			affectAnnotationButton.setEnabled(true);
+			deleteAnnotationButton.setEnabled(true);
+		}
+		else {
+			annotationValuesText.setEnabled(false);
+			affectAnnotationButton.setEnabled(false);
+			deleteAnnotationButton.setEnabled(false);
+		}
+	}
+	
+	protected void affectAnnotationToSelection(ISelection selection) {
+		
+		final IStructuredSelection lineSelection = (IStructuredSelection) selection;
+		List<Line> lines = lineSelection.toList();
+		ArrayList<Match> matches = new ArrayList<>();
+		for (Line l : lines) {
+			matches.add(l.getMatch());
+		}
+		
+		affectAnnotationsToMatches(matches);
+	}
+	
+	protected void affectAnnotationValues(final List<? extends Match> matches, final AnnotationType type, final String svalue, JobHandler job) {
+		TypedValue value_to_add = null; // reset
+		if (matches == null || matches.size() == 0) {
+			Log.warning("No line selected. Aborting.");
+			return;
+		}
+		if (type == null) return; // no type, no annotation
+		
+		job.syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				if (matches.size() > NALERTAFFECTANNOTATIONS) {
+					ConfirmDialog dialog = new ConfirmDialog(Display.getCurrent().getActiveShell(),
+							"confirm_annotate",  //$NON-NLS-1$
+							KRAnnotationUIMessages.confirmAnnotationAffectation,
+							NLS.bind(KRAnnotationUIMessages.youAreAboutToAnnotateP0ElementsContinue, matches.size()));
+					
+					if (dialog.open() == ConfirmDialog.CANCEL) {
+						Log.info("Annotation aborted by user.");
+						matches.clear();
+					}
+				}
+			}
+		});
+		
+		// get value from combo text value
+		Log.fine(NLS.bind(KRAnnotationUIMessages.lookingForTypedValueWithIdEqualsP0, svalue));
+		final KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(type.getKnowledgeRepository());
+		value_to_add = kr.getValue(type, svalue);
+		
+		
+		if (value_to_add == null && kr instanceof LocalKnowledgeRepository) { // create or not the annotation is simple mode
+			value_to_add = kr.addValue(svalue, svalue, type.getId());
+		}
+		
+		if (value_to_add == null) {
+			job.syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					String mess = KRAnnotationUIMessages.bind(KRAnnotationUIMessages.noValueFoundWithTheP0Id, svalue);
+					Log.warning(mess);
+					MessageDialog.openError(Display.getCurrent().getActiveShell(), "Annotation canceled", mess);
+				}
+			});
+			return;
+		}
+		
+		Log.info(TXMCoreMessages.bind(KRAnnotationUIMessages.AffectP0ToSelectionEqualsP1, value_to_add.getId(), value_to_add.getTypeID(), matches.size()));
+		
+		// finally we can 'try' to create the annotations \o/
+		try {
+			//System.out.println("CREATE ANNOTATIONS");
+			HashMap<Match, List<Annotation>> existingAnnots = annotManager.createAnnotations(type, value_to_add, matches, job);
+			//System.out.println("END OF CREATE ANNOTATIONS");
+			// did we had problems ?
+			if (existingAnnots != null && existingAnnots.size() > 0) {
+				String message = NLS.bind(KRAnnotationUIMessages.couldNotAnnotateTheValueP0OnCertainSequences, value_to_add.getStandardName());
+				for (Match m : existingAnnots.keySet()) {
+					message += NLS.bind(KRAnnotationUIMessages.theSequenceP0IsOverlappingWith, m);
+					
+					for (Annotation existingAnnot : existingAnnots.get(m)) {
+						if (existingAnnot.getStart() < m.getStart()) {
+							message += TXMCoreMessages.bind(KRAnnotationUIMessages.theEndOfAStructureP0AtP1P2, existingAnnot.getType(), existingAnnot.getStart(), existingAnnot.getEnd());
+						}
+						else {
+							message += TXMCoreMessages.bind(KRAnnotationUIMessages.theStartOfAStructureP0AtP1P2, existingAnnot.getType(), existingAnnot.getStart(), existingAnnot.getEnd());
+						}
+					}
+				}
+				final String final_message = message;
+				job.syncExec(new Runnable() {
+					
+					@Override
+					public void run() {
+						MessageDialog.openInformation(editor.getSite().getShell(), KRAnnotationUIMessages.aboutAnnotations, final_message);
+					}
+				});
+			}
+			// if (history != null && !history.get(type).contains(value_to_add))
+			// history.get(type).add(value_to_add);
+			
+			if (Log.getLevel().intValue() < Level.INFO.intValue() && annotManager != null) {
+				annotManager.checkData();
+			}
+			// concordance.reloadCurrentLines();
+		}
+		catch (Exception e1) {
+			Log.warning(NLS.bind(KRAnnotationUIMessages.errorWhileAffectionAnnotationColonP0, e1));
+			Log.printStackTrace(e1);
+			return;
+		}
+		
+		job.syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				try {
+					//System.out.println("REFRESH ANNOTATIONS");
+					annotationColumn.setText("*" + annotations.getViewAnnotation().getName());
+					notifyStartOfRefresh();
+					//System.out.println("END OF REFRESH ANNOTATIONS");
+					annotationColumnViewer.getViewer().refresh();
+					//editor.refresh(false);
+				}
+				catch (Exception e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+			}
+		});
+	}
+	
+	protected void deleteAnnotationValues(ISelection selection) {
+		
+		final IStructuredSelection lineSelection = (IStructuredSelection) selection;
+		List<Line> lines = lineSelection.toList();
+		ArrayList<Match> matches = new ArrayList<>();
+		for (Line l : lines) {
+			matches.add(l.getMatch());
+		}
+		
+		deleteAnnotationValues(matches);
+	}
+	
+	protected void deleteAnnotationValues(final List<Match> matches) {
+		final AnnotationType type = getSelectedAnnotationType();
+		
+		JobHandler job = new JobHandler(KRAnnotationUIMessages.annotatingConcordanceSelection, true) {
+			
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				this.runInit(monitor);
+				try {
+					deleteAnnotationValues(matches, type, this);
+				}
+				catch (Exception e) {
+					Log.severe(NLS.bind(KRAnnotationUIMessages.errorWhileAnnotatingConcordanceSelectionColonP0, e));
+					Log.printStackTrace(e);
+					return Status.CANCEL_STATUS;
+				}
+				catch (ThreadDeath td) {
+					Log.info(KRAnnotationUIMessages.annotationCanceledByUser);
+					return Status.CANCEL_STATUS;
+				}
+				
+				return Status.OK_STATUS;
+			}
+		};
+		job.startJob(true);
+	}
+	
+	protected void deleteAnnotationValues(List<Match> matches, AnnotationType type, JobHandler job) {
+		
+		if (matches.size() == 0) {
+			Log.warning("No lines selected. Aborting.");
+			return;
+		}
+		
+		if (type == null) {
+			return;
+		}
+		
+		try {
+			if (annotManager != null && annotManager.deleteAnnotations(type, matches, job)) {
+				if (Log.getLevel().intValue() < Level.INFO.intValue()) annotManager.checkData();
+				
+			}
+			else {
+				return;
+			}
+		}
+		catch (Exception e1) {
+			Log.warning(NLS.bind(KRAnnotationUIMessages.errorWhileDeletingAnnotationColonP0, e1));
+			Log.printStackTrace(e1);
+			return;
+		}
+		
+		job.syncExec(new Runnable() {
+			
+			@Override
+			public void run() {
+				try {
+					annotationColumn.setText("*" + annotations.getViewAnnotation().getName());
+					notifyStartOfRefresh();
+					annotationColumnViewer.getViewer().refresh();
+				}
+				catch (Exception e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+			}
+		});
+	}
+	
+	protected void affectAnnotationsToMatches(final List<? extends Match> matches) {
+		final AnnotationType type = getSelectedAnnotationType();
+		final String svalue = annotationValuesText.getText();
+		
+		JobHandler job = new JobHandler(KRAnnotationUIMessages.annotatingConcordanceSelection, true) {
+			
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				this.runInit(monitor);
+				try {
+					affectAnnotationValues(matches, type, svalue, this);
+				}
+				catch (Exception e) {
+					Log.severe(NLS.bind(KRAnnotationUIMessages.errorWhileAnnotatingConcordanceSelectionColonP0, e));
+					Log.printStackTrace(e);
+					return Status.CANCEL_STATUS;
+				}
+				catch (ThreadDeath td) {
+					Log.info(KRAnnotationUIMessages.annotationCanceledByUser);
+					return Status.CANCEL_STATUS;
+				}
+				
+				return Status.OK_STATUS;
+			}
+		};
+		job.startJob(true);
+	}
+	
+	@Override
+	public boolean install(TXMEditor<? extends TXMResult> txmeditor, AnnotationExtension ext, Composite parent, int position) throws Exception {
+		
+		this.extension = ext;
+		this.editor = (ConcordanceEditor) txmeditor;
+		this.concordance = this.editor.getConcordance();
+		this.corpus = concordance.getCorpus();
+		this.annotations = new ConcordanceAnnotations(this.editor.getConcordance());
+		//annotations.computeLines(this.editor.getConcordance().getLines()); // pre-compute the annotation lines ot avoid breaking the sort and co.
+		this.annotManager = KRAnnotationEngine.getAnnotationManager(corpus);
+		
+		TableViewer viewer = this.editor.getLineTableViewer();
+		
+		// RESULT
+		if (position < 0) {
+			position = 3 + extension.getNumberOfAnnotationArea(); // after keyword column and previous annotation columns
+		}
+		
+		annotationColumnViewer = new TableViewerColumn(viewer, SWT.CENTER, position);
+		annotationColumn = annotationColumnViewer.getColumn();
+		annotationColumn.setText(KRAnnotationUIMessages.property);
+		annotationColumn.setToolTipText(KRAnnotationUIMessages.keywordsAnnotation);
+		annotationColumn.setAlignment(SWT.CENTER);
+		annotationColumn.pack();
+		annotationColumn.setResizable(true);
+		annotationColumn.addControlListener(new ConcordanceColumnSizeControlListener(annotationColumn));
+		defaultColummnFont = editor.getContainer().getFont();
+		FontData fdata = defaultColummnFont.getFontData()[0];
+		annotationColummnFont = new Font(Display.getCurrent(), fdata.getName(), fdata.getHeight(), SWT.ITALIC);
+		annotationColumnViewer.setLabelProvider(new ColumnLabelProvider() {
+			
+			@Override
+			public String getText(Object element) {
+				Line line = (Line) element;
+				AnnotationLine annotationLine = annotations.getAnnotationLine(line);
+				if (annotationLine == null) return EMPTYTEXT;
+				if (annotationLine.getAnnotation() != null) {
+					String value = annotationLine.getAnnotationValue().getStandardName();
+					Annotation a = annotationLine.getAnnotation();
+					if (value == null) value = a.getValue();
+					
+					if (a.getStart() < line.matchGetStart() - line.getLeftContextSize()) {
+						value = "… " + value; //$NON-NLS-1$
+					}
+					
+					if (a.getEnd() > line.matchGetEnd() + line.getRightContextSize()) {
+						value = value + " …"; //$NON-NLS-1$
+					}
+					return value;
+				}
+				else {
+					return EMPTYTEXT;
+				}
+			}
+			
+			@Override
+			public Font getFont(Object element) {
+				Line line = (Line) element;
+				
+				AnnotationLine annotationLine = annotations.getAnnotationLine(line);
+				if (annotationLine == null) return null;
+				
+				Annotation a = annotationLine.getAnnotation();
+				if (a == null) return null;
+				
+				String value = annotationLine.getAnnotationValue().getStandardName();
+				if (a instanceof CQPAnnotation) return null;
+				
+				return annotationColummnFont;
+			}
+		});
+		
+		List<KnowledgeRepository> krs = InitializeKnowledgeRepository.get(corpus.getMainCorpus());
+		typesList.clear();
+		Log.fine("Corpus KRs: " + krs); //$NON-NLS-1$
+		
+		currentKnowledgeRepository = KnowledgeRepositoryManager.getKnowledgeRepository(corpus.getMainCorpus().getName());
+		if (currentKnowledgeRepository == null) {
+			HashMap<String, HashMap<String, ?>> conf = new HashMap<>();
+			HashMap<String, String> access = new HashMap<>();
+			conf.put(KRAnnotationEngine.KNOWLEDGE_ACCESS, access);
+			HashMap<String, HashMap<String, String>> fields = new HashMap<>();
+			conf.put(KRAnnotationEngine.KNOWLEDGE_TYPES, fields);
+			HashMap<String, HashMap<String, String>> strings = new HashMap<>();
+			conf.put(KRAnnotationEngine.KNOWLEDGE_STRINGS, strings);
+			
+			access.put("mode", DatabasePersistenceManager.ACCESS_FILE); //$NON-NLS-1$
+			access.put("version", "0"); //$NON-NLS-1$ //$NON-NLS-2$
+			currentKnowledgeRepository = KnowledgeRepositoryManager.createKnowledgeRepository(corpus.getMainCorpus().getName(), conf);
+			KnowledgeRepositoryManager.registerKnowledgeRepository(currentKnowledgeRepository);
+			// KRAnnotationEngine.registerKnowledgeRepositoryName(corpus, corpus.getMainCorpus().getName());
+		}
+		
+		List<WordProperty> wordProperties = corpus.getProperties();
+		for (WordProperty p : wordProperties) {
+			if (p.getName().equals("id")) continue; //$NON-NLS-1$
+			AnnotationType type = currentKnowledgeRepository.getType(p.getName());
+			if (type == null) {
+				AnnotationType t = currentKnowledgeRepository.addType(p.getName(), p.getName());
+				t.setEffect(AnnotationEffect.TOKEN);
+			}
+			else if (type != null) {
+				type.setEffect(AnnotationEffect.TOKEN);
+			}
+		}
+		
+		Log.fine("KR: " + currentKnowledgeRepository); //$NON-NLS-1$
+		List<AnnotationType> krtypes = currentKnowledgeRepository.getAllAnnotationTypes();
+		for (AnnotationType type : krtypes) {
+			if (type.getEffect().equals(AnnotationEffect.TOKEN)) {
+				typesList.add(type);
+			}
+		}
+		
+		Log.fine(NLS.bind(KRAnnotationUIMessages.availableAnnotationTypesColonP0, typesList));
+		
+		annotationArea = new GLComposite(parent, SWT.NONE, KRAnnotationUIMessages.concordanceAnnotationArea);
+		annotationArea.getLayout().numColumns = 12;
+		annotationArea.getLayout().horizontalSpacing = 2;
+		annotationArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+		
+		GridData gdata = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+		gdata.widthHint = 90;
+		
+		new Label(annotationArea, SWT.NONE).setText(TXMCoreMessages.common_property);
+		
+		// Display combo with list of Annotation Type
+		annotationTypesCombo = new ComboViewer(annotationArea, SWT.READ_ONLY);
+		annotationTypesCombo.setContentProvider(new ArrayContentProvider());
+		annotationTypesCombo.setLabelProvider(new SimpleLabelProvider() {
+			
+			@Override
+			public String getColumnText(Object element, int columnIndex) {
+				return ((AnnotationType) element).getName();
+			}
+			
+			@Override
+			public String getText(Object element) {
+				return ((AnnotationType) element).getName();
+			}
+		});
+		// annotationTypesCombo.getCombo().addKeyListener(new KeyListener() {
+		//
+		// @Override
+		// public void keyReleased(KeyEvent e) {
+		// if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+		// String name = annotationTypesCombo.getCombo().getText();
+		// if (currentKnowledgeRepository.getType(name) == null) {
+		// createNewType(e, name);
+		// } else {
+		// for (AnnotationType type : typesList) {
+		// if (name.equals(type.getId())) {
+		// StructuredSelection selection = new StructuredSelection(type);
+		// annotationTypesCombo.setSelection(selection, true);
+		// break;
+		// }
+		// }
+		// }
+		// }
+		// }
+		//
+		// @Override
+		// public void keyPressed(KeyEvent e) { }
+		// });
+		
+		gdata = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+		gdata.widthHint = 200;
+		
+		annotationTypesCombo.getCombo().setLayoutData(gdata);
+		annotationTypesCombo.setInput(typesList);
+		annotationTypesCombo.getCombo().select(0);
+		annotations.setViewAnnotation(typesList.get(0));
+		annotationColumn.setText(typesList.get(0).getName());
+		// for (int i = 0 ; i < typesList.size(); i++) {
+		// String name = typesList.get(i).getName();
+		// if ("word".equals(name)) {
+		// annotations.setViewAnnotation(typesList.get(i));
+		// annotationColumn.setText(name);
+		// }
+		// }
+		
+		annotationTypesCombo.addSelectionChangedListener(new ISelectionChangedListener() {
+			
+			@Override
+			public void selectionChanged(SelectionChangedEvent event) {
+				onAnnotationTypeSelected(event);
+			}
+		});
+		
+		addAnnotationTypeLink = new Button(annotationArea, SWT.PUSH);
+		addAnnotationTypeLink.setToolTipText(KRAnnotationUIMessages.addANewCategory);
+		addAnnotationTypeLink.setImage(IImageKeys.getImage(IImageKeys.ACTION_ADD));
+		addAnnotationTypeLink.setEnabled(true);
+		addAnnotationTypeLink.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		addAnnotationTypeLink.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (currentKnowledgeRepository == null) return;
+				if (!(currentKnowledgeRepository instanceof LocalKnowledgeRepository)) return;
+				
+				LocalKnowledgeRepository kr = (LocalKnowledgeRepository) currentKnowledgeRepository;
+				
+				InputDialog dialog = new InputDialog(e.widget.getDisplay().getActiveShell(), "New property", "Enter the new property name", "", null);
+				if (dialog.open() == InputDialog.OK) {
+					String name = dialog.getValue();
+					if (name.trim().length() == 0) return;
+					String id = AsciiUtils.buildId(name);
+					AnnotationType existingType = kr.getType(id);
+					if (existingType != null) {
+						Log.warning(NLS.bind("The ''{0}'' annotation type already exists. Please use another name ({1}).", id, name));
+						annotationTypesCombo.setSelection(new StructuredSelection(existingType));
+						return;
+					}
+					AnnotationType type = kr.addType(name, id, "", AnnotationEffect.TOKEN); //$NON-NLS-1$
+					typesList.add(type);
+					
+					if (annotationTypesCombo != null) annotationTypesCombo.refresh();
+					if (typesList.size() == 1) {
+						if (annotationTypesCombo != null) annotationTypesCombo.getCombo().select(typesList.size() - 1);
+						
+						if (concordance != null) {
+							annotations.setViewAnnotation(type);
+							annotations.setAnnotationOverlap(true);
+							annotationColumn.setText(type.getId());
+							editor.fillDisplayArea(false);
+						}
+						annotationArea.layout(true);
+						
+					}
+					else {
+						if (typesList.size() > 1) {
+							if (annotationTypesCombo != null) {
+								annotationTypesCombo.setSelection(new StructuredSelection(typesList.get(typesList.size() - 1)));
+							}
+						}
+					}
+					annotations.setViewAnnotation(type);
+					annotationTypesCombo.setSelection(new StructuredSelection(typesList.get(typesList.size() - 1)));
+					annotationArea.layout(true);
+					KRView.refresh();
+					updateAnnotationWidgetStates();
+				}
+				else {
+					Log.info("Creation aborted.");
+				}
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		equalLabel = new Label(annotationArea, SWT.NONE);
+		equalLabel.setText("="); //$NON-NLS-1$
+		equalLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		
+		annotationValuesText = new Text(annotationArea, SWT.BORDER);
+		annotationValuesText.setToolTipText(KRAnnotationUIMessages.enterAValueForAnId);
+		GridData gdata2 = new GridData(SWT.FILL, SWT.CENTER, false, false);
+		gdata2.widthHint = 200;
+		annotationValuesText.setLayoutData(gdata2);
+		annotationValuesText.addKeyListener(new KeyListener() {
+			
+			@Override
+			public void keyReleased(KeyEvent e) {
+				if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+					affectAnnotationToSelection(editor.getLineTableViewer().getSelection());
+				}
+			}
+			
+			@Override
+			public void keyPressed(KeyEvent e) {}
+		});
+		
+		addTypedValueLink = new Button(annotationArea, SWT.PUSH);
+		addTypedValueLink.setText("..."); //$NON-NLS-1$
+		addTypedValueLink.setToolTipText(KRAnnotationUIMessages.selectAValueAmongTheList);
+		addTypedValueLink.setEnabled(true);
+		addTypedValueLink.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		addTypedValueLink.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (currentKnowledgeRepository == null) return;
+				if (!(currentKnowledgeRepository instanceof LocalKnowledgeRepository)) return;
+				
+				AnnotationType type = getSelectedAnnotationType();
+				if (type == null) return;
+				
+				LocalKnowledgeRepository kr = (LocalKnowledgeRepository) currentKnowledgeRepository;
+				
+				ListDialog dialog = new ListDialog(e.widget.getDisplay().getActiveShell());
+				String title = currentKnowledgeRepository.getString(editor.getLocale(), "ConcordancesEditor_100"); //$NON-NLS-1$
+				if (title == null) title = KRAnnotationUIMessages.availableValuesForP0;
+				dialog.setTitle(ConcordanceUIMessages.bind(title, type.getName()));// +"valeurs de "+type.getName());
+				dialog.setContentProvider(new ArrayContentProvider());
+				dialog.setLabelProvider(new SimpleLabelProvider() {
+					
+					@Override
+					public String getColumnText(Object element, int columnIndex) {
+						if (element instanceof TypedValue)
+							return ((TypedValue) element).getId();
+						return element.toString();
+					}
+				});
+				List<TypedValue> values;
+				try {
+					values = kr.getValues(type);
+				}
+				catch (Exception e1) {
+					e1.printStackTrace();
+					return;
+				}
+				dialog.setInput(values);
+				if (dialog.open() == InputDialog.OK) {
+					TypedValue value = (TypedValue) dialog.getResult()[0];
+					String name = value.getId();
+					if (name.trim().length() == 0) return;
+					
+					annotationValuesText.setText(name);
+				}
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		new Label(annotationArea, SWT.NONE).setText(" ");
+		
+		affectAnnotationButton = new Button(annotationArea, SWT.PUSH);
+		affectAnnotationButton.setText(KRAnnotationUIMessages.oK);
+		affectAnnotationButton.setToolTipText(KRAnnotationUIMessages.proceedToAnnotation);
+		affectAnnotationButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		affectAnnotationButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				affectAnnotationToSelection(editor.getLineTableViewer().getSelection());
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		deleteAnnotationButton = new Button(annotationArea, SWT.PUSH);
+		deleteAnnotationButton.setText(KRAnnotationUIMessages.delete);
+		deleteAnnotationButton.setToolTipText(KRAnnotationUIMessages.delete);
+		deleteAnnotationButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		deleteAnnotationButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				deleteAnnotationValues(editor.getLineTableViewer().getSelection());
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		affectAllAnnotationButton = new Button(annotationArea, SWT.PUSH);
+		affectAllAnnotationButton.setText(KRAnnotationUIMessages.all);
+		affectAllAnnotationButton.setToolTipText(KRAnnotationUIMessages.proceedToAnnotation);
+		affectAllAnnotationButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		affectAllAnnotationButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				
+				try {
+					List<? extends Match> matches = concordance.getMatches();
+					affectAnnotationsToMatches(matches);
+				}
+				catch (Exception e1) {
+					Log.severe(NLS.bind(KRAnnotationUIMessages.errorWhileAnnotatingConcordanceColonP0, e1.getLocalizedMessage()));
+					Log.printStackTrace(e1);
+					return;
+				}
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		addAnnotationTypeButton = new Button(annotationArea, SWT.PUSH);
+		addAnnotationTypeButton.setLayoutData(new GridData(GridData.END, GridData.CENTER, true, false));
+		addAnnotationTypeButton.setToolTipText(KRAnnotationUIMessages.addANewCategory);
+		addAnnotationTypeButton.setImage(IImageKeys.getImage(IImageKeys.ACTION_ADD));
+		addAnnotationTypeButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				try {
+					// int position = -1;
+					// TableColumn[] columns = editor.getLineTableViewer().getTable().getColumns();
+					// TableColumn column = annotationColumnViewer.getColumn();
+					// for (int i = 0 ; i < columns.length ; i++) {
+					// if (columns[i] == column) {
+					// position = i + 1; // after the current column
+					// }
+					// }
+					// int position = 3 + extension.getNumberOfAnnotationArea();
+					extension.openAnnotationMode(new WordAnnotationToolbar(), -1);
+				}
+				catch (Exception e1) {
+					// TODO Auto-generated catch block
+					e1.printStackTrace();
+				}
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		Button closeButton = new Button(annotationArea, SWT.PUSH);
+		closeButton.setToolTipText(KRAnnotationUIMessages.closeTheToolbarWithoutSaving);
+		closeButton.setImage(IImageKeys.getImage(IImageKeys.ACTION_DELETE));
+		
+		closeButton.addSelectionListener(new SelectionListener() {
+			
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				extension.closeArea(WordAnnotationToolbar.this, true);
+			}
+			
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {}
+		});
+		
+		updateAnnotationWidgetStates();
+		
+		editor.layout(true);
+		
+//		ext.getSaveButton().setEnabled(true);
+//		viewer.refresh();
+		return true;
+	}
+	
+	protected void onAnnotationTypeSelected(SelectionChangedEvent event) {
+		IStructuredSelection sel = (IStructuredSelection) annotationTypesCombo.getSelection();
+		AnnotationType type = (AnnotationType) sel.getFirstElement();
+		if (type == null) return;
+		
+		if (type.getSize() != AnnotationType.ValuesSize.LARGE) {
+			try {
+				KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(type.getKnowledgeRepository());
+				typeValuesList = kr.getValues(type);
+			}
+			catch (Exception e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+		
+		annotationColumn.setText(type.getName());
+		
+		annotations.setViewAnnotation(type);
+		annotations.setAnnotationOverlap(true);
+		try {
+			notifyStartOfRefresh();
+			annotationColumnViewer.getViewer().refresh();
+		}
+		catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+		updateAnnotationWidgetStates();
+	}
+	
+	protected void createNewType(TypedEvent e, String typeName) {
+		
+		if (currentKnowledgeRepository == null) return;
+		if (!(currentKnowledgeRepository instanceof LocalKnowledgeRepository)) return;
+		
+		LocalKnowledgeRepository kr = (LocalKnowledgeRepository) currentKnowledgeRepository;
+		if (typeName == null) typeName = ""; //$NON-NLS-1$
+		InputDialog dialog = new InputDialog(e.widget.getDisplay().getActiveShell(), KRAnnotationUIMessages.nouvelleProprit, KRAnnotationUIMessages.nomDeLaPropritPatternEqualsazaz09Plus, typeName,
+				null);
+		if (dialog.open() == InputDialog.OK) {
+			String name = dialog.getValue();
+			if (name.trim().length() == 0) return;
+			String baseid = AsciiUtils.buildId(name);
+			String id = AsciiUtils.buildId(name);
+			int c = 1;
+			while (kr.getType(id) != null) {
+				id = baseid + "_" + (c++); //$NON-NLS-1$
+			}
+			AnnotationType type = kr.addType(name, id, "", AnnotationEffect.TOKEN); //$NON-NLS-1$
+			typesList.add(type);
+			annotationTypesCombo.refresh();
+			StructuredSelection selection = new StructuredSelection(type);
+			annotationTypesCombo.setSelection(selection, true);
+			
+			// if (annotationTypesCombo != null) annotationTypesCombo.refresh();
+			// if (typesList.size() == 1) {
+			// if (annotationTypesCombo != null) annotationTypesCombo.getCombo().select(0);
+			// annotations.setViewAnnotation(type);
+			// annotations.setAnnotationOverlap(true);
+			// try {
+			// editor.refresh(false);
+			// } catch (Exception e1) {
+			// // TODO Auto-generated catch block
+			// e1.printStackTrace();
+			// }
+			// annotationArea.layout(true);
+			// } else {
+			// if (typesList.size() > 1) {
+			// if (annotationTypesCombo != null) {
+			// annotationTypesCombo.getCombo().select(typesList.size()-1);
+			// }
+			// }
+			// }
+			// KRView.refresh();
+			// updateAnnotationWidgetStates();
+			
+			// onAnnotationTypeSelected(null);
+		}
+		else {
+			Log.info("Creation aborted.");
+		}
+	}
+	
+	@Override
+	public boolean save() {
+		try {
+			AnnotationManager am = KRAnnotationEngine.getAnnotationManager(WordAnnotationToolbar.this.corpus);
+			if (am != null && am.hasChanges()) {
+				// && MessageDialog.openConfirm(e.display.getActiveShell(), "Confirm annotation save", "Saving annotation will close this editor. Are you sure you want to save annotations right now
+				// ?")
+				JobHandler saveJob = SaveAnnotations.save(WordAnnotationToolbar.this.corpus.getMainCorpus());
+				if (saveJob == null || saveJob.getResult() == Status.CANCEL_STATUS) {
+					Log.warning("Fail to save annotations of the corpus.");
+					return false;
+				}
+				else {
+					if (annotationColumn != null && !annotationColumn.isDisposed()) {
+						annotationColumn.setText(annotations.getViewAnnotation().getName());
+					}
+					return true; // something was saved
+				}
+			}
+			else {
+				return false;
+			}
+		}
+		catch (Exception ex) {
+			ex.printStackTrace();
+			return false;
+		}
+	}
+	
+	@Override
+	public boolean hasChanges() {
+		AnnotationManager am;
+		try {
+			am = KRAnnotationEngine.getAnnotationManager(corpus);
+			if (am != null && am.hasChanges()) {
+				return am.hasChanges();
+			}
+			else {
+				return false;
+			}
+		}
+		catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+			return false;
+		}
+	}
+	
+	@Override
+	public boolean notifyStartOfCompute() throws Exception {
+		if (annotationArea == null) return false;
+		if (annotationArea.isDisposed()) return false;
+		
+		AnnotationType type = getSelectedAnnotationType();
+		if (type != null) {
+			annotations.setViewAnnotation(type);
+			annotations.setAnnotationOverlap(true);
+		}
+		
+		return true;
+	}
+	
+	@Override
+	public boolean notifyEndOfCompute() throws Exception {
+		return true;
+	}
+	
+	@Override
+	public boolean isAnnotationEnable() {
+		return annotationArea != null;
+	}
+	
+	@Override
+	public void notifyStartOfRefresh() throws Exception {
+		if (annotationArea == null) return;
+		if (annotationArea.isDisposed()) return;
+		
+		List<Line> lines = concordance.getLines(concordance.getTopIndex(), concordance.getTopIndex() + concordance.getNLinePerPage());
+		//List<Line> lines = concordance.getLines();
+		annotations.computeLines(lines);
+		
+		updateAnnotationWidgetStates();
+		
+		// update annotation column width
+		if (annotationArea != null) {
+			//annotationColumn.pack();
+			
+			annotationColumn.setResizable(true);
+		}
+		else {
+			annotationColumn.setWidth(0);
+		}
+		
+		annotationColumnViewer.getViewer().refresh();
+	}
+	
+	@Override
+	protected void _close() {
+		
+		if (!annotationColumn.isDisposed()) annotationColumn.dispose();
+		if (!annotationArea.isDisposed()) annotationArea.dispose();
+		extension.layout();
+	}
+	
+	@Override
+	public void notifyEndOfRefresh() throws Exception {
+		// TODO Auto-generated method stub
+		
+	}
+	
+	@Override
+	public void notifyStartOfCreatePartControl() throws Exception {
+		// TODO Auto-generated method stub
+	}
+	
+	@Override
+	public Class<? extends TXMResult> getAnnotatedTXMResultClass() {
+		return Concordance.class;
+	}
+	
+	@Override
+	public boolean isDirty() {
+		if (annotManager != null) {
+			return annotManager.isDirty();
+		}
+		return false;
+	}
+	
+	@Override
+	public boolean discardChanges() {
+		return false;
+	}
+	
+	@Override
+	public boolean needToUpdateIndexes() {
+		return KRAnnotationPreferences.getInstance().getBoolean(KRAnnotationPreferences.UPDATE);
+	}
+	
+	@Override
+	public boolean needToUpdateEditions() {
+		return KRAnnotationPreferences.getInstance().getBoolean(KRAnnotationPreferences.UPDATE_EDITION);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/WordAnnotationToolbar.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/ConcordanceAnnotations.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/ConcordanceAnnotations.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/ConcordanceAnnotations.java	(revision 3653)
@@ -0,0 +1,246 @@
+package org.txm.annotation.kr.rcp.concordance;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.TreeMap;
+
+import org.eclipse.osgi.util.NLS;
+import org.txm.annotation.kr.core.Annotation;
+import org.txm.annotation.kr.core.AnnotationManager;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.TypedValue;
+import org.txm.concordance.core.functions.Concordance;
+import org.txm.concordance.core.functions.Line;
+import org.txm.objects.Match;
+import org.txm.utils.logger.Log;
+
+/**
+ * Annotation values to display in the current concordance shown lines
+ * 
+ * Call getLines(conclines, from, to) 
+ * 
+ * @author mdecorde
+ *
+ */
+public class ConcordanceAnnotations {
+	
+	Concordance concordance;
+	
+	private AnnotationType viewAnnotation;
+	
+	public ConcordanceAnnotations(Concordance concordance) {
+		this.concordance = concordance;
+	}
+	
+	private boolean overlapAnnotation;
+
+	private HashMap<Line, AnnotationLine> lines;
+
+	private List<Line> concordanceLines;
+	public void setAnnotationOverlap(boolean overlap) {
+		overlapAnnotation = overlap;
+	}
+	public boolean getAnnotationOverlap() {
+		return overlapAnnotation;
+	}
+	
+	public HashMap<Line, AnnotationLine> computeLines(List<Line> concordanceLines) throws Exception {
+
+		this.concordanceLines = concordanceLines;
+		
+//		HashMap<Match, Line> matches = new HashMap<Match, Line>();
+//		for (Line line : concordanceLines) {
+//			matches.put(line.getMatch(), line);
+//		}
+//		
+//		ArrayList<Match> sorted_matches = new ArrayList<Match>(matches.keySet());
+//		Collections.sort(sorted_matches);
+//		
+//		List<Annotation> ann = getAnnotationForMatches(sorted_matches, overlapAnnotation);
+//		lines = new HashMap<Line, AnnotationLine>();
+//		
+//		for (int i = 0 ; i < ann.size() ; i++) {
+//			Annotation a = ann.get(i);
+//			AnnotationLine aline = new AnnotationLine(a, getAnnotationTypedValue(a));
+//			lines.put(matches.get(sorted_matches.get(i)), aline);
+//		}
+//		
+//		return lines; // TODO find a way to add with lazy method
+		
+		LinkedHashMap<Match, Line> matches = new LinkedHashMap<Match, Line>();
+		for (Line line : concordanceLines) {
+			matches.put(line.getMatch(), line);
+		}
+		
+		ArrayList<Match> sorted_matches = new ArrayList<Match>(matches.keySet());
+		Collections.sort(sorted_matches);
+		
+		List<Annotation> ann = getAnnotationForMatches(sorted_matches, overlapAnnotation);
+		lines = new HashMap<Line, AnnotationLine>();
+		
+		for (int i = 0 ; i < ann.size() ; i++) {
+			Annotation a = ann.get(i);
+			AnnotationLine aline = new AnnotationLine(a, getAnnotationTypedValue(a));
+			lines.put(matches.get(sorted_matches.get(i)), aline);
+		}
+		
+		return lines; // TODO find a way to add with lazy method
+	}
+	
+	private String findAnnotationForLine(Match match, List<Annotation> annots, boolean overlap) {
+		String annotationValue = "";
+		if (annots!=null) {
+			if (!annots.isEmpty()) {
+				for (Annotation annot : annots) {
+					if (overlap) {
+						if ((annot.getStart()<=match.getStart() && annot.getEnd()>=match.getEnd()) || (annot.getStart()>match.getStart() && annot.getEnd()<match.getEnd())
+								) {
+							annotationValue = annot.getValue(); 
+							// use the first Annotation found, the one stored in the temporary HSQL database
+							//should be modified to display a list of annotation values corresponding to the match positions (or wrapped if overlap is admitted)
+						}
+					} else {
+						if (annot.getStart()==match.getStart() && annot.getEnd()==match.getEnd()) {
+							annotationValue = annot.getValue(); 
+							// use the first Annotation found, the one stored in the temporary HSQL database
+						}
+					}
+				}
+			}
+		}
+		return annotationValue;
+	}
+	
+	public TypedValue getAnnotationTypedValue(Annotation annotation) { 
+
+		TypedValue annotationValue = null;
+		if (annotation!=null) {
+			annotationValue = viewAnnotation.getTypedValue(annotation.getValue());
+			if (annotationValue == null) { // the annotation is not stored in the KR type -> the annotation is surely built with the CQPAnnotationManager
+				//System.out.println("WARNING: no annotation value found for value id="+annotation.getValue()+" - will be created.");
+				annotationValue = new TypedValue(annotation.getValue(), annotation.getValue(), annotation.getType());
+			}
+		}
+		
+		return annotationValue;
+	}
+
+	/**
+	 * 
+	 * @return the current annotation type
+	 */
+	public AnnotationType getViewAnnotation() {
+		return viewAnnotation;
+	}
+
+
+	private List<Annotation> prepareAnnotationsList(List<Match> matches, List<Annotation> annotations, boolean overlap){
+		List<Annotation> annotsList = new ArrayList<Annotation>();
+
+		int iMatch = 0;
+		int iAnnotation = 0;
+		int nMatch = matches.size();
+		int nAnnotations = annotations.size();
+
+		while (iMatch < nMatch && iAnnotation < nAnnotations) {
+			if (overlap) {
+				if (matches.get(iMatch).getEnd() < annotations.get(iAnnotation).getStart()) {
+					iMatch++;
+					annotsList.add(null); // nothing for this match
+				} else if (annotations.get(iAnnotation).getEnd() < matches.get(iMatch).getStart()) {
+					iAnnotation++;
+				} else {
+					annotsList.add(annotations.get(iAnnotation));
+					iMatch++;
+				}
+			} else {
+				if (matches.get(iMatch).getEnd() < annotations.get(iAnnotation).getStart()) {
+					iMatch++;
+					annotsList.add(null); // nothing for this match
+				} else if (annotations.get(iAnnotation).getEnd() < matches.get(iMatch).getStart()) {
+					iAnnotation++;
+				} else if (annotations.get(iAnnotation).getStart() == matches.get(iMatch).getStart() && 
+						annotations.get(iAnnotation).getEnd() == matches.get(iMatch).getEnd()) {
+					annotsList.add(annotations.get(iAnnotation));
+					iMatch++;
+					iAnnotation++;
+				} else {
+					iAnnotation++;
+				}
+			}
+		}
+
+		while (annotsList.size() < matches.size() ) annotsList.add(null); // fill matches that were not process due to no more annotations
+
+		return annotsList;
+	}
+
+	private HashMap<Match, Annotation> prepareAnnotationsMap(List<Match> matches, List<Annotation> annots, boolean overlap){
+		HashMap<Match, Annotation> annotsList = new HashMap<Match, Annotation>();
+		for (Match m : matches) {
+			boolean hasAnnotations = false;
+			if (annots!=null) {
+				if (!annots.isEmpty()) {
+					for (Annotation annot : annots) {
+						if (overlap){
+							if ((annot.getStart() <= m.getStart() && m.getStart() <= annot.getEnd() && m.getEnd() >= annot.getEnd()) || 
+									(annot.getStart() <= m.getEnd() && m.getEnd() <= annot.getEnd() && m.getStart() <= annot.getStart()) 
+									|| !(annot.getEnd() < m.getStart() || annot.getStart() > m.getEnd())){
+								annotsList.put(m, annot);
+								hasAnnotations = true;
+							}
+						} else {
+							if (annot.getStart()==m.getStart() && annot.getEnd()==m.getEnd()) {
+								annotsList.put(m, annot); 
+								hasAnnotations = true;
+							}
+						}
+					}
+				}
+			}
+			if (!hasAnnotations) {
+				annotsList.put(m, null);
+			}
+		}
+		return annotsList;
+	}
+
+	public List<Annotation> getAnnotationForMatches(List<Match> subsetMatch, boolean overlapAnnotation) throws Exception {
+		
+		AnnotationManager am = KRAnnotationEngine.getAnnotationManager(concordance.getCorpus());
+		
+		//List<Annotation> allAnnotations = null;
+		List<Annotation> annotationsPerMatch = new ArrayList<Annotation>();
+		if (viewAnnotation != null && am != null) {
+			try {
+				annotationsPerMatch = am.getAnnotationsForMatches(viewAnnotation, subsetMatch, overlapAnnotation);
+				//System.out.println("annotationsPerMatch: "+annotationsPerMatch);
+			} catch (Exception e) {
+				Log.warning(NLS.bind("Error while reading annotation {0} and with {1} matches", viewAnnotation, subsetMatch.size()));
+				Log.printStackTrace(e);
+			}
+		}
+		return annotationsPerMatch;
+	}
+
+	public void setViewAnnotation(AnnotationType type) {
+		viewAnnotation = type;
+		//concordance.resetLines();
+	}
+	
+	/**
+	 * 
+	 * @param i the relative position of the AnnotationLine in the lines list
+	 * 
+	 * @return the AnnotationLine pointed by 'i'. May return null if i is wrong.
+	 */
+	public AnnotationLine getAnnotationLine(Line line) {
+		if (lines == null) return null;
+		if (!lines.containsKey(line)) return null;
+		return lines.get(line);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/src/org/txm/annotation/kr/rcp/concordance/ConcordanceAnnotations.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/build.properties
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/build.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/build.properties	(revision 3653)
@@ -0,0 +1,10 @@
+#Fri Jul 06 10:25:03 CEST 2018
+output..=bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml,\
+               icons/,\
+               OSGI-INF/,\
+               OSGI-INF/l10n/bundle.properties
+source..=src/
+#qualifier=svn

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/build.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/OSGI-INF/l10n/bundle.properties
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/OSGI-INF/l10n/bundle.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/OSGI-INF/l10n/bundle.properties	(revision 3653)
@@ -0,0 +1,22 @@
+#TXM OSGI messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+Bundle-Name=KR Annotation RCP
+command.label=Knowledge Repository
+command.label.0=Export CQP Annotations
+command.label.1=CQP Annotations in Table format (.csv)
+command.label.111=Save Annotations
+command.label.2=CQP Annotation from Table (.csv)
+command.name=Rename Word Property
+command.name.0=Save CQP Annotations
+command.name.1=Open Knowledge Repository View
+command.name.2=Copy Annotation Identifier
+command.name.3=Reload Knowledge Repository View
+command.name.4=Open Annotation Information Page
+command.name.5=Delete
+command.name.6=Add
+command.name.7=Export CQP Annotations
+command.name.8=Export in table (.csv)
+command.name.9=Import from table (.csv)
+page.name=Annotation
+page.name.0=CQP
+view.name=Knowledge Repository

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/OSGI-INF/l10n/bundle.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/OSGI-INF/l10n/bundle_ru.properties
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/OSGI-INF/l10n/bundle_ru.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/OSGI-INF/l10n/bundle_ru.properties	(revision 3653)
@@ -0,0 +1,14 @@
+#TXM OSGI messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+command.label=Ð¥ÑÐ°Ð½Ð¸Ð»Ð¸ÑÐµ
+command.label.0=Ð­ÐºÑÐ¿Ð¾ÑÑÐ¸ÑÐ¾Ð²Ð°ÑÑ Ð°Ð½Ð½Ð¾ÑÐ°ÑÐ¸Ñ
+command.name=ÐÐµÑÐµÐºÐ¾Ð´Ð¸ÑÐ¾Ð²Ð°ÑÑ
+command.name.0=Ð¡Ð¾ÑÑÐ°Ð½Ð¸ÑÑ Ð°Ð½Ð½Ð¾ÑÐ°ÑÐ¸Ñ
+command.name.1=ÐÑÐºÑÑÑÑ Ð²Ð¸Ð´ Ð¥ÑÐ°Ð½Ð¸Ð»Ð¸ÑÐµ
+command.name.2=ÐÐ¾Ð¿Ð¸ÑÐ¾Ð²Ð°ÑÑ
+command.name.3=ÐÐ±Ð½Ð¾Ð²Ð¸ÑÑ
+command.name.4=ÐÐ½ÑÐ¾ÑÐ¼Ð°ÑÐ¸Ñ
+command.name.5=Ð£Ð´Ð°Ð»Ð¸ÑÑ
+command.name.6=ÐÐ¾Ð±Ð°Ð²Ð¸ÑÑ
+command.name.7=Ð­ÐºÑÐ¿Ð¾ÑÑÐ¸ÑÐ¾Ð²Ð°ÑÑ Ð°Ð½Ð½Ð¾ÑÐ°ÑÐ¸Ñ
+view.name=Ð¥ÑÐ°Ð½Ð¸Ð»Ð¸ÑÐµ

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/OSGI-INF/l10n/bundle_ru.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/OSGI-INF/l10n/bundle_fr.properties
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/OSGI-INF/l10n/bundle_fr.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/OSGI-INF/l10n/bundle_fr.properties	(revision 3653)
@@ -0,0 +1,21 @@
+#TXM OSGI messages generated by the PluginMessagesManager class
+#Fri Jun 24 09:43:12 CEST 2022
+command.label=R�f�rentiel de connaissances
+command.label.0=Exporter les annotations CQP
+command.label.1=Annotations CQP au format Table (.csv)...
+command.label.111=Enregistrer les annotations CQP
+command.label.2=Annotations CQP depuis une table (.csv)
+command.name=Renommer la propri�t� de mot
+command.name.0=Sauvegarder les annotations CQP
+command.name.1=Ouvrir la vue du r�f�rentiel de connaissances
+command.name.2=Copier l''identifiant d''annotation
+command.name.3=Recharger la vue du r�f�rentiel de connaissances
+command.name.4=Ouvrir la page d''information sur les annotations
+command.name.5=Supprimer
+command.name.6=Ajouter
+command.name.7=Exporter les annotations CQP
+command.name.8=Exporter dans une table (.csv)
+command.name.9=Importer depuis une table (.csv)
+page.name=Annotation
+page.name.0=CQP
+view.name=R�f�rentiel de connaissances

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/OSGI-INF/l10n/bundle_fr.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/icons/functions/pencil_save.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/icons/functions/pencil_save.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/icons/functions/pencil.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/icons/functions/pencil.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/icons/functions/save.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/icons/functions/save.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/icons/popup_menu.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/icons/popup_menu.gif
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/plugin.xml
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/plugin.xml	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/plugin.xml	(revision 3653)
@@ -0,0 +1,399 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>  
+   <extension
+         point="org.eclipse.ui.commands">
+               <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.rcp.commands.workspace.RecodeCorpus"
+            id="org.txm.rcp.commands.workspace.RecodeCorpus"
+            name="%command.name">
+      </command>
+            <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.kr.rcp.commands.SaveAnnotations"
+            id="org.txm.rcp.commands.annotation.SaveAnnotations"
+            name="%command.name.0">
+      </command>
+            <command
+            defaultHandler="org.txm.annotation.kr.rcp.commands.krview.OpenKRView"
+            id="org.txm.rcp.commands.krview.OpenKRView"
+            name="%command.name.1">
+      </command>
+      <command
+            defaultHandler="org.txm.annotation.kr.rcp.commands.krview.Copy"
+            id="org.txm.rcp.commands.krview.Copy"
+            name="%command.name.2">
+      </command>
+      <command
+            defaultHandler="org.txm.annotation.kr.rcp.commands.krview.Reload"
+            id="org.txm.rcp.commands.krview.Reload"
+            name="%command.name.3">
+      </command>
+      <command
+            defaultHandler="org.txm.annotation.kr.rcp.commands.krview.Informations"
+            id="org.txm.rcp.commands.krview.Informations"
+            name="%command.name.4">
+      </command>
+      <command
+            defaultHandler="org.txm.annotation.kr.rcp.commands.krview.Delete"
+            id="org.txm.rcp.commands.krview.Delete"
+            name="%command.name.5">
+      </command>
+      <command
+            defaultHandler="org.txm.annotation.kr.rcp.commands.krview.Add"
+            id="org.txm.rcp.commands.krview.Add"
+            name="%command.name.6">
+      </command>
+      <command
+            defaultHandler="org.txm.annotation.kr.rcp.commands.ExportStandoff"
+            id="org.txm.rcp.commands.annotation.ExportStandoff"
+            name="%command.name.7">
+      </command>
+      <command
+            categoryId="org.txm.rcp.category.txm"
+            defaultHandler="org.txm.annotation.kr.rcp.commands.SaveAnnotationsAndUpdateCorpus"
+            id="org.txm.annotation.kr.rcp.commands.SaveAnnotationsAndUpdateCorpus"
+            name="%command.label.111">
+      </command>
+      <command
+            defaultHandler="org.txm.annotation.kr.rcp.commands.ExportTable"
+            id="org.txm.annotation.kr.rcp.commands.ExportTable"
+            name="%command.name.8">
+      </command>
+      <command
+            defaultHandler="org.txm.annotation.kr.rcp.commands.ImportTable"
+            id="org.txm.annotation.kr.rcp.commands.ImportTable"
+            name="%command.name.9">
+      </command>
+   </extension>
+  <extension
+        point="org.eclipse.ui.preferencePages">
+     <page
+           category="org.txm.annotation.rcp.preferences.AnnotationPreferencePage"
+           class="org.txm.annotation.kr.rcp.preferences.KRAnnotationPreferencePage"
+           id="org.txm.annotation.kr.rcp.preferences.KRAnnotationPreferencePage"
+           name="%page.name.0">
+     </page>
+  </extension>
+     <extension
+         point="org.eclipse.ui.views">
+      <view
+            category="org.txm.rcp"
+            class="org.txm.annotation.kr.rcp.views.knowledgerepositories.KRView"
+            id="org.txm.annotation.kr.rcp.views.knowledgerepositories.KRView"
+            name="%view.name"
+            restorable="true">
+      </view>
+   </extension>
+  <extension
+         point="org.eclipse.ui.bindings">
+      <key
+            commandId="org.txm.rcp.commands.krview.Add"
+            contextId="org.txm.rcp.annotation.krview"
+            schemeId="org.txm.rcp.scheme"
+            sequence="Ctrl+A">
+      </key>
+      <key
+            commandId="org.txm.rcp.commands.krview.Reload"
+            contextId="org.txm.rcp.annotation.krview"
+            schemeId="org.txm.rcp.scheme"
+            sequence="Ctrl+R">
+      </key>
+      <key
+            commandId="org.txm.rcp.commands.krview.Informations"
+            contextId="org.txm.rcp.annotation.krview"
+            schemeId="org.txm.rcp.scheme"
+            sequence="Ctrl+I">
+      </key>
+      <key
+            commandId="org.txm.rcp.commands.krview.Copy"
+            contextId="org.txm.rcp.annotation.krview"
+            schemeId="org.txm.rcp.scheme"
+            sequence="Ctrl+C">
+      </key>
+      <key
+            commandId="org.txm.rcp.commands.krview.Delete"
+            contextId="org.txm.rcp.annotation.krview"
+            schemeId="org.txm.rcp.scheme"
+            sequence="Ctrl+D">
+      </key>
+   </extension>
+  <extension
+        point="org.eclipse.ui.menus">
+     <menuContribution
+           allPopups="false"
+           locationURI="menu:menu.display.views?before=menu.display.views.separator">
+           <command
+                     commandId="org.txm.rcp.commands.krview.OpenKRView"
+                     label="%command.label"
+                     style="push">
+               </command>
+     </menuContribution>
+     <menuContribution
+            locationURI="popup:org.txm.annotation.kr.rcp.views.knowledgerepositories.KRView">
+         <command
+               commandId="org.txm.rcp.commands.krview.Copy"
+               style="push"
+               tooltip="%command.tooltip.89">
+         </command>
+         <command
+               commandId="org.txm.rcp.commands.krview.Reload"
+               style="push"
+               tooltip="%command.tooltip.90">
+            <visibleWhen
+                  checkEnabled="false">
+               <reference
+                     definitionId="OneKRSelected">
+               </reference>
+            </visibleWhen>
+         </command>
+         <command
+               commandId="org.txm.rcp.commands.krview.Informations"
+               style="push"
+               tooltip="%command.tooltip.93">
+         </command>
+         <command
+               commandId="org.txm.rcp.commands.krview.Add"
+               style="push"
+               tooltip="%command.tooltip.94">
+            <visibleWhen
+                  checkEnabled="false">
+               <or>
+                  <reference
+                        definitionId="OneLocalKRSelected">
+                  </reference>
+                  <reference
+                        definitionId="OneAnnotationTypeSelected">
+                  </reference>
+               </or>
+            </visibleWhen>
+         </command>
+         <command
+               commandId="org.txm.rcp.commands.krview.Delete"
+               style="push"
+               tooltip="%command.tooltip.95">
+            <visibleWhen
+                  checkEnabled="false">
+               <or>
+                  <reference
+                        definitionId="OneAnnotationTypeSelected">
+                  </reference>
+                  <reference
+                        definitionId="OneTypedValueSelected">
+                  </reference>
+               </or>
+            </visibleWhen>
+         </command>
+      </menuContribution>
+     <menuContribution
+           allPopups="false"
+           locationURI="menu:menu.file.export.properties">
+        <command
+              commandId="org.txm.rcp.commands.annotation.ExportStandoff"
+              id="menu.file.export.exporttei"
+              label="%command.label.0"
+              style="push">
+           <visibleWhen
+                 checkEnabled="false">
+              <reference
+                    definitionId="OneMainCorpusSelected">
+              </reference>
+           </visibleWhen>
+        </command>
+     </menuContribution>
+     <menuContribution
+           allPopups="false"
+           locationURI="menu:menu.file.export.annotations">
+           <command
+                 commandId="org.txm.annotation.kr.rcp.commands.ExportTable"
+                 id="menu.file.export.exporttable"
+                 label="%command.label.1"
+                 style="push">
+              <visibleWhen
+                    checkEnabled="false">
+                 <reference
+                       definitionId="OneMainCorpusSelected">
+                 </reference>
+              </visibleWhen>
+           </command>
+     </menuContribution>
+     <menuContribution
+           allPopups="false"
+           locationURI="menu:corporaview.menu.file.export?after=org.txm.rcp.views.corpora.CorporaView.annotation">
+            <command
+                  commandId="org.txm.rcp.commands.annotation.ExportStandoff"
+                  label="%command.label.0"
+                  style="push">
+               <visibleWhen
+                     checkEnabled="false">
+                  <reference
+                        definitionId="OneMainCorpusSelected">
+                  </reference>
+               </visibleWhen>
+            </command>
+            <command
+                  commandId="org.txm.annotation.kr.rcp.commands.ExportTable"
+                  label="%command.label.1"
+                  style="push">
+               <visibleWhen
+                     checkEnabled="false">
+                  <reference
+                        definitionId="OneMainCorpusSelected">
+                  </reference>
+               </visibleWhen>
+            </command>
+     </menuContribution>
+     <menuContribution
+           allPopups="false"
+           locationURI="menu:menu.corpus?after=menu.corpus.build">
+           <command
+                  commandId="org.txm.annotation.kr.rcp.commands.SaveAnnotationsAndUpdateCorpus"
+                  icon="icons/functions/pencil_save.png"
+                  label="%command.label.111"
+                  style="push">
+            </command>
+     </menuContribution>
+     <menuContribution
+           allPopups="false"
+           locationURI="popup:org.txm.rcp.views.corpora.CorporaView">
+        <command
+              commandId="org.txm.annotation.kr.rcp.commands.SaveAnnotationsAndUpdateCorpus"
+              icon="icons/functions/pencil_save.png"
+              label="%command.label.111"
+              style="push">
+           <visibleWhen
+                 checkEnabled="false">
+              <reference
+                    definitionId="CorpusNeedtoSaveAnnotation">
+              </reference>
+           </visibleWhen>
+        </command>
+     </menuContribution>
+     <menuContribution
+           allPopups="false"
+           locationURI="toolbar:org.txm.rcp.toolbarcorpus?after=org.txm.rcp.toolbarcorpus.annotation">
+        <command
+              commandId="org.txm.annotation.kr.rcp.commands.SaveAnnotationsAndUpdateCorpus"
+              icon="icons/functions/pencil_save.png"
+              label="CQP"
+              mode="FORCE_TEXT"
+              style="push"
+              tooltip="CQP">
+        </command>
+     </menuContribution>
+     <menuContribution
+           locationURI="menu:menu.file.import.annotations">
+        <command
+              commandId="org.txm.annotation.kr.rcp.commands.ImportTable"
+              label="%command.label.2"
+              style="push">
+           <visibleWhen
+                 checkEnabled="false">
+              <reference
+                    definitionId="OneMainCorpusSelected">
+              </reference>
+           </visibleWhen>
+        </command>
+     </menuContribution>
+  </extension>
+  <extension
+         point="org.eclipse.ui.contexts">
+      <context
+            description="%context.description"
+            id="org.txm.rcp.annotation.krview"
+            name="%context.name">
+      </context>
+   </extension>
+  <extension
+        point="org.eclipse.core.expressions.definitions">
+     <definition
+                  id="OneKRSelected">
+               <with
+                     variable="selection">
+                  <iterate
+                        ifEmpty="false"
+                        operator="and">
+                     <instanceof
+                           value="org.txm.annotation.KnowledgeRepository">
+                     </instanceof>
+                  </iterate>
+               </with>
+            </definition>
+            <definition
+                  id="OneLocalKRSelected">
+               <with
+                     variable="selection">
+                  <iterate
+                        ifEmpty="false"
+                        operator="and">
+                     <instanceof
+                           value="org.txm.annotation.repository.LocalKnowledgeRepository">
+                     </instanceof>
+                  </iterate>
+               </with>
+            </definition>
+                        <definition
+                  id="OneAnnotationTypeSelected">
+               <with
+                     variable="selection">
+                  <iterate
+                        ifEmpty="false"
+                        operator="and">
+                     <instanceof
+                           value="org.txm.annotation.repository.AnnotationType">
+                     </instanceof>
+                  </iterate>
+               </with>
+            </definition>
+            <definition
+                  id="OneTypedValueSelected">
+               <with
+                     variable="selection">
+                  <iterate
+                        ifEmpty="false"
+                        operator="and">
+                     <instanceof
+                           value="org.txm.annotation.repository.TypedValue">
+                     </instanceof>
+                  </iterate>
+               </with>
+            </definition>
+            <definition
+                  id="CorpusNeedtoSaveAnnotation">
+               <and>
+                  <test
+                        forcePluginActivation="true"
+                        property="org.txm.rcp.testers.IsCorpusDirty">
+                  </test>
+               </and>
+            </definition>
+  </extension>
+  
+     <extension
+         point="org.eclipse.core.expressions.propertyTesters">
+      <propertyTester
+            class="org.txm.rcp.testers.IsCorpusDirty"
+            id="org.txm.rcp.testers.IsCorpusDirty"
+            namespace="org.txm.rcp.testers"
+            properties="IsCorpusDirty"
+            type="java.lang.Object">
+      </propertyTester>
+   </extension>
+  
+  <extension
+        point="org.txm.annotation.rcp.editor.AnnotationArea">
+     <annotationtoolbar
+           class="org.txm.annotation.kr.rcp.concordance.KRAnnotation"
+           position="3">
+     </annotationtoolbar>
+     <annotationtoolbar
+           class="org.txm.annotation.kr.rcp.concordance.WordAnnotationToolbar"
+           position="1">
+     </annotationtoolbar>
+     <annotationtoolbar
+           class="org.txm.annotation.kr.rcp.concordance.SimpleKRAnnotation"
+           position="2">
+     </annotationtoolbar>
+  </extension>
+</plugin>

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/plugin.xml
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/.settings/org.eclipse.core.resources.prefs
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/.settings/org.eclipse.core.resources.prefs	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/.settings/org.eclipse.core.resources.prefs	(revision 3653)
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+encoding//src/org/txm/annotation/kr/rcp/messages/messages.properties=UTF-8
+encoding//src/org/txm/annotation/kr/rcp/messages/messages_fr.properties=UTF-8

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/.settings/org.eclipse.core.resources.prefs
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/.classpath
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/.classpath	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/.classpath	(revision 3653)
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con"
+		path="org.eclipse.jdt.launching.JRE_CONTAINER" />
+	<classpathentry kind="con"
+		path="org.eclipse.pde.core.requiredPlugins">
+		<accessrules>
+			<accessrule kind="accessible" pattern="**" />
+		</accessrules>
+	</classpathentry>
+	<classpathentry kind="src" path="src" />
+	<classpathentry kind="output" path="bin" />
+</classpath>
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/.classpath
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/META-INF/MANIFEST.MF
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/META-INF/MANIFEST.MF	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/META-INF/MANIFEST.MF	(revision 3653)
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Export-Package: org.txm.annotation.kr.rcp.commands,org.txm.annotation.
+ kr.rcp.commands.krview,org.txm.annotation.kr.rcp.concordance,org.txm.
+ annotation.kr.rcp.editors.imports.sections,org.txm.annotation.kr.rcp.
+ messages,org.txm.annotation.kr.rcp.preferences,org.txm.annotation.kr.
+ rcp.views.knowledgerepositories
+Bundle-SymbolicName: org.txm.annotation.kr.rcp;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Name: %Bundle-Name
+Require-Bundle: org.txm.annotation.kr.core;bundle-version="1.0.0";visi
+ bility:=reexport,org.txm.annotation.rcp;bundle-version="1.0.0";visibi
+ lity:=reexport
+Bundle-ManifestVersion: 2
+Bundle-RequiredExecutionEnvironment: JavaSE-16
+Bundle-Vendor: Textometrie.org
+Automatic-Module-Name: org.txm.annotation.kr.rcp
+

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/META-INF/MANIFEST.MF
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.rcp/.project
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.rcp/.project	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.rcp/.project	(revision 3653)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.txm.annotation.kr.rcp</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp/.project
___________________________________________________________________
Added: svn:mime-type
   + text/plain


Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.rcp
___________________________________________________________________
Added: svn:ignore
   + bin

target


Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationInjector.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationInjector.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationInjector.java	(revision 3653)
@@ -0,0 +1,895 @@
+package org.txm.annotation.kr.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+
+import org.eclipse.osgi.util.NLS;
+import org.txm.Toolbox;
+import org.txm.importer.StaxIdentityParser;
+import org.txm.importer.ValidateXml;
+import org.txm.utils.logger.Log;
+
+/**
+ * The Class AnnotationInjection.
+ *
+ * @author mdecorde
+ *
+ *         inject annotation from a stand-off file into a xml-tei-txm file "id"
+ */
+
+public class AnnotationInjector extends StaxIdentityParser {
+	
+	File xmlFile;
+	
+	HashMap<Integer, List<Annotation>> annotationsToAddByStartPos; // contains
+	// annotation
+	// to write
+	
+	HashMap<Integer, List<Annotation>> annotationsToAddByEndPos;
+	
+	List<Annotation> currentStartAnnotations;
+	
+	List<Annotation> currentEndAnnotations;
+	
+	LinkedHashMap<String, Annotation> currentTokenAnnotations = new LinkedHashMap<>();
+	
+	int n = 0;
+	
+	boolean debug = false;
+	
+	String data; // the word id properties to add/replace
+	
+	String newform = null;
+	
+	String wordId;
+	
+	boolean inW = false;
+	
+	String anaType;
+	
+	int position_counter = 0;
+	
+	String closeNext = null; // the next close tag to delete
+	
+	ArrayList<String> openedElements = new ArrayList<>(); // to ensure to
+	// delete the
+	// right element
+	
+	private List<Annotation> previousEndAnnotations;
+	
+	private ArrayList<Annotation> tokenAnnotations;
+	
+	String user;
+	
+	/**
+	 * 
+	 * @param xmlFile
+	 * @param tokenAnnotations
+	 * @param annotationsToAddByStartPos
+	 * @param annotationsToAddByEndPos
+	 * @param corpus_start_position
+	 * @param debug
+	 * @throws XMLStreamException
+	 * @throws IOException
+	 */
+	public AnnotationInjector(File xmlFile, List<Annotation> segmentAnnotations, ArrayList<Annotation> tokenAnnotations, int corpus_start_position, boolean debug) throws IOException,
+			XMLStreamException {
+		super(xmlFile.toURI().toURL()); // init reader and writer
+		
+		this.user = System.getProperty("user.name");
+		
+		this.debug = debug;
+		this.xmlFile = xmlFile;
+		this.n = 0;
+		// println ""+records.size()+" lines to process..."
+		this.position_counter = corpus_start_position;
+		factory = XMLInputFactory.newInstance();
+		
+		// preparing annotations to being written in the right inclusion order
+		annotationsToAddByStartPos = new HashMap<>();
+		annotationsToAddByEndPos = new HashMap<>();
+		
+		for (Annotation a : segmentAnnotations) {
+			if (!annotationsToAddByStartPos.containsKey(a.getStart()))
+				annotationsToAddByStartPos.put(a.getStart(), new ArrayList<Annotation>());
+			if (!annotationsToAddByEndPos.containsKey(a.getEnd()))
+				annotationsToAddByEndPos.put(a.getEnd(), new ArrayList<Annotation>());
+			
+			annotationsToAddByStartPos.get(a.getStart()).add(a);
+			annotationsToAddByEndPos.get(a.getEnd()).add(a);
+		}
+		
+		for (int i : annotationsToAddByStartPos.keySet()) {
+			List<Annotation> a = annotationsToAddByStartPos.get(i);
+			Collections.sort(a, new Comparator<Annotation>() { // reverse sort
+				// annotation ->
+				// write the
+				// smaller in
+				// the bigger
+				
+				@Override
+				public int compare(Annotation arg0, Annotation arg1) {
+					return arg1.getEnd() - arg0.getEnd();
+				}
+			});
+		}
+		for (int i : annotationsToAddByEndPos.keySet()) {
+			List<Annotation> a = annotationsToAddByEndPos.get(i);
+			Collections.sort(a, new Comparator<Annotation>() { // reverse sort
+				// annotation ->
+				// write the
+				// smaller in
+				// the bigger
+				
+				@Override
+				public int compare(Annotation arg0, Annotation arg1) {
+					return arg1.getStart() - arg0.getStart();
+				}
+			});
+		}
+		
+		// sorting token annotations
+		this.tokenAnnotations = tokenAnnotations;
+		Collections.sort(tokenAnnotations, new Comparator<Annotation>() {
+			
+			@Override
+			public int compare(Annotation arg0, Annotation arg1) {
+				return arg0.getStart() - arg1.getStart();
+			}
+		});
+		
+		if (debug) {
+			Log.finer("annotations for " + xmlFile);
+			Log.finer(" segment grouped and ordered by start position: " + annotationsToAddByStartPos);
+			Log.finer(" segment grouped and ordered by end position: " + annotationsToAddByEndPos);
+			Log.finer(" token ordered by start position: " + tokenAnnotations);
+		}
+	}
+	
+	boolean mustChangeAnaValue = false;
+	
+	boolean inAna = false;
+	
+	private boolean inForm;
+	
+	private boolean mustChangeWordValue;
+	
+	@Override
+	protected void processStartElement() throws XMLStreamException, IOException {
+		
+		currentStartAnnotations = annotationsToAddByStartPos.get(position_counter);
+		currentEndAnnotations = annotationsToAddByEndPos.get(position_counter);
+		// System.out.println("A Starts: "+currentStartAnnotations+" "+currentEndAnnotations);
+		// if (debug)
+		// System.out.println("----- "+localname+"@"+position_counter+" START ANNOT = "+currentStartAnnotations);
+		if ("teiHeader".equals(localname)) {
+			super.processStartElement();
+			goToEnd("teiHeader"); // skip teiHeader // will be closed in
+			// processEndElement()
+		}
+		else if ("w".equals(localname)) {
+			// System.out.println("W START pos="+position_counter+" annots="+currentStartAnnotations);
+			if (currentStartAnnotations != null) {// there are still annotations
+				// to write, possible
+				// several for a position
+				// if (debug)
+				// System.out.println("WRITING START at "+position_counter+": "+currentStartAnnotations);
+				for (Annotation a : currentStartAnnotations) {
+					if (!"#del".equals(a.getValue())) {
+						if (debug) {
+							Log.finer(" force write start annotation " + a);
+						}
+						writeStartAnnotation(a);
+					}
+					else {
+						if (debug)
+							Log.finer(" no need to write start annotation " + a);
+						currentEndAnnotations = annotationsToAddByEndPos.get(a.getEnd());
+						// System.out.println(" shall we need to change annotation attribute : "+a.getValue()+
+						// " | currentEndAnnotations : "+currentEndAnnotations);
+						if (currentEndAnnotations == null) {
+							Log.finer("WARNING ERROR null pointer for end position of annotation " + a);
+						}
+						else {
+							currentEndAnnotations.remove(a);
+						}
+					}
+				}
+			}
+			inW = true;
+			
+			// get token annotation if any
+			currentTokenAnnotations.clear(); // current word annotations to write, may be empty
+			Annotation a = null;
+			
+			ArrayList<Annotation> toRemove = new ArrayList<>();
+			for (Annotation annot : tokenAnnotations) {
+				a = annot;
+				// System.out.println("for p="+position_counter+" next token annot="+a);
+				
+				if (a.getStart() <= position_counter && position_counter <= a.getEnd()) {
+					// write the annotation
+					currentTokenAnnotations.put(a.getType(), a);
+					if (a.getEnd() == position_counter) { // its the last word that needs to write this annotation
+						toRemove.add(annot);
+					}
+				}
+			}
+			tokenAnnotations.removeAll(toRemove);
+			
+			super.processStartElement(); // write the tag
+			
+		}
+		else if ("form".equals(localname) && inW) {
+			if (currentTokenAnnotations.containsKey("word")) {
+				Annotation a = currentTokenAnnotations.get("word");
+				// System.out.println("Updating token annotation with: " + a);
+				
+				String value = a.getValue();
+				if ("#del".equals(value)) {
+					value = "";
+				}
+				if (value == null) {
+					value = "ERROR";
+				}
+				try {
+					writer.writeStartElement(TXMNS, "form");
+					writer.writeCharacters(value);
+					mustChangeWordValue = true;
+				}
+				catch (XMLStreamException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+				
+				currentTokenAnnotations.remove("word"); // annotation updated
+			}
+			else {
+				super.processStartElement();
+			}
+		}
+		else if ("ana".equals(localname) && inW) {
+			inAna = true;
+			String type = parser.getAttributeValue(null, "type").substring(1);
+			if (currentTokenAnnotations.containsKey(type)) {
+				Annotation a = currentTokenAnnotations.get(type);
+				// System.out.println("Updating token annotation with: " + a);
+				
+				String value = a.getValue();
+				if ("#del".equals(value)) {
+					value = "";
+				}
+				if (value == null) {
+					value = "ERROR";
+				}
+				
+				try {
+					writer.writeStartElement("ana");
+					writer.writeAttribute("type", "#" + type);
+					writer.writeAttribute("resp", "#" + a.getAnnotator()); // change
+					// resp
+					writer.writeCharacters(value);
+					mustChangeAnaValue = true;
+				}
+				catch (XMLStreamException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+				
+				currentTokenAnnotations.remove(type); // annotation updated
+			}
+			else {
+				super.processStartElement();
+			}
+		}
+		else if (currentStartAnnotations != null) { // is it an annotations ?
+			// System.out.println("A START="+localname);
+			
+			String s_end = parser.getAttributeValue(null, "end");
+			String s_start = parser.getAttributeValue(null, "start");
+			String s_author = parser.getAttributeValue(null, "author");
+			String s_ref = parser.getAttributeValue(null, "ref");
+			
+			boolean toDelete = false;
+			
+			int start = -1;
+			int end = -1;
+			try {
+				start = Integer.parseInt(s_start);
+				end = Integer.parseInt(s_end);
+			}
+			catch (Exception e) {
+				
+			}
+			
+			if (s_end == null || s_end.length() == 0 || s_start == null || s_start.length() == 0 || start < 0 || end < 0) {
+				// this is not an annotation
+			}
+			else {
+				for (int i = 0; i < currentStartAnnotations.size(); i++) {
+					Annotation a = currentStartAnnotations.get(i);
+					// if (debug)
+					// System.out.println("=============== Start annot : "+a);
+					if (a.getType().equals(localname)) { // force delete, will be
+						// written in the "w"
+						// case
+						
+						if (a.getStart() == start && a.getEnd() == end) {
+							// updated = true;
+							// if (debug)
+							// System.out.println(" found existing annotation "+a);
+							if ("#del".equals(a.getValue())) {
+								toDelete = true;
+								// currentEndAnnotations.remove(a); // MAYBE NOT TO
+								// DO THIS HERE ?
+								if (debug) {
+									Log.finer(" force delete start annotation " + a);
+								}
+							}
+							else { // update existing annotation, no need to store
+									 // the end of annotation
+								writeStartAnnotation(a);
+								toDelete = true;
+								if (debug) {
+									Log.finer(" update annotation " + a);
+								}
+								currentEndAnnotations = annotationsToAddByEndPos.get(a.getEnd());// EL
+								// NO
+								// CAPITO
+								// YET
+								// !!
+								// System.out.println(" shall we need to change annotation attribute : "+a.getValue()+
+								// " | currentEndAnnotations : "+currentEndAnnotations);
+								if (currentEndAnnotations == null) {
+									Log.warning(NLS.bind("Error: null pointer for end position of annotation {0}.", a));
+								}
+								else {
+									currentEndAnnotations.remove(a);
+								}
+							}
+							
+							currentStartAnnotations.remove(i);
+							i--;
+						}
+						
+						break; // no need to continue
+					}
+					else {
+						// System.out.println("------- with same start pos");
+						
+						if (s_start != null && s_end != null && s_author != null && s_ref != null) {
+							if (a.getEnd() >= end) { // must write a
+								if (!"#del".equals(a.getValue())) {
+									if (debug) {
+										Log.finer(NLS.bind(" writing of start annotation {0}.", a));
+									}
+									writeStartAnnotation(a);
+									
+								}
+								else {
+									toDelete = true;
+									if (debug) {
+										Log.finer(NLS.bind(" no writing of start annotation {0}.", a));
+									}
+									currentEndAnnotations = annotationsToAddByEndPos.get(a.getEnd());
+									// System.out.println(" shall we need to change annotation attribute : "+a.getValue()+
+									// " | currentEndAnnotations : "+currentEndAnnotations);
+									if (currentEndAnnotations == null) {
+										Log.warning(NLS.bind("Error: null pointer for end position of annotation {0}.", a));
+									}
+									else {
+										currentEndAnnotations.remove(a);
+									}
+								}
+								currentStartAnnotations.remove(i);
+								i--;
+								// break;
+							}
+						}
+					}
+				}
+			}
+			if (!toDelete) { // the structure or annotation was not modified
+				super.processStartElement();
+			}
+		}
+		else {
+			// System.out.println("X START="+localname);
+			super.processStartElement();
+		}
+	}
+	
+	@Override
+	public void processCharacters() throws XMLStreamException {
+		// System.out.println("processCharaters inAna="+inAna+" mustChangeAnaValue="+mustChangeAnaValue);
+		if (inAna && mustChangeAnaValue) {
+			// nothing content is already written
+			// System.out.println("skip ana value because we replace it");
+		}
+		else if (inW && mustChangeWordValue) {
+			// nothing content is already written
+			// System.out.println("skip form value because we replace it");
+		}
+		else {
+			super.processCharacters();
+		}
+	}
+	
+	@Override
+	protected void processEndElement() throws XMLStreamException {
+		// currentEndAnnotations =
+		// annotationsToAddByEndPos.get(position_counter); // annotation to end
+		previousEndAnnotations = annotationsToAddByEndPos.get(position_counter - 1); // existing
+		// (or
+		// not)
+		// annotation
+		// that
+		// have
+		// already
+		// been
+		// closed
+		// if (debug)
+		// System.out.println("----- "+localname+"@"+position_counter+" END ANNOT = "+currentEndAnnotations);
+		
+		if ("w".equals(localname)) {
+			// System.out.println("W END");
+			
+			for (String type : currentTokenAnnotations.keySet()) {
+				try {
+					writer.writeStartElement("ana");
+					writer.writeAttribute("type", "#" + type);
+					writer.writeAttribute("resp", "#" + currentTokenAnnotations.get(type).getAnnotator()); // change
+					// resp
+					writer.writeCharacters(currentTokenAnnotations.get(type).getValue());
+					writer.writeEndElement();
+				}
+				catch (XMLStreamException e) {
+					e.printStackTrace();
+				}
+			}
+			
+			super.processEndElement(); // write word then close annotations
+			inW = false;
+			// force write All known annotation after the word
+			if (currentEndAnnotations != null) {// there are still annotations
+				// to write, possible several
+				// for a position
+				// if (debug)
+				// System.out.println("WRITING END at "+position_counter+": "+currentEndAnnotations);
+				for (Annotation a : currentEndAnnotations) {
+					// if (debug)
+					// System.out.println("=============== End annot : "+a);
+					if (!"#del".equals(a.getValue())) {
+						if (debug) {
+							Log.finer(" force write end annotation " + a);
+						}
+						writeEndAnnotation(a);
+					} /*
+						 * else { if (debug)
+						 * System.out.println(" no need to write end annotation "
+						 * +a); }
+						 */
+					
+				}
+			}
+			
+			position_counter++;
+		}
+		else if ("form".equals(localname) && inW) {
+			// if (!mustChangeAnaValue)
+			super.processEndElement();
+			mustChangeWordValue = false;
+			inForm = false;
+		}
+		else if ("ana".equals(localname) && inW) {
+			// if (!mustChangeAnaValue)
+			super.processEndElement();
+			inAna = false;
+			mustChangeAnaValue = false;
+		}
+		else if (previousEndAnnotations != null) { // force delete annotations
+			// previously written in
+			// the "w" case
+			// System.out.println("previousEndAnnotations !!!!! "+previousEndAnnotations);
+			boolean toDelete = false;
+			for (int i = 0; i < previousEndAnnotations.size(); i++) {
+				Annotation a = previousEndAnnotations.get(i);
+				if (a.getType().equals(localname)) { // update the annotation
+					// if (debug)
+					// System.out.println(" found existing end annotation "+a);
+					
+					if ("#del".equals(a.getValue())) { // if
+						// (!"#del".equals(a.getValue()))
+						// {
+						toDelete = true;
+						if (debug) {
+							Log.finer(" force delete end annotation " + a);
+						}
+					}
+					
+					previousEndAnnotations.remove(i);
+					i--;
+					break; // no need to continue
+				}
+			}
+			if (!toDelete) { // the structure or annotation was not modified
+				super.processEndElement();
+			}
+			else {
+				// if (debug)
+				// System.out.println("DELETING END at "+position_counter+" localname="+localname+": "+previousEndAnnotations);
+			}
+		}
+		else {
+			// System.out.println("X END="+localname);
+			super.processEndElement();
+		}
+	}
+	
+	private void writeStartAnnotation(Annotation a) {
+		try {
+			writer.writeStartElement("txm:" + a.getType());
+			writer.writeAttribute("author", "" + a.getAnnotator());
+			writer.writeAttribute("ref", a.getValue());
+			writer.writeAttribute("date", Toolbox.dateformat.format(new Date()));
+			writer.writeAttribute("start", Integer.toString(a.getStart()));
+			writer.writeAttribute("end", Integer.toString(a.getEnd()));
+		}
+		catch (XMLStreamException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	private void writeEndAnnotation(Annotation a) {
+		try {
+			writer.writeEndElement();
+		}
+		catch (XMLStreamException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	//////////// TESTS ///////////
+	
+	public static ArrayList<Annotation> testAdding() {
+		
+		Annotation a1 = new Annotation("Actr", "Actr100", 15, 16);
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		return annotations;
+	}
+	
+	public static ArrayList<Annotation> testAddingInclusive() {
+		
+		Annotation a1 = new Annotation("CoAc", "CoAc2093", 15, 19);
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		return annotations;
+	}
+	
+	public static ArrayList<Annotation> testAddingInclusive2() {
+		
+		Annotation a1 = new Annotation("Actr", "Actr100", 15, 16);
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		return annotations;
+	}
+	
+	public static ArrayList<Annotation> testUpdating() {
+		
+		Annotation a1 = new Annotation("Actr", "Actr200", 15, 16);
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		return annotations;
+	}
+	
+	public static ArrayList<Annotation> testUpdatingDeleting() {
+		Annotation a1 = new Annotation("Actr", "Actr200", 15, 16);
+		Annotation a2 = new Annotation("CoAc", "#del", 15, 19);
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		annotations.add(a2);
+		return annotations;
+	}
+	
+	public static ArrayList<Annotation> testAddDeleting2() {
+		Annotation a1 = new Annotation("Actr", "#del", 15, 16); // DELETE
+		Annotation a2 = new Annotation("NaPl", "NaPl14554", 15, 19); // ADD
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		annotations.add(a2);
+		return annotations;
+	}
+	
+	public static ArrayList<Annotation> testUpdatingDeletingAdding() {
+		Annotation a1 = new Annotation("Actr", "Actr200", 15, 16); // UPDATE
+		Annotation a2 = new Annotation("NaPl", "NaPl14554", 15, 19); // ADD
+		Annotation a3 = new Annotation("CoAc", "#del", 15, 19);	// DELETE
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		annotations.add(a2);
+		annotations.add(a3);
+		return annotations;
+	}
+	
+	public static ArrayList<Annotation> testUpdatingDeletingAdding2() {	// NOT WORKING
+		Annotation a1 = new Annotation("Actr", "#del", 15, 16); // DELETE
+		Annotation a2 = new Annotation("NaPl", "NaPl14554", 15, 19); // ADD same place as CoAc
+		Annotation a3 = new Annotation("CoAc", "CoAc2091", 15, 19); // UPDATE
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		annotations.add(a2);
+		annotations.add(a3);
+		return annotations;
+	}
+	
+	public static ArrayList<Annotation> testUpdatingDeletingAdding3() {	// NOT WORKING
+		Annotation a1 = new Annotation("Actr", "#del", 15, 16); // DELETE
+		Annotation a2 = new Annotation("NaPl", "NaPl14554", 15, 16); // ADD same place as Actr
+		Annotation a3 = new Annotation("CoAc", "CoAc2091", 15, 19); // UPDATE
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		annotations.add(a2);
+		annotations.add(a3);
+		return annotations;
+	}
+	
+	public static ArrayList<Annotation> testUpdatingDeletingAdding4() {
+		Annotation a1 = new Annotation("Actr", "#del", 15, 16); // DELETE
+		Annotation a2 = new Annotation("NaPl", "NaPl14554", 13, 20); // ADD Outside Actr and CoAc
+		Annotation a3 = new Annotation("CoAc", "CoAc2091", 15, 19); // UPDATE
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		annotations.add(a2);
+		annotations.add(a3);
+		return annotations;
+	}
+	
+	public static ArrayList<Annotation> testUpdatingDeletingAdding5() {
+		Annotation a1 = new Annotation("Actr", "#del", 15, 16); // DELETE
+		Annotation a2 = new Annotation("NaPl", "NaPl14554", 15, 16); // ADD
+		Annotation a3 = new Annotation("CoAc", "#del", 15, 19); // DELETE
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		annotations.add(a2);
+		annotations.add(a3);
+		return annotations;
+	}
+	
+	public static ArrayList<Annotation> testUpdatingDeletingAdding6() {
+		Annotation a1 = new Annotation("Actr", "#del", 15, 16); // DELETE
+		Annotation a2 = new Annotation("NaPl", "NaPl14554", 15, 16); // ADD
+		Annotation a3 = new Annotation("CoAc", "#del", 15, 19); // DELETE
+		Annotation a4 = new Annotation("CoAc", "CoAc1", 15, 18); // DELETE
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		annotations.add(a2);
+		annotations.add(a3);
+		annotations.add(a4);
+		return annotations;
+	}
+	
+	public static ArrayList<Annotation> testUpdatingInclusive() {
+		Annotation a1 = new Annotation("Actr", "Actr200", 15, 16);
+		Annotation a2 = new Annotation("CoAc", "CoAc321", 15, 19);
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		annotations.add(a2);
+		return annotations;
+	}
+	
+	public static ArrayList<Annotation> testDeleting() {
+		
+		Annotation a1 = new Annotation("Actr", "#del", 15, 16);
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		return annotations;
+	}
+	
+	public static ArrayList<Annotation> testDeletingInclusive() {
+		
+		Annotation a1 = new Annotation("Actr", "#del", 15, 16);
+		Annotation a2 = new Annotation("CoAc", "#del", 15, 16);
+		ArrayList<Annotation> annotations = new ArrayList<>();
+		annotations.add(a1);
+		annotations.add(a2);
+		return annotations;
+	}
+	
+	static int ADD = 1;
+	
+	static int UPDATE = 2;
+	
+	static int DELETE = 3;
+	
+	static int ADD2 = 4;
+	
+	static int UPDATE2 = 5;
+	
+	static int DELETE2 = 6;
+	
+	static int DELETE3 = 7;
+	
+	static int DELETE4 = 8;
+	
+	static int ADD3 = 9;
+	
+	static int UPDATE3 = 10;
+	
+	static int UPDATEDELETE = 11;
+	
+	static int UPDATEDELETEADD = 12;
+	
+	static int UPDATEDELETEADD2 = 13;
+	
+	static int UPDATEDELETEADD3 = 14;
+	
+	static int UPDATEDELETEADD4 = 15;
+	
+	static int UPDATEDELETEADD5 = 16;
+	
+	static int UPDATEDELETEADD6 = 17;
+	
+	static int ADDDELETE2 = 18;
+	
+	public static void main2(String args[]) throws IOException, XMLStreamException {
+		File xmlFile = null;
+		int corpus_start_position = 10;
+		
+		ArrayList<Annotation> annotations = null;
+		int test = UPDATEDELETEADD3;// AnnotationWriter.UPDATE;// AnnotationWriter.ADD;
+		switch (test) {
+			case 1:
+				// AnnotationWriter.ADD
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST.xml");
+				annotations = testAdding(); /// OK
+				break;
+			case 2:
+				// AnnotationWriter.UPDATE
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST2.xml");
+				annotations = testUpdating(); /// OK
+				break;
+			case 3:
+				// AnnotationWriter.DELETE
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST4.xml");
+				annotations = testDeleting(); /// OK
+				break;
+			case 4:
+				// AnnotationWriter.ADD2
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST3.xml");
+				annotations = testAddingInclusive(); /// OK
+				break;
+			case 5:
+				// AnnotationWriter.UPDATE2
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST5.xml");
+				annotations = testUpdating(); /// OK
+				break;
+			case 6:
+				// AnnotationWriter.DELETE2
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST6.xml");
+				annotations = testDeleting();
+				break;
+			case 7:
+				// AnnotationWriter.DELETE3
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST6.xml");
+				annotations = testDeletingInclusive();
+				break;
+			case 8:
+				// AnnotationWriter.DELETE4
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST7.xml");
+				annotations = testDeletingInclusive();
+				break;
+			case 9:
+				// AnnotationWriter.ADD3
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST3bis.xml");
+				annotations = testAddingInclusive2(); /// OK
+				break;
+			case 10:
+				// AnnotationWriter.UPDATE3
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST5.xml");
+				annotations = testUpdatingInclusive(); /// OK
+				break;
+			case 11:
+				// AnnotationWriter.UPDATEDELETE
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST5.xml");
+				annotations = testUpdatingDeleting(); /// OK
+				break;
+			case 12:
+				// AnnotationWriter.UPDATEDELETEADD
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST5.xml");
+				annotations = testUpdatingDeletingAdding(); /// NOT OK
+				break;
+			case 13:
+				// AnnotationWriter.UPDATEDELETEADD2
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST5.xml");
+				annotations = testUpdatingDeletingAdding2(); /// OK
+				break;
+			case 14:
+				// AnnotationWriter.UPDATEDELETEADD3
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST5.xml");
+				annotations = testUpdatingDeletingAdding3(); /// OK
+				break;
+			case 15:
+				// AnnotationWriter.UPDATEDELETEADD4 -- add 1 annotation over the 2 others
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST5.xml");
+				annotations = testUpdatingDeletingAdding4(); /// OK
+				break;
+			case 16:
+				// AnnotationWriter.UPDATEDELETEADD5 -- delete 2 annotations, add 1
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST5.xml");
+				annotations = testUpdatingDeletingAdding5(); /// OK
+				break;
+			case 17:
+				// AnnotationWriter.UPDATEDELETEADD6 -- delete 2 annotations, add 2
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST5.xml");
+				annotations = testUpdatingDeletingAdding6(); /// NOT OK
+				break;
+			case 18:
+				// AnnotationWriter.ADDDELETE -- delete 1, add 1
+				xmlFile = new File(System.getProperty("user.home"), "TXM/corpora/TEST/TEST5.xml");
+				annotations = testAddDeleting2(); /// OK
+				break;
+			//
+			default:
+				break;
+		}
+		
+		// no token annotations
+		AnnotationInjector annotationInjector = new AnnotationInjector(xmlFile, annotations, new ArrayList<Annotation>(), corpus_start_position, true);
+		File outfile = new File(xmlFile.getParentFile(), "result-" + xmlFile.getName());
+		if (annotationInjector.process(outfile)) {
+			if (!ValidateXml.test(outfile)) {
+				System.out.println("FAIL");
+			}
+			else {
+				System.out.println("SUCCESS ??");
+			}
+		}
+		
+	}
+	
+	public static void main(String[] args) {
+		try {
+			File xmlFile = new File(System.getProperty("user.home"), "TXM-0.8.3/corpora/XMLLINEBREAK/txm/XMLLINEBREAK/test.xml");
+			File outfile = new File(System.getProperty("user.home"), "TXM-0.8.3/corpora/XMLLINEBREAK/txm/XMLLINEBREAK/test-out.xml");
+			
+			ArrayList<Annotation> segmentAnnotations = new ArrayList<>();
+			// int starts[] = { 3, 6 };
+			// int ends[] = { 5, 8 };
+			// for (int i = 0; i < starts.length; i++) {
+			// segmentAnnotations.add(new Annotation("UN", "un", starts[i], ends[i]));
+			// segmentAnnotations.add(new Annotation("DEUX", "deux", starts[i], ends[i]));
+			// }
+			
+			ArrayList<Annotation> tokenAnnotations = new ArrayList<>();
+			int positions[] = { 1, 2 };
+			int n = 1;
+			for (int p : positions) {
+				tokenAnnotations.add(new Annotation("frlemma", "" + (n++), p, p));
+				tokenAnnotations.add(new Annotation("frpos", "" + (n++), p, p));
+			}
+			
+			AnnotationInjector ai;
+			
+			ai = new AnnotationInjector(xmlFile, segmentAnnotations, tokenAnnotations, 0, true);
+			System.out.println("start processing...");
+			ai.process(outfile);
+			System.out.println("Done.");
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationInjector.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/CQPAnnotationManager.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/CQPAnnotationManager.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/CQPAnnotationManager.java	(revision 3653)
@@ -0,0 +1,416 @@
+package org.txm.annotation.kr.core;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.osgi.service.prefs.BackingStoreException;
+import org.txm.annotation.kr.core.repository.AnnotationEffect;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.KnowledgeRepository;
+import org.txm.objects.Match;
+import org.txm.objects.Match2P;
+import org.txm.searchengine.cqp.AbstractCqiClient;
+import org.txm.searchengine.cqp.CQPSearchEngine;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.searchengine.cqp.corpus.Property;
+import org.txm.searchengine.cqp.corpus.StructuralUnit;
+import org.txm.searchengine.cqp.corpus.StructuralUnitProperty;
+import org.txm.searchengine.cqp.serverException.CqiServerError;
+import org.txm.utils.logger.Log;
+
+public class CQPAnnotationManager {
+	
+	MainCorpus corpus;
+	
+	public static final String REF = "ref";
+	
+	public CQPAnnotationManager(MainCorpus corpus) {
+		this.corpus = corpus;
+	}
+	
+	/**
+	 * returns all annotations for a given type
+	 * 
+	 * @return
+	 * @throws Exception
+	 */
+	public List<Annotation> getAnnotations(AnnotationType type) throws Exception {
+		return getAnnotations(type, false);
+	}
+	
+	/**
+	 * returns all annotations for a given type and overlap option
+	 * 
+	 * @return
+	 * @throws Exception
+	 */
+	public List<Annotation> getAnnotations(AnnotationType type, boolean overlap) throws Exception {
+		return getAnnotations(type, null, null, overlap);
+	}
+	
+	public List<Annotation> getAnnotations(AnnotationType type, int start, int end) throws CqiClientException, IOException, CqiServerError {
+		return getAnnotations(type, new Match2P(start, end), null, false);
+	}
+	
+	public List<Annotation> getAnnotations(AnnotationType type, int start, int end, boolean overlap) throws CqiClientException, IOException, CqiServerError {
+		return getAnnotations(type, new Match2P(start, end), null, overlap);
+	}
+	
+	/**
+	 * Return all annotations for ONE match
+	 * can be use to find out overlap
+	 * 
+	 * @param refType can be null
+	 * @param match can be null
+	 * @param value can be null
+	 * @param overlap
+	 * @return
+	 * @throws CqiClientException
+	 * @throws CqiServerError
+	 * @throws IOException
+	 */
+	public List<Annotation> getAnnotations(AnnotationType type, Match match, String value, boolean overlap) throws CqiClientException, IOException, CqiServerError {
+		HashMap<StructuralUnitProperty, AnnotationType> supList = new HashMap<StructuralUnitProperty, AnnotationType>();
+		
+		// TODO add a corpus parameters for structures that code annotations
+		// TODO manage word properties annotations
+		if (type == null) {
+			
+			// first get know annotations from corpus's KR
+			for (String kr_name : KRAnnotationEngine.getKnowledgeRepositoryNames(corpus)) {
+				KnowledgeRepository kr;
+				try {
+					kr = KRAnnotationEngine.getKnowledgeRepository(corpus, kr_name);
+					if (kr == null) continue;
+					List<AnnotationType> types = kr.getAllAnnotationTypes();
+					for (AnnotationType t : types) {
+						StructuralUnit su = corpus.getStructuralUnit(t.getId().toLowerCase());
+						if (su != null) {
+							StructuralUnitProperty sup = su.getProperty(REF);
+							if (sup != null) {
+								supList.put(sup, t);
+							}
+						}
+					}
+				}
+				catch (BackingStoreException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+			}
+			
+			for (StructuralUnit su : corpus.getStructuralUnits()) {
+				if (su.getName().equals("text") || su.getName().equals("txmcorpus") ||
+						su.getName().equals("lb") || su.getName().equals("pb")) continue; // that's no annotation for sure ;)
+				
+				StructuralUnitProperty sup = su.getProperty(REF);
+				if (sup == null) sup = su.getProperty("n");
+				if (sup != null) {
+					if (!supList.containsKey(sup)) // don't override a know annotation
+						supList.put(sup, null);
+				}
+			}
+			
+		}
+		else {
+			StructuralUnit su = corpus.getStructuralUnit(type.getId().toLowerCase());
+			if (su == null) return new ArrayList<Annotation>(); // no property, no annotation :)
+			
+			StructuralUnitProperty sup = su.getProperty(REF);
+			if (sup == null) return new ArrayList<Annotation>(); // no attribute REF, no annotation :)
+			
+			supList.put(sup, type);
+		}
+		
+		ArrayList<Annotation> result = new ArrayList<Annotation>();
+		for (StructuralUnitProperty sup : supList.keySet()) {
+			String sup_name = sup.getStructuralUnit().getName();
+			AnnotationType sup_type = supList.get(sup);
+			if (sup_type != null) sup_name = sup_type.getId();
+			
+			int Nstruct = CQPSearchEngine.getCqiClient().attributeSize(sup.getQualifiedName());
+			
+			// TODO: can optimize this, to fetch only structure that matches
+			int[] iStructs = new int[Nstruct];
+			for (int iStruct = 0; iStruct < Nstruct; iStruct++)
+				iStructs[iStruct] = iStruct;
+			String svalues[] = CQPSearchEngine.getCqiClient().struc2Str(sup.getQualifiedName(), iStructs); // one position
+			
+			for (int iStruct = 0; iStruct < Nstruct; iStruct++) {
+				int smatch[] = CQPSearchEngine.getCqiClient().struc2Cpos(sup.getQualifiedName(), iStruct);
+				
+				if (value != null) { // supplementary test if value is specified
+					if (!value.equals(svalues[iStruct])) {
+						continue; // next struct
+					}
+				}
+				if (match != null) {
+					if (overlap) {
+						if (match.getEnd() < smatch[0]) {
+							break; // no need to continue, structures are ordered
+						}
+						else if (smatch[1] < match.getStart()) {
+							continue; // next structure
+						}
+						else {
+							result.add(new Annotation(sup_name, svalues[iStruct], smatch[0], smatch[1]));
+						}
+					}
+					else {
+						if (match.getStart() == smatch[0] && match.getEnd() == smatch[1]) {
+							result.add(new Annotation(sup_name, svalues[iStruct], smatch[0], smatch[1]));
+						}
+					}
+				}
+				else { // get all annotations
+					result.add(new Annotation(sup_name, svalues[iStruct], smatch[0], smatch[1]));
+				}
+			}
+		}
+		return result;
+	}
+	
+	/**
+	 * 
+	 * @param matches Ordered matches, not null
+	 * @param type not null
+	 * @param overlap use true to detect overlapping annotations
+	 * @return ONE Annotation per Match for a given type
+	 * 
+	 * @throws CqiServerError
+	 * @throws IOException
+	 * @throws CqiClientException
+	 */
+	public List<? extends Annotation> getAnnotationsForMatches(List<Match> matches, AnnotationType type, boolean overlap) throws IOException, CqiServerError, CqiClientException {
+		if (type.getEffect().equals(AnnotationEffect.SEGMENT)) {
+			return getSegmentAnnotationsForMatches(matches, type, overlap);
+		}
+		else {
+			return getTokenAnnotationsForMatches(matches, type, overlap);
+		}
+	}
+	
+	/**
+	 * 
+	 * @param matches Ordered matches, not null
+	 * @param type not null
+	 * @param overlap use true to detect overlapping annotations
+	 * @return ONE Annotation per Match for a given type
+	 * 
+	 * @throws CqiServerError
+	 * @throws IOException
+	 * @throws CqiClientException
+	 */
+	public List<? extends Annotation> getTokenAnnotationsForMatches(List<Match> matches, AnnotationType type, boolean overlap) throws IOException, CqiServerError, CqiClientException {
+		
+		Property prop = corpus.getProperty(type.getId().toLowerCase());
+		if (prop == null) return nullAnnotationList(matches.size()); // no property, no annotation :)
+		
+		AbstractCqiClient cqi = CQPSearchEngine.getCqiClient();
+		
+		int positions[] = new int[matches.size()];
+		int i = 0;
+		for (Match m : matches) {
+			if (m.getTarget() >= 0) {
+				positions[i++] = m.getTarget();
+			}
+			else {
+				positions[i++] = m.getStart();
+			}
+		}
+		
+		String[] strs = cqi.cpos2Str(prop.getQualifiedName(), positions);
+		
+		ArrayList<CQPAnnotation> annotations = new ArrayList<CQPAnnotation>();
+		i = 0;
+		for (String str : strs) {
+			int p = positions[i++];
+			annotations.add(new CQPAnnotation(type.getId(), str, p, p));
+		}
+		// Log.info("TOKEN ANNOTATION CQP VALUES: "+annotations);
+		return annotations;
+	}
+	
+	/**
+	 * 
+	 * @param matches Ordered matches, not null
+	 * @param type not null
+	 * @param overlap use true to detect overlapping annotations
+	 * @return ONE Annotation per Match for a given type
+	 * 
+	 * @throws CqiServerError
+	 * @throws IOException
+	 * @throws CqiClientException
+	 */
+	public List<Annotation> getSegmentAnnotationsForMatches(List<Match> matches, AnnotationType type, boolean overlap) throws IOException, CqiServerError, CqiClientException {
+		
+		StructuralUnit su = corpus.getStructuralUnit(type.getId().toLowerCase());
+		if (su == null) return nullAnnotationList(matches.size()); // no property, no annotation :)
+		
+		StructuralUnitProperty sup = su.getProperty(REF);
+		if (sup == null) return nullAnnotationList(matches.size()); // no attribute REF, no annotation :)
+		
+		int Nstruct = CQPSearchEngine.getCqiClient().attributeSize(sup.getQualifiedName());
+		int iMatch = 0;
+		int iStruct = 0;
+		int Nmatches = matches.size();
+		ArrayList<Integer> values = new ArrayList<Integer>(); // contains structure numbers
+		ArrayList<int[]> annotationsStartEnd = new ArrayList<int[]>(); // contains structure numbers
+		
+		if (Nstruct == 0) return new ArrayList<Annotation>(matches.size()); // no annotation
+		// System.out.println("NUMBER OF STRUCT "+sup+" "+Nstruct);
+		// System.out.println("MATCHES "+matches);
+		int smatch[] = CQPSearchEngine.getCqiClient().struc2Cpos(sup.getQualifiedName(), iStruct);
+		// System.out.println(" TEST WITH "+smatch[0]+"-"+smatch[1]);
+		if (overlap) {
+			for (iMatch = 0; iStruct < Nstruct && iMatch < Nmatches;) {
+				Match m = matches.get(iMatch);
+				int start, end;
+				if (m.getTarget() >= 0) {
+					start = end = m.getTarget();
+				}
+				else {
+					start = m.getStart();
+					end = m.getEnd();
+				}
+				if (smatch[1] < start) { // next struct
+					iStruct++;
+					if (iStruct < Nstruct)
+						smatch = CQPSearchEngine.getCqiClient().struc2Cpos(sup.getQualifiedName(), iStruct);
+					// System.out.println(" NEXT STRUCT TEST WITH "+smatch[0]+"-"+smatch[1]);
+				}
+				else if (end < smatch[0]) { // next match
+					values.add(null);
+					annotationsStartEnd.add(null);
+					iMatch++;
+					// System.out.println(" NEXT MATCH of ["+m.getStart()+"-"+m.getEnd()+"] match TEST WITH "+smatch[0]+"-"+smatch[1]);
+				}
+				else {
+					// ((m.getStart() <= smatch[0] && smatch[0] <= m.getEnd()) ||
+					// (m.getStart() <= smatch[1] && smatch[1] <= m.getEnd()) ||
+					// (smatch[0] <= m.getStart() && m.getEnd() <= smatch[1])) {
+					iMatch++;
+					values.add(iStruct);
+					annotationsStartEnd.add(smatch);
+					// System.out.println(" FOUND annotation "+smatch[0]+"-"+smatch[1]);
+				}
+			}
+		}
+		else { // strict matches
+			for (iMatch = 0; iStruct < Nstruct && iMatch < Nmatches;) {
+				Match m = matches.get(iMatch);
+				int start, end;
+				if (m.getTarget() >= 0) {
+					start = end = m.getTarget();
+				}
+				else {
+					start = m.getStart();
+					end = m.getEnd();
+				}
+				
+				if (smatch[0] == start && smatch[1] == end) {
+					values.add(iStruct);
+					annotationsStartEnd.add(smatch);
+					iMatch++;
+					iStruct++;
+					if (iStruct < Nstruct)
+						smatch = CQPSearchEngine.getCqiClient().struc2Cpos(sup.getQualifiedName(), iStruct);
+				}
+				else if (smatch[1] < start) { // next struct
+					iStruct++;
+					if (iStruct < Nstruct)
+						smatch = CQPSearchEngine.getCqiClient().struc2Cpos(sup.getQualifiedName(), iStruct);
+				}
+				else if (end < smatch[0]) { // next match
+					values.add(null);
+					annotationsStartEnd.add(null);
+					iMatch++;
+				}
+				else {
+					values.add(null);
+					annotationsStartEnd.add(null);
+					iMatch++;
+				}
+			}
+		}
+		
+		while (values.size() < matches.size()) {
+			values.add(null); // if matches have not been processed due to no more struct available
+			annotationsStartEnd.add(null);
+		}
+		
+		int tmp_strucs[] = new int[values.size()]; // create the structure numbers array that CQP.struc2Str needs
+		for (int i = 0; i < values.size(); i++) {
+			if (values.get(i) == null) {
+				tmp_strucs[i] = 0; // add a fake value, remove after CQP call
+			}
+			else {
+				tmp_strucs[i] = values.get(i);
+			}
+		}
+		
+		String[] svalues = CQPSearchEngine.getCqiClient().struc2Str(sup.getQualifiedName(), tmp_strucs);
+		ArrayList<Annotation> annotations = new ArrayList<Annotation>();
+		for (int i = 0; i < values.size(); i++) { // remove the fake values
+			if (values.get(i) == null) {
+				annotations.add(null);
+			}
+			else {
+				annotations.add(new Annotation(type.getId(), svalues[i], annotationsStartEnd.get(i)[0], annotationsStartEnd.get(i)[1]));
+			}
+		}
+		
+		// Log.info("SEGMENT ANNOTATION CQP VALUES: "+annotations);
+		return annotations;
+	}
+	
+	private ArrayList<Annotation> nullAnnotationList(int size) {
+		ArrayList<Annotation> a = new ArrayList<Annotation>(size);
+		for (int i = 0; i < size; i++) {
+			a.add(null);
+		}
+		return a;
+	}
+	
+	/**
+	 * @param start
+	 * @param end
+	 * @param type
+	 * @return value for a match and a StructuralUnit
+	 * @throws IOException
+	 * @throws CqiServerError
+	 * @throws CqiClientException
+	 */
+	public String getCQPAnnotationValue(int start, int end, AnnotationType type) throws IOException, CqiServerError, CqiClientException {
+		
+		StructuralUnit su = corpus.getStructuralUnit(type.getId().toLowerCase());
+		if (su == null) return null;
+		
+		StructuralUnitProperty sup = su.getProperty(REF);
+		if (sup == null) return null;
+		int[] cpos = { start, end };
+		int[] struc = CQPSearchEngine.getCqiClient().cpos2Struc(sup.getQualifiedName(), cpos);
+		
+		if (struc[0] >= 0) {
+			// System.out.println("struct for positions "+start+"-"+end+" -> "+struc[0]+"-"+struc[1]);
+			if (struc[0] == struc[1]) { // même structure
+				String[] struc_str = CQPSearchEngine.getCqiClient().struc2Str(sup.getQualifiedName(), struc);
+				return struc_str[0];
+			}
+			else { // should not happens
+				Log.warning("WARNING: FOUND EXISTING ANNOTATION FOR TYPE=" + type + " START=" + start + " END=" + end);
+				return null;
+			}
+		}
+		else {
+			return null;
+		}
+	}
+	
+	public void close() {
+		
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/CQPAnnotationManager.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/Annotation.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/Annotation.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/Annotation.java	(revision 3653)
@@ -0,0 +1,88 @@
+package org.txm.annotation.kr.core;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.IdClass;
+import javax.persistence.Table;
+
+import org.txm.Toolbox;
+import org.txm.annotation.kr.core.repository.KnowledgeRepository;
+
+@Entity
+public class Annotation implements Serializable {
+	
+	private static final long serialVersionUID = -1007684142118207359L;
+	
+	// primaryKey corresponds to the start and end positions (in the corpus) and the refType
+	@EmbeddedId
+	private AnnotationPK PK;
+	
+	// corresponding to the type and value of the KnowledgeRepository, used to annotate
+	private String refVal = "";
+	
+	// user in the project, responsible for the annotation, maybe should be an integer
+	private String annotatorId = "";
+	
+	private String date;
+	
+	public Annotation() {}
+	
+	
+	public Annotation(String refType, String refVal, int CQPstartpos, int CQPendpos) {
+		this.PK = new AnnotationPK(CQPstartpos, CQPendpos, refType);
+		this.refVal = refVal;
+		this.date = Toolbox.dateformat.format(new Date());
+		
+		String s = System.getProperty(KnowledgeRepository.LOGIN_KEY);
+		if (s != null && s.length() > 0) {
+			this.annotatorId = s;
+		}
+		else {
+			this.annotatorId = System.getProperty("user.name");
+		}
+	}
+	
+	
+	public AnnotationPK getPK() {
+		return this.PK;
+	}
+	
+	public int getStart() {
+		return this.PK.getStartPosition();
+	}
+	
+	public int getEnd() {
+		return this.PK.getEndPosition();
+	}
+	
+	public String getType() {
+		return this.PK.getRefType();
+	}
+	
+	public String getValue() {
+		return this.refVal;
+	}
+	
+	public String getDate() {
+		return this.date;
+	}
+	
+	// Maybe will be an integer ?
+	public String getAnnotator() {
+		return annotatorId;
+	}
+	
+	
+	public void setReferentielVal(String newRefVal) {
+		this.refVal = newRefVal;
+	}
+	
+	
+	public String toString() {
+		return getPK().toString() + "=" + getValue();
+	}
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/Annotation.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/CQPAnnotation.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/CQPAnnotation.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/CQPAnnotation.java	(revision 3653)
@@ -0,0 +1,11 @@
+package org.txm.annotation.kr.core;
+
+public class CQPAnnotation extends Annotation {
+	
+	public CQPAnnotation(String id, String str, int p, int p2) {
+		super(id, str, p, p2);
+	}
+	
+	private static final long serialVersionUID = -3539813867449634393L;
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/CQPAnnotation.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/preferences/KRAnnotationPreferences.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/preferences/KRAnnotationPreferences.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/preferences/KRAnnotationPreferences.java	(revision 3653)
@@ -0,0 +1,42 @@
+package org.txm.annotation.kr.core.preferences;
+
+import org.osgi.service.prefs.Preferences;
+import org.txm.core.preferences.TXMPreferences;
+
+/**
+ * Preferences initializer and manager.
+ * 
+ * @author mdecorde
+ *
+ */
+public class KRAnnotationPreferences extends TXMPreferences {
+	
+	public static final String UPDATE_EDITION = "udpate_edition";
+	
+	public static final String UPDATE = "udpate";
+	
+	public static final String PRESERVE_ANNOTATIONS = "reset_temporary_annotations_when leaving_txm";
+	
+	/**
+	 * Gets the instance.
+	 * 
+	 * @return the instance
+	 */
+	public static TXMPreferences getInstance() {
+		
+		if (!TXMPreferences.instances.containsKey(KRAnnotationPreferences.class)) {
+			new KRAnnotationPreferences();
+		}
+		return TXMPreferences.instances.get(KRAnnotationPreferences.class);
+	}
+	
+	@Override
+	public void initializeDefaultPreferences() {
+		
+		super.initializeDefaultPreferences();
+		Preferences preferences = this.getDefaultPreferencesNode();
+		preferences.putBoolean(UPDATE_EDITION, true);
+		preferences.putBoolean(UPDATE, true);
+		preferences.putBoolean(PRESERVE_ANNOTATIONS, false);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/preferences/KRAnnotationPreferences.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/storage/temporary/TemporaryAnnotationManager.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/storage/temporary/TemporaryAnnotationManager.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/storage/temporary/TemporaryAnnotationManager.java	(revision 3653)
@@ -0,0 +1,633 @@
+package org.txm.annotation.kr.core.storage.temporary;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.logging.Level;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.TypedQuery;
+
+import org.eclipse.persistence.config.PersistenceUnitProperties;
+import org.eclipse.persistence.jpa.PersistenceProvider;
+import org.txm.annotation.kr.core.Annotation;
+import org.txm.annotation.kr.core.AnnotationPK;
+import org.txm.annotation.kr.core.DatabasePersistenceManager;
+import org.txm.annotation.kr.core.preferences.KRAnnotationPreferences;
+import org.txm.annotation.kr.core.repository.AnnotationEffect;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.TypedValue;
+import org.txm.objects.Match;
+import org.txm.objects.Match2P;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.logger.Log;
+
+public class TemporaryAnnotationManager {
+	
+	/**
+	 * 
+	 * @param clazz persistence.xml location depends on the classloader
+	 * @param corpus
+	 * @return
+	 */
+	public static HashMap<String, Object> getInitialisationProperties(Class clazz, MainCorpus corpus) {
+		File path = new File(corpus.getProjectDirectory(), "temporary_annotations/" + corpus.getID() + "/db");
+		path.getParentFile().mkdirs();
+		
+		HashMap<String, Object> properties = new HashMap<>();
+		// System.out.println("CLASSLOADER: "+Toolbox.class.getClassLoader());
+		properties.put(PersistenceUnitProperties.CLASSLOADER, clazz.getClassLoader());
+		properties.put("javax.persistence.jdbc.driver", "org.hsqldb.jdbcDriver");
+		
+		String urlProperty = "jdbc:hsqldb:file:" + path + ";shutdown=true;hsqldb.write_delay=false;hsqldb.lock_file=false;";
+		if (Log.getLevel().intValue() < Level.INFO.intValue()) {
+			urlProperty += "";
+		}
+		else {
+			urlProperty += "hsqldb.applog=0;hsqldb.sqllog=0";
+		}
+		properties.put("javax.persistence.jdbc.url", urlProperty);
+		properties.put("javax.persistence.jdbc.username", "SA");
+		properties.put(PersistenceUnitProperties.DDL_GENERATION_MODE, "database");
+		if (KRAnnotationPreferences.getInstance().getBoolean(KRAnnotationPreferences.PRESERVE_ANNOTATIONS)) {
+			properties.put(PersistenceUnitProperties.DDL_GENERATION, "create-or-extend-tables"); // create&update table if needed, drop-and-create-tables to reset all
+		}
+		else {
+			properties.put(PersistenceUnitProperties.DDL_GENERATION, "drop-and-create-tables"); // drop-and-create-tables to reset all
+		}
+		
+		if (Log.getLevel().intValue() < Level.INFO.intValue()) {
+			properties.put(PersistenceUnitProperties.LOGGING_LEVEL, "INFO");
+			properties.put(PersistenceUnitProperties.LOGGING_PARAMETERS, "true");
+		}
+		else {
+			properties.put(PersistenceUnitProperties.LOGGING_LEVEL, "OFF");
+			properties.put(PersistenceUnitProperties.LOGGING_PARAMETERS, "false");
+		}
+		
+		return properties;
+	}
+	
+	private EntityManager em;
+	
+	private MainCorpus corpus;
+
+	private EntityManagerFactory emf;
+	
+	public TemporaryAnnotationManager(MainCorpus corpus) {
+		this.corpus = corpus;
+		em = initTemporaryAnnotationDatabase();
+	}
+	
+	public TemporaryAnnotationManager(MainCorpus corpus, HashMap<String, Object> properties) {
+		this.corpus = corpus;
+		em = initTemporaryAnnotationDatabase(properties);
+	}
+	
+	public void checkData() throws Exception {
+		List<Annotation> annots = getAnnotations();
+		System.out.println("ID \t Type \t Val \t startPos \t startEnd \t Text ");
+		System.out.println("----------------------------------------------------");
+		for (Annotation an : annots) {
+			System.out.print("\t " + an.getPK().getRefType());
+			System.out.print("\t " + an.getValue());
+			System.out.print("\t " + an.getPK().getStartPosition());
+			System.out.print("\t " + an.getPK().getEndPosition() + "\n");
+		}
+	}
+	
+	public void close() {
+		if (em != null) {
+			em.close();
+		}
+		if (emf != null) {
+			emf.close();
+		}
+	}
+	
+	
+	public List<Annotation> createAnnotation(AnnotationType type, TypedValue value, int startPos, int endPos) throws Exception {
+		em.getTransaction().begin();
+		List<Annotation> a = createAnnotationNoCommit(type, value, startPos, endPos);
+		em.getTransaction().commit();
+		return a;
+	}
+	
+	/**
+	 * update or create an annotation BUT em.getTransaction().begin(); and em.getTransaction().commit();
+	 * must be called before and after !!
+	 * 
+	 * @param type
+	 * @param value
+	 * @param startPos
+	 * @param endPos
+	 * @param authorizedOverlap
+	 * @return overlapping annotations
+	 * @throws Exception
+	 */
+	public List<Annotation> createAnnotationNoCommit(AnnotationType type, TypedValue value, int startPos, int endPos) throws Exception {
+		AnnotationPK pkannot = new AnnotationPK(startPos, endPos, type.getId());
+		Annotation annot = em.find(Annotation.class, pkannot);
+		List<Annotation> overlapingAnnotations = new ArrayList<>();
+		if (annot == null) { // create annotation
+			
+			if (type.getEffect().equals(AnnotationEffect.SEGMENT)) {
+				// check if it does not already exist, with either one of the positions (overlaps)
+				// isOverlapAnnots = isOverlapAnnotationCritical(refType, refVal, startPos, endPos);
+				ArrayList<Match> matches = new ArrayList<>();
+				matches.add(new Match2P(startPos, endPos));
+				overlapingAnnotations = getAnnotations(null, matches, null, false, true); // getAll annotation ovelapping with startPos-endPos
+				for (int i = 0; i < overlapingAnnotations.size(); i++) { // parse overlapping annotations to remove wrapping annotation with different type and annotation with same type and same
+																		 // position
+					annot = overlapingAnnotations.get(i);
+					if (annot.getType().equals(type.getId())) {
+						if (annot.getStart() == startPos && annot.getEnd() == endPos) {
+							overlapingAnnotations.remove(i);
+							i--;
+						}
+					}
+					else {
+						// System.out.println("Pas le même TYPE !!!!! DONC on exige que seuls INNER et OUTTER overlaps sont admis");
+						if ((annot.getStart() <= startPos && endPos <= annot.getEnd() ||
+								(startPos <= annot.getStart() && annot.getEnd() <= endPos))) {
+							/*
+							 * System.out.println("Taille du tableau annotations AVANT : "+overlapingAnnotations.size());
+							 * System.out.println(annot.getStart()+" <= " +startPos+" && "+endPos+" <= "+annot.getEnd()+" OU ");
+							 * System.out.println(startPos+" <= " +annot.getStart()+" && "+annot.getEnd()+" <= "+endPos);
+							 */
+							overlapingAnnotations.remove(i);
+							// System.out.println("Taille du tableau annotations APRES : "+overlapingAnnotations.size());
+							i--;
+						}
+						else {
+							// System.out.println(annot.getStart()+"-"+annot.getEnd()+" // "+startPos+"-"+endPos);
+						}
+					}
+				}
+			}
+			else {
+				// no need to check collision
+			}
+			
+			if (overlapingAnnotations.size() > 0) { // don't create the annotation
+				// for (Annotation overlapAnnot : overlapingAnnotations) {
+				// System.out.println("---Overlap with : "+overlapAnnot.toString());
+				// }
+			}
+			else { // we can create the annotation \o/
+				annot = new Annotation(type.getId(), value.getId(), startPos, endPos);
+				
+				em.persist(annot);
+				// System.out.println("--- Create : "+annot.toString());
+			}
+		}
+		else { // update annotation
+				 // UPDATE
+				 // System.out.println("--- Update annot : "+annot.toString()+" ----- ");
+			annot.setReferentielVal(value.getId());
+		}
+		return overlapingAnnotations;
+	}
+	
+	/**
+	 * 
+	 * @param refType
+	 * @param refVal
+	 * @param CQPpositions
+	 * @return
+	 * @throws Exception
+	 */
+	public List<Annotation> createAnnotations(AnnotationType type, TypedValue value, List<Match> matches) throws Exception {
+		List<Annotation> isOverlappedWithAnnots = new ArrayList<>();
+		em.getTransaction().begin(); // mandatory ! :@
+		for (Match m : matches) {
+			int t = m.getTarget();
+			List<Annotation> annotsOverlapped = null;
+			if (t >= 0) {
+				annotsOverlapped = createAnnotationNoCommit(type, value, t, t);
+			}
+			else {
+				annotsOverlapped = createAnnotationNoCommit(type, value, m.getStart(), m.getEnd());
+			}
+			
+			if (annotsOverlapped != null) {
+				isOverlappedWithAnnots.addAll(annotsOverlapped);
+			}
+		}
+		em.getTransaction().commit(); // mandatory ! :@
+		return isOverlappedWithAnnots;
+	}
+	
+	public void deleteAnnotation(AnnotationType type, int start, int end) throws Exception {
+		em.getTransaction().begin();
+		deleteAnnotationNoCommit(type, start, end);
+		em.getTransaction().commit();
+	}
+	
+	public void deleteAnnotation(AnnotationType type, Match m) throws Exception {
+		deleteAnnotation(type, m.getStart(), m.getEnd());
+	}
+	
+	/**
+	 * Warning this method must be called ONLY if a transaction has been start AND dont forget to call commit after
+	 * 
+	 * @param type
+	 * @param start
+	 * @param end
+	 */
+	public void deleteAnnotationNoCommit(AnnotationType type, int start, int end) {
+		List<Annotation> annots = getAnnotations(type, start, end);
+		for (Annotation annot : annots) {
+			em.remove(annot);
+		}
+	}
+	
+	public void deleteAnnotations() throws Exception {
+		List<Annotation> annots = getAnnotations();
+		em.getTransaction().begin();
+		for (Annotation annot : annots) {
+			em.remove(annot);
+		}
+		em.getTransaction().commit();
+	}
+	
+	public void deleteAnnotations(AnnotationType refType, List<Match> matches) throws Exception {
+		em.getTransaction().begin();
+		for (Match m : matches) {
+			deleteAnnotationNoCommit(refType, m.getStart(), m.getEnd());
+		}
+		em.getTransaction().commit();
+	}
+	
+	/**
+	 * returns all annotations with no particular constraints
+	 * 
+	 * @return
+	 * @throws Exception
+	 */
+	public List<Annotation> getAnnotations() throws Exception {
+		
+		TypedQuery<Annotation> query = em.createQuery("SELECT annot FROM Annotation AS annot", Annotation.class);
+		return query.getResultList();
+	}
+	
+	/**
+	 * returns all annotations with no particular constraints
+	 * 
+	 * @return
+	 * @throws Exception
+	 */
+	public List<Annotation> getAnnotations(AnnotationType type) throws Exception {
+		return getAnnotations(type, false);
+	}
+	
+	/**
+	 * returns all annotations with no particular constraints
+	 * 
+	 * @return
+	 * @throws Exception
+	 */
+	public List<Annotation> getAnnotations(AnnotationType type, boolean ordered) throws Exception {
+		return getAnnotations(type, -1, -1, null);
+	}
+	
+	public List<Annotation> getAnnotations(AnnotationType type, int start, int end) {
+		return getAnnotations(type, start, end, null);
+	}
+	
+	/**
+	 * returns annotation with all available constraints
+	 * 
+	 * @param typeId
+	 * @return
+	 * @throws Exception
+	 */
+	public List<Annotation> getAnnotations(AnnotationType refType, int startPosition, int endPosition, String value) {
+		String query = "SELECT annot FROM Annotation AS annot WHERE annot.PK.refType LIKE '" + refType.getId() + "'";
+		if (startPosition >= 0)
+			query += " AND annot.PK.startpos = " + startPosition;
+		
+		if (endPosition >= 0)
+			query += " AND annot.PK.endpos = " + endPosition;
+		
+		if (value != null)
+			query += " AND annot.refVal LIKE ':" + value + "' ";
+		
+		TypedQuery<Annotation> typedQuery = em.createQuery(query, Annotation.class);
+		return typedQuery.getResultList();
+	}
+	
+	
+	/**
+	 * returns all annotations given a series of positions (start and end)
+	 * 
+	 * @return
+	 * @throws Exception
+	 */
+	public List<Annotation> getAnnotations(AnnotationType type, List<? extends Match> matches, String value, boolean ordered, boolean overlap) throws Exception {
+		String query = "SELECT annot FROM Annotation AS annot";
+		boolean where = false; // TODO: need to replace this
+		
+		String queryPos = " ";
+		int i = 0;
+		
+		for (Match match : matches) {
+			int start, end;
+			if (match.getTarget() >= 0) {
+				start = end = match.getTarget();
+			}
+			else {
+				start = match.getStart();
+				end = match.getEnd();
+			}
+			
+			if (i == 0) {
+				if (overlap) {
+					queryPos += " ( (" + overlapString(start, end, 0) + ")"
+							+ " OR (" + overlapString(start, end, 1) + ") ";
+					// String overlapBesides = "annot.PK.endpos < "+match.getStart()+" OR annot.PK.startpos > "+match.getEnd()+"";
+					// queryPos += " AND NOT ( "+overlapBesides+" ) ) ";
+					queryPos += " OR ( annot.PK.startpos <= " + start + " AND " + end + " <= annot.PK.endpos ) )";
+				}
+				else {
+					queryPos += " (annot.PK.startpos = " + start + " AND annot.PK.endpos = " + end + ")";
+				}
+			}
+			else {
+				if (overlap) {
+					queryPos += " OR ( (" + overlapString(start, end, 0) + ")"
+							+ " OR (" + overlapString(start, end, 1) + ") ";
+					// String overlapBesides = "annot.PK.endpos < "+match.getStart()+" OR annot.PK.startpos > "+match.getEnd()+"";
+					// queryPos += " AND NOT ( "+overlapBesides+" ) ) ";
+					queryPos += " OR ( annot.PK.startpos <= " + start + " AND " + end + " <= annot.PK.endpos ) )";
+				}
+				else {
+					queryPos += " OR (annot.PK.startpos = " + start + " AND annot.PK.endpos = " + end + ")";
+				}
+			}
+			++i;
+		}
+		
+		if (matches.size() > 0) {
+			if (where)
+				query += " AND ( " + queryPos + " )";
+			else {
+				query += " WHERE ( " + queryPos + " )";
+				where = true;
+			}
+		}
+		
+		if (type != null) {
+			if (where)
+				query += " AND annot.PK.refType LIKE '" + type.getId() + "'";
+			else {
+				query += " WHERE annot.PK.refType LIKE '" + type.getId() + "'";
+				where = true;
+			}
+		}
+		
+		if (value != null) {
+			if (where)
+				query += " AND annot.PK.refVal LIKE '" + value + "'";
+			else {
+				query += " WHERE annot.PK.refVal LIKE '" + value + "'";
+				where = true;
+			}
+		}
+		// System.out.println("Query : "+ query);
+		// System.out.println("STOP GET ANNOTATIONS @"+i);
+		TypedQuery<Annotation> typedQuery = em.createQuery(query, Annotation.class);
+		return typedQuery.getResultList();
+	}
+	
+	public List<Annotation> getAnnotationsForMatches(List<Match> sortedMatches, List<Annotation> sortedAnnotations, boolean overlap) {
+		
+		List<Annotation> annotsList = new ArrayList<>();
+//		matches = new ArrayList<>(matches);
+//		Collections.sort(matches);
+		int iMatch = 0;
+		int iAnnotation = 0;
+		int nMatch = sortedMatches.size();
+		int nAnnotations = sortedAnnotations.size();
+		
+		Match match = null;
+		Annotation annotation = null;
+		while (iMatch < nMatch && iAnnotation < nAnnotations) {
+			
+			match = sortedMatches.get(iMatch);
+			int start, end;
+			if (match.getTarget() >= 0) {
+				start = end = match.getTarget();
+			}
+			else {
+				start = match.getStart();
+				end = match.getEnd();
+			}
+			
+			annotation = sortedAnnotations.get(iAnnotation);
+			int astart = annotation.getStart(), aend = annotation.getEnd();
+			
+			if (overlap) {
+				if (end < astart) {
+					iMatch++;
+					annotsList.add(null); // nothing for this match
+				}
+				else if (aend < start) {
+					iAnnotation++;
+				}
+				else {
+					annotsList.add(annotation);
+					iMatch++;
+				}
+			}
+			else {
+				if (end < astart) {
+					iMatch++;
+					annotsList.add(null); // nothing for this match
+				}
+				else if (aend < start) {
+					iAnnotation++;
+				}
+				else if (astart == start &&
+						aend == end) {
+					annotsList.add(annotation);
+					iMatch++;
+					iAnnotation++;
+				}
+				else {
+					iAnnotation++;
+				}
+			}
+		}
+		
+		while (annotsList.size() < sortedMatches.size())
+			annotsList.add(null); // fill matches that were not process due to no more annotations
+			
+		return annotsList;
+	}
+	
+	/**
+	 * You know what you're doing
+	 * 
+	 * @return the EntityManager that manages the DB
+	 */
+	public EntityManager getEntityManager() {
+		return em;
+	}
+	
+	public boolean hasChanges() {
+		try {
+			if (em == null) return false;
+			TypedQuery<Annotation> query = em.createQuery("SELECT annot FROM Annotation AS annot", Annotation.class);
+			// System.out.println("hasChanges query rez: "+query.getResultList());
+			return query.setMaxResults(1).getResultList().size() > 0; // get only the first match -> faster
+		}
+		catch (Exception e) {
+			Log.severe("** Error while testing corpus annotations state: " + e);
+		}
+		return false;
+	}
+	
+	public EntityManager initTemporaryAnnotationDatabase() {
+		HashMap<String, Object> properties = TemporaryAnnotationManager.getInitialisationProperties(this.getClass(), corpus);
+		
+		return initTemporaryAnnotationDatabase(properties);
+	}
+	
+	public EntityManager initTemporaryAnnotationDatabase(HashMap<String, Object> properties) {
+		
+		if (em != null) return em;
+		
+		PersistenceProvider pp = new PersistenceProvider();
+		// System.out.println("Check for provider: "+pp.checkForProviderProperty(properties));
+		
+		// System.out.println("Generate schema: "+pp.generateSchema(PERSISTENCE_UNIT_NAME, properties));
+		// SEPersistenceUnitInfo infos = new SEPersistenceUnitInfo();
+		// infos.setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
+		// infos.setTransactionType(PersistenceUnitTransactionType.RESOURCE_LOCAL);
+		// infos.setPersistenceProviderClassName("org.eclipse.persistence.jpa.PersistenceProvider");
+		// infos.getManagedClassNames().add("org.txm.annotation.Annotation");
+		// infos.getManagedClassNames().add("org.txm.annotation.TypedValue");
+		// pp.generateSchema(infos, properties);
+		
+		emf = pp.createEntityManagerFactory(DatabasePersistenceManager.PERSISTENCE_UNIT_NAME, properties);
+		
+		em = emf.createEntityManager();
+				
+		return em;
+	}
+	
+	private String overlapString(int startPos, int endPos, int typeOverlap) {
+		String overlap = "";
+		switch (typeOverlap) {
+			case 0:
+				return overlap += "annot.PK.startpos >= " + startPos + " AND annot.PK.startpos <= " + endPos; // OverlapOnStart
+			case 1:
+				return overlap += "annot.PK.endpos >= " + startPos + " AND annot.PK.endpos <= " + endPos + ""; // OverlapOnEnd
+			default:
+				return overlap;
+		}
+		
+	}
+	
+	/**
+	 * returns annotation with all available constraints
+	 * 
+	 * @param typeId
+	 * @return
+	 * @throws Exception
+	 */
+	// A REVOIR avec le tuto : http://stackoverflow.com/questions/2772305/jpql-in-clause-java-arrays-or-lists-sets
+	/*
+	 * public List<Annotation> getAnnotations(AnnotationType refType, int[] startPositions, int[] endPositions, String value, boolean ordered) {
+	 * EntityManager em = getJPAManager(corpus);
+	 * String query = "SELECT annot FROM Annotation AS annot "
+	 * + "WHERE annot.PK.refType LIKE '"+refType.getId()+"'";
+	 * if (startPositions.length > 0)
+	 * query += " AND annot.PK.startpos IN :startpositions ";
+	 * if (endPositions.length > 0)
+	 * query += " AND annot.PK.endpos IN :endpositions ";
+	 * if (value != null)
+	 * query += " AND annot.refVal LIKE ':"+value+"' ";
+	 * if (ordered)
+	 * query += " ORDER BY annot.refVal, annot.PK.startpos ASC";
+	 * TypedQuery<Annotation> typedQuery = em.createQuery(query, Annotation.class);
+	 * List<String> positionsOfStart = Arrays.asList(startPositions.toString());
+	 * List<String> positionsOfEnd = Arrays.asList(endPositions.toString());
+	 * typedQuery.setParameter("startpositions", positionsOfStart);
+	 * typedQuery.setParameter("endpositions", positionsOfEnd);
+	 * return typedQuery.getResultList();
+	 * }
+	 */
+	
+	// /**
+	// * Should not
+	// * @param corpus
+	// * @param refType
+	// * @param refVal
+	// * @param startPos
+	// * @param endPos
+	// * @return
+	// */
+	// public List<Annotation> isOverlapAnnotationCritical(AnnotationType refType, TypedValue refVal, int startPos, int endPos){
+	// EntityManager em = getJPAManager(corpus);
+	//
+	// String query = "SELECT annot FROM Annotation AS annot "
+	//
+	// + "WHERE ( annot.PK.refType not LIKE '"+refType.getId()+"' ";
+	// //String overlapInside = "annot.PK.startpos >= "+startPos+" OR annot.PK.endpos <= "+endPos+"";
+	// //String overlapOutside = "annot.PK.startpos <= "+startPos+" OR annot.PK.endpos >= "+endPos+"";
+	// //query += " AND ( ( "+overlapInside+" ) OR ( "+overlapOutside+" ) ) AND NOT ( "+overlapBesides+" ) ) ";
+	// String overlapOnEnd = "annot.PK.startpos >= "+startPos+" AND annot.PK.startpos <= "+endPos +" AND annot.PK.endpos >= "+endPos+"";
+	// String overlapOnStart = "annot.PK.startpos <= "+startPos+" AND annot.PK.endpos >= "+startPos+" AND annot.PK.endpos <= "+endPos+"";
+	// String overlapBesides = "annot.PK.endpos < "+startPos+" OR annot.PK.startpos > "+endPos+"";
+	// query += " AND ( ( "+overlapOnEnd+" ) OR ( "+overlapOnStart+" ) ) ) ";
+	// query += " OR ( annot.PK.refType LIKE '"+refType.getId()+"' ";
+	// query += " AND NOT ( "+overlapBesides+" ) ) ";
+	//
+	// System.out.println("Query for OVERLAP : "+query);
+	// TypedQuery<Annotation> typedQuery = em.createQuery(query, Annotation.class);
+	// return typedQuery.getResultList();
+	// }
+	
+	// Not necessary for the moment (@finnishgazelle, 22/10/2015)
+	
+	/*
+	 * private void modifyAnnotations(int typeModif, List<int[]> positions, String refVal, String newrefVal, String refType, String newrefType) throws Exception{
+	 * switch(typeModif){
+	 * case MODIFY_TYPEVAL : modifyAnnotations(positions, refType, refVal, newrefType, newrefVal) ;
+	 * break;
+	 * case MODIFY_VAL : modifyAnnotations(positions, refVal, newrefVal);
+	 * break;
+	 * default: ;
+	 * break;
+	 * }
+	 * }
+	 * private void modifyAnnotations(List<int[]> positions, String refVal, String newrefVal) throws Exception{
+	 * //List<Annotation> annots = getAnnotationsByRefValue(refVal);
+	 * for (int[] position : positions){
+	 * Annotation annot = entityManager.find(Annotation.class, position[0]+"_"+position[1]);
+	 * if(annot.getReferentielVal().equals(refVal)){
+	 * entityManager.getTransaction().begin();
+	 * annot.setReferentielVal(newrefVal);
+	 * entityManager.getTransaction().commit();
+	 * }
+	 * }
+	 * }
+	 * private void modifyAnnotations(List<int[]> positions, String refType, String refVal, String newrefType, String newrefVal) throws Exception{
+	 * for (int[] position : positions){
+	 * Annotation annot = entityManager.find(Annotation.class, position[0]+"_"+position[1]);
+	 * if(annot.getReferentielVal().equals(refVal) && annot.getReferentielType().equals(refType)){
+	 * entityManager.getTransaction().begin();
+	 * annot.setReferentielVal(newrefVal);
+	 * annot.setReferentielVal(newrefType);
+	 * entityManager.getTransaction().commit();
+	 * }
+	 * }
+	 * }
+	 */
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/storage/temporary/TemporaryAnnotationManager.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/messages/KRAnnotationCoreMessages.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/messages/KRAnnotationCoreMessages.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/messages/KRAnnotationCoreMessages.java	(revision 3653)
@@ -0,0 +1,34 @@
+package org.txm.annotation.kr.core.messages;
+
+import org.eclipse.osgi.util.NLS;
+import org.txm.utils.messages.Utf8NLS;
+
+
+/**
+ * KR annotation Core messages.
+ * 
+ * @author mdecorde
+ * @author sjacquot
+ *
+ */
+public class KRAnnotationCoreMessages extends NLS {
+	
+	private static final String BUNDLE_NAME = "org.txm.annotation.kr.core.messages.messages"; //$NON-NLS-1$
+	
+	public static String savingP0Annotations;
+	
+	public static String annotationSuccesfullyWritten;
+	
+	public static String savingAnnotations;
+	
+	public static String annotationSuccesfullyWrittenIntheP0File;
+	
+	static {
+		// initialize resource bundle
+		Utf8NLS.initializeMessages(BUNDLE_NAME, KRAnnotationCoreMessages.class);
+	}
+	
+	private KRAnnotationCoreMessages() {
+		
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/messages/KRAnnotationCoreMessages.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/messages/messages_fr.properties
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/messages/messages_fr.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/messages/messages_fr.properties	(revision 3653)
@@ -0,0 +1,6 @@
+#TXM messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+annotationSuccesfullyWritten=Fichiers pivots mis à jour.
+annotationSuccesfullyWrittenIntheP0File=Annotations enregistrées dans le fichier {0}.
+savingAnnotations=Enregistrement des annotations
+savingP0Annotations=Enregistrement de {0} annotations...

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/messages/messages_fr.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/messages/messages.properties
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/messages/messages.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/messages/messages.properties	(revision 3653)
@@ -0,0 +1,6 @@
+#TXM messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+annotationSuccesfullyWritten=Pivot files updated.
+annotationSuccesfullyWrittenIntheP0File=Annotations successfully written in the {0} file.
+savingAnnotations=Saving annotations.
+savingP0Annotations=Saving {0} annotations...

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/messages/messages.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/Activator.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/Activator.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/Activator.java	(revision 3653)
@@ -0,0 +1,50 @@
+package org.txm.annotation.kr.core;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+	
+	// The plug-in ID
+	public static final String PLUGIN_ID = "org.txm.annotation.core"; //$NON-NLS-1$
+	
+	// The shared instance
+	private static Activator plugin;
+	
+	/**
+	 * The constructor
+	 */
+	public Activator() {
+		
+	}
+	
+	/*
+	 * (non-Javadoc)
+	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+	 */
+	public void start(BundleContext context) throws Exception {
+		super.start(context);
+		plugin = this;
+	}
+	
+	/*
+	 * (non-Javadoc)
+	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+	 */
+	public void stop(BundleContext context) throws Exception {
+		plugin = null;
+		super.stop(context);
+	}
+	
+	/**
+	 * Returns the shared instance
+	 *
+	 * @return the shared instance
+	 */
+	public static Activator getDefault() {
+		return plugin;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/Activator.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/KRAnnotationEngine.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/KRAnnotationEngine.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/KRAnnotationEngine.java	(revision 3653)
@@ -0,0 +1,554 @@
+package org.txm.annotation.kr.core;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+import org.txm.annotation.core.AnnotationEngine;
+import org.txm.annotation.kr.core.preferences.KRAnnotationPreferences;
+import org.txm.annotation.kr.core.repository.KnowledgeRepository;
+import org.txm.annotation.kr.core.repository.KnowledgeRepositoryManager;
+import org.txm.annotation.kr.core.repository.SQLKnowledgeRepository;
+import org.txm.core.results.TXMResult;
+import org.txm.objects.CorpusBuild;
+import org.txm.objects.Project;
+import org.txm.searchengine.cqp.corpus.CQPCorpus;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.sql.SQLConnection;
+import org.txm.utils.DeleteDir;
+import org.txm.utils.logger.Log;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class KRAnnotationEngine extends AnnotationEngine {
+	
+	static HashMap<MainCorpus, AnnotationManager> ams = new HashMap<>();
+	
+	public static String KNOWLEDGE_ACCESS = "access";
+	
+	public static String KNOWLEDGE_STRINGS = "strings";
+	
+	public static String KNOWLEDGE_TYPEQUERIES = "queries";
+	
+	public static String KNOWLEDGE_TYPES = "fields";
+	
+	public static String KNOWLEDGE_TYPEWEBACCESS = "typeaccess";
+	
+	public static boolean canBeAnnotated(MainCorpus corpus) {
+		return getKnowledgeRepositoryNames(corpus).size() > 0;
+	}
+	
+	public static AnnotationManager getAnnotationManager(CQPCorpus corpus) throws Exception {
+		return getAnnotationManager(corpus.getMainCorpus());
+	}
+	
+	/**
+	 * get the corpus Annotation Manager and Lazy load if created
+	 * 
+	 * @param corpus
+	 * @return
+	 * @throws Exception
+	 */
+	public static AnnotationManager getAnnotationManager(MainCorpus corpus) throws Exception {
+		AnnotationManager am = ams.get(corpus);
+		if (am == null) {
+			am = new AnnotationManager(corpus);
+			am.initialize();
+			ams.put(corpus, am);
+		}
+		return am;
+	}
+	
+	// protected static Element getKnowledgeRepositoriesElement(Element corpusElement) {
+	// NodeList textsList = corpusElement.getElementsByTagName("knowledgeRepositories");
+	// if (textsList.getLength() == 0) {
+	// Element knowledgeRepositories = corpusElement.getOwnerDocument().createElement("knowledgeRepositories");
+	// corpusElement.appendChild(knowledgeRepositories);
+	// return knowledgeRepositories;
+	// } else {
+	// return (Element) textsList.item(0);
+	// }
+	// }
+	
+	/**
+	 * 
+	 * Lazy load KR
+	 * 
+	 * @param name KnowledgeRepository's name
+	 * @return may return null if the KnowledgeRepository does not exist
+	 * @throws BackingStoreException
+	 */
+	public static KnowledgeRepository getKnowledgeRepository(CQPCorpus corpus, String name) throws BackingStoreException {
+		return KnowledgeRepositoryManager.getKnowledgeRepository(name, corpus.getMainCorpus());
+	}
+	
+	/**
+	 * Utility method to get a knowledge repository configuration
+	 * 
+	 * @param name the repository name
+	 * @return the KR configuration map
+	 */
+	public static HashMap<String, HashMap<String, ?>> getKnowledgeRepositoryConfiguration(String name, Element e) {
+		HashMap<String, HashMap<String, ?>> repConfiguration = new HashMap<>();
+		
+		HashMap<String, String> access = new HashMap<>();
+		HashMap<String, HashMap<String, String>> strings = new HashMap<>();
+		HashMap<String, HashMap<String, String>> fields = new HashMap<>();
+		
+		if (e == null) return null;
+		
+		access.put(SQLKnowledgeRepository.NAME, e.getAttribute(SQLKnowledgeRepository.NAME));
+		access.put("version", e.getAttribute("version"));
+		access.put("mode", e.getAttribute("mode"));
+		access.put(SQLKnowledgeRepository.TYPE_URL, e.getAttribute(SQLKnowledgeRepository.TYPE_URL));
+		access.put(SQLKnowledgeRepository.TYPE_RESURL, e.getAttribute(SQLKnowledgeRepository.TYPE_RESURL));
+		access.put(SQLKnowledgeRepository.TYPE_TYPEURL, e.getAttribute(SQLKnowledgeRepository.TYPE_TYPEURL));
+		access.put(SQLConnection.SQL_ADDRESS, e.getAttribute(SQLConnection.SQL_ADDRESS));
+		access.put(SQLConnection.SQL_DRIVER, e.getAttribute(SQLConnection.SQL_DRIVER));
+		access.put(SQLConnection.SQL_PORT, e.getAttribute(SQLConnection.SQL_PORT));
+		access.put(SQLConnection.SQL_USER, e.getAttribute(SQLConnection.SQL_USER));
+		access.put(SQLConnection.SQL_PASSWORD, e.getAttribute(SQLConnection.SQL_PASSWORD));
+		
+		// <type id="" name> ... </type>
+		NodeList typesList = e.getElementsByTagName("type");
+		for (int i = 0; i < typesList.getLength(); i++) {
+			// <field type="xxx">yyy</field>
+			Element typeElement = (Element) typesList.item(i);
+			String type_id = "" + typeElement.getAttribute(SQLKnowledgeRepository.TYPE_ID);
+			
+			String type_name = typeElement.getAttribute(SQLKnowledgeRepository.NAME);
+			if (type_name == null || type_name.length() == 0) type_name = type_id;
+			
+			String type_url = "" + typeElement.getAttribute(SQLKnowledgeRepository.TYPE_URL);
+			
+			String type_size = typeElement.getAttribute(SQLKnowledgeRepository.TYPE_SIZE);
+			if (type_size == null || type_size.length() == 0) type_size = "SMALL"; // show all by default
+			type_size = type_size.toUpperCase();
+			
+			String type_effect = typeElement.getAttribute(SQLKnowledgeRepository.TYPE_EFFECT);
+			if (type_effect == null || type_effect.length() == 0) type_effect = "SEGMENT"; // segment annotation by default
+			type_effect = type_effect.toUpperCase();
+			
+			HashMap<String, String> hashFields = new HashMap<>();
+			NodeList fieldsList = typeElement.getElementsByTagName("field"); // contains KR type specific properties
+			for (int j = 0; j < fieldsList.getLength(); j++) {
+				Element fieldElement = (Element) fieldsList.item(j);
+				hashFields.put(fieldElement.getAttribute("type"), fieldElement.getTextContent());
+			}
+			
+			hashFields.put(SQLKnowledgeRepository.TYPE_URL, type_url);
+			hashFields.put(SQLKnowledgeRepository.NAME, type_name);
+			hashFields.put(SQLKnowledgeRepository.TYPE_SIZE, type_size);
+			hashFields.put(SQLKnowledgeRepository.TYPE_EFFECT, type_effect);
+			fields.put(type_id, hashFields);
+		}
+		
+		NodeList stringsList = e.getElementsByTagName("strings");
+		for (int i = 0; i < stringsList.getLength(); i++) {
+			Element stringsElement = (Element) stringsList.item(i);
+			String lang = stringsElement.getAttribute("lang");
+			if (lang == null) lang = "en"; // default lang is "en"
+			
+			HashMap<String, String> values = new HashMap<>();
+			strings.put(lang, values);
+			
+			NodeList stringList = stringsElement.getElementsByTagName("string");
+			for (int j = 0; j < stringList.getLength(); j++) {
+				Element stringElement = (Element) stringList.item(j);
+				String key = stringElement.getAttribute("key");
+				if (key != null) {
+					values.put(key, stringElement.getTextContent());
+				}
+			}
+		}
+		
+		repConfiguration.put(KNOWLEDGE_ACCESS, access);
+		repConfiguration.put(KNOWLEDGE_TYPES, fields);
+		repConfiguration.put(KNOWLEDGE_STRINGS, strings);
+		
+		return repConfiguration;
+	}
+	
+	/**
+	 * Utility method to get a knowledge repository configuration
+	 * 
+	 * @param name the repository name
+	 * @return the KR configuration map
+	 * @throws BackingStoreException
+	 */
+	public static HashMap<String, HashMap<String, ?>> getKnowledgeRepositoryConfiguration(String name, Preferences preference) throws BackingStoreException {
+		HashMap<String, HashMap<String, ?>> repConfiguration = new HashMap<>();
+		
+		HashMap<String, String> access = new HashMap<>();
+		HashMap<String, HashMap<String, String>> strings = new HashMap<>();
+		HashMap<String, HashMap<String, String>> fields = new HashMap<>();
+		
+		if (preference == null) return null;
+		
+		access.put(SQLKnowledgeRepository.NAME, preference.get(SQLKnowledgeRepository.NAME, "default"));
+		access.put("version", preference.get("version", "0"));
+		access.put("mode", preference.get("mode", ""));
+		access.put(SQLKnowledgeRepository.TYPE_URL, preference.get(SQLKnowledgeRepository.TYPE_URL, ""));
+		access.put(SQLKnowledgeRepository.TYPE_RESURL, preference.get(SQLKnowledgeRepository.TYPE_RESURL, ""));
+		access.put(SQLKnowledgeRepository.TYPE_TYPEURL, preference.get(SQLKnowledgeRepository.TYPE_TYPEURL, ""));
+		access.put(SQLConnection.SQL_ADDRESS, preference.get(SQLConnection.SQL_ADDRESS, ""));
+		access.put(SQLConnection.SQL_DRIVER, preference.get(SQLConnection.SQL_DRIVER, ""));
+		access.put(SQLConnection.SQL_PORT, preference.get(SQLConnection.SQL_PORT, ""));
+		access.put(SQLConnection.SQL_USER, preference.get(SQLConnection.SQL_USER, ""));
+		access.put(SQLConnection.SQL_PASSWORD, preference.get(SQLConnection.SQL_PASSWORD, ""));
+		
+		// <type id="" name> ... </type>
+		Preferences typesList = preference.node("type");
+		for (String type_id : typesList.childrenNames()) {
+			// <field type="xxx">yyy</field>
+			// Element typeElement = (Element)typesList.item(i);
+			// String type_id = ""+typeElement.getAttribute(SQLKnowledgeRepository.TYPE_ID);
+			
+			Preferences typeElement = typesList.node(type_id);
+			
+			String type_name = typeElement.get(SQLKnowledgeRepository.NAME, type_id);
+			
+			String type_url = "" + typeElement.get(SQLKnowledgeRepository.TYPE_URL, "");
+			
+			String type_size = typeElement.get(SQLKnowledgeRepository.TYPE_SIZE, "SMALL");
+			type_size = type_size.toUpperCase();
+			
+			String type_effect = typeElement.get(SQLKnowledgeRepository.TYPE_EFFECT, "SEGMENT");
+			type_effect = type_effect.toUpperCase();
+			
+			HashMap<String, String> hashFields = new HashMap<>();
+			Preferences fieldsList = typeElement.node("field"); // contains KR type specific properties
+			for (String field_type : fieldsList.keys()) {
+				hashFields.put(field_type, fieldsList.get(field_type, ""));
+			}
+			
+			hashFields.put(SQLKnowledgeRepository.TYPE_URL, type_url);
+			hashFields.put(SQLKnowledgeRepository.NAME, type_name);
+			hashFields.put(SQLKnowledgeRepository.TYPE_SIZE, type_size);
+			hashFields.put(SQLKnowledgeRepository.TYPE_EFFECT, type_effect);
+			fields.put(type_id, hashFields);
+		}
+		
+		Preferences stringsList = preference.node("strings");
+		for (String lang : stringsList.childrenNames()) {
+			Preferences stringsElement = stringsList.node(lang);
+			// String lang = stringsElement.getAttribute("lang");
+			// if (lang == null) lang = "en"; // default lang is "en"
+			
+			HashMap<String, String> values = new HashMap<>();
+			strings.put(lang, values);
+			
+			for (String key : stringsElement.keys()) {
+				values.put(key, stringsElement.get(key, ""));
+			}
+		}
+		
+		repConfiguration.put(KNOWLEDGE_ACCESS, access);
+		repConfiguration.put(KNOWLEDGE_TYPES, fields);
+		repConfiguration.put(KNOWLEDGE_STRINGS, strings);
+		
+		return repConfiguration;
+	}
+	
+	// public static Element getKnowledgeRepositoryElement(BaseOldParameters params, String name) {
+	// Element rElement = getKnowledgeRepositoriesElement(params.getCorpusElement());
+	// NodeList repositoriesList = rElement.getElementsByTagName("repository");
+	// for (int i = 0 ; i < repositoriesList.getLength() ; i++) {
+	// Element e = ((Element)repositoriesList.item(i));
+	// if (name.equals(e.getAttribute("name"))) {
+	// return e;
+	// }
+	// }
+	//
+	// return null;
+	// }
+	
+	
+	// /**
+	// * Utility method to get a knowledge repository configuration
+	// *
+	// * @param params
+	// * @return the repository names
+	// */
+	// public static List<String> getKnowledgeRepositoryNames(BaseOldParameters params) {
+	// ArrayList<String> names = new ArrayList<String>();
+	// Element corpusElement = params.getCorpusElement();
+	// if (corpusElement == null) return names;
+	//
+	// Element rElement = getKnowledgeRepositoriesElement(corpusElement);
+	// if (rElement == null) return names;
+	//
+	// NodeList repositoriesList = rElement.getElementsByTagName("repository");
+	// for (int i = 0 ; i < repositoriesList.getLength() ; i++) {
+	// names.add(((Element)repositoriesList.item(i)).getAttribute("name"));
+	// }
+	//
+	// if (names.size() == 0) names.add(params.getCorpusName()); // add default KR = properties & structure properties
+	// return names;
+	// }
+	
+	/**
+	 * 
+	 * @param corpus the corpus
+	 * @return the repository names the corpus is using
+	 */
+	public static List<String> getKnowledgeRepositoryNames(CQPCorpus corpus) {
+		if (corpus == null) return new ArrayList<>();
+		Project base = corpus.getProject();
+		if (base == null) return new ArrayList<>();
+		
+		String[] names;
+		try {
+			IEclipsePreferences node = base.getPreferencesScope().getNode("KnowledgeRepository");
+			if (!node.nodeExists(corpus.getID())) {
+				// create the "DEFAULT" KR configuration
+				Preferences krconf = node.node(corpus.getID());
+				krconf.put("name", corpus.getID());
+			}
+			names = node.childrenNames();
+			return Arrays.asList(names); // getKnowledgeRepositoryNames(params);
+		}
+		catch (BackingStoreException e) {
+			e.printStackTrace();
+			return new ArrayList<>();
+		}
+	}
+	
+	/**
+	 * 
+	 * @param corpus
+	 * @return true if there are annotations to save for this corpus
+	 */
+	public static boolean needToSaveAnnotations(MainCorpus corpus) {
+		AnnotationManager am = ams.get(corpus);
+		if (am != null)
+			return am.isDirty();
+		else
+			return false;
+	}
+	
+	public void closeAnnotationManager(MainCorpus corpus) {
+		AnnotationManager am = ams.get(corpus);
+		if (am != null) {
+			// System.out.println(" Closing AM...");
+			am.closeAll();
+		}
+	}
+	
+	// public static Element createKnowledgeRepositoryElement(BaseOldParameters params, String name) {
+	// Element rElement = getKnowledgeRepositoriesElement(params.getCorpusElement());
+	// Element e = rElement.getOwnerDocument().createElement("repository");
+	// e.setAttribute("name", name);
+	// e.setAttribute("mode", "file");
+	// e.setAttribute("user", "false");
+	// e.setAttribute("password", "false");
+	// e.setAttribute("version", "0");
+	//
+	// rElement.appendChild(e);
+	// return e;
+	// }
+	
+	@Override
+	public String getName() {
+		return "CQP";
+	}
+	
+	@Override
+	public boolean isRunning() {
+		return true;
+	}
+	
+	@Override
+	public boolean initialize() { // nothing to load right now, the kr and am are lazy
+		return true;
+	}
+	
+	@SuppressWarnings("unchecked")
+	public boolean[] mustLoginToKnowledgeRepository(CQPCorpus corpus, String kr_name) {
+		return KnowledgeRepositoryManager.mustLoginToKnowledgeRepository(kr_name, corpus.getMainCorpus());
+	}
+	
+	@Override
+	public boolean start(IProgressMonitor monitor) {
+		ams = new HashMap<>();
+		return true;
+	}
+	
+	@Override
+	public boolean stop() {
+		boolean success = true;
+		for (KnowledgeRepository kr : KnowledgeRepositoryManager.getKnowledgeRepositories()) {
+			try {
+				if (kr.getJPAManager().isOpen())
+					kr.getJPAManager().close();
+			}
+			catch (Exception e) {
+				Log.warning(NLS.bind("Error: cannot close the {0} KR : {1}.", kr, e.getLocalizedMessage()));
+				Log.printStackTrace(e);
+				success = false;
+			}
+		}
+		for (AnnotationManager am : ams.values()) {
+			try {
+				if (am.isOpen())
+					am.closeAll();
+			}
+			catch (Exception e) {
+				Log.warning(NLS.bind("Error: cannot close the {0} AM : {1}.", am, e.getLocalizedMessage()));
+				Log.printStackTrace(e);
+				success = false;
+			}
+		}
+		ams.clear();
+		return success;
+	}
+	
+	/**
+	 * The KR Annotation engine is an assisted oriented annotation engine
+	 * 
+	 * @return false
+	 */
+	@Override
+	public boolean isAutomatic() {
+		return false;
+	}
+	
+	@Override
+	public boolean processFile(File xmlFile, File binaryCorpusDirectory, HashMap<String, Object> parameters) {
+		return false;
+	}
+	
+	@Override
+	public void notify(TXMResult r, String state) {
+		
+		if (r instanceof MainCorpus && "before_clean".equals(state)) {
+			
+			MainCorpus c = (MainCorpus) r;
+			
+			if (c.getProject() == null || c.getProject().getDoUpdate()) {
+				return;
+			}
+			
+			for (String krname : KRAnnotationEngine.getKnowledgeRepositoryNames(c)) {
+				Log.fine("cleaning KR: " + krname);
+				KRAnnotationEngine.unregisterKnowledgeRepositoryName(c, krname);
+			}
+			
+			if (c.getProjectDirectory() == null || !c.getProjectDirectory().exists()) {
+				return;
+			}
+			
+			if (ams.get(c) != null && ams.get(c).tempManager != null && ams.get(c).tempManager.getEntityManager() != null ) {
+				Log.fine("closing temporary annotations database of: "+c);
+				ams.get(c).tempManager.close(); // free files
+			}
+			
+			File buildDirectory = new File(c.getProjectDirectory(), "temporary_annotations/" + c.getID());
+			if (buildDirectory.exists()) {
+				DeleteDir.deleteDirectory(buildDirectory);
+			}
+		} else if (r instanceof MainCorpus && "clean".equals(state)) {
+			
+			MainCorpus c = (MainCorpus) r;
+			
+			if (c.getProject() == null || c.getProject().getDoUpdate()) {
+				return;
+			}
+			
+			for (String krname : KRAnnotationEngine.getKnowledgeRepositoryNames(c)) {
+				Log.fine("cleaning KR: " + krname);
+				KRAnnotationEngine.unregisterKnowledgeRepositoryName(c, krname);
+			}
+			
+			
+			
+			if (c.getProjectDirectory() == null || !c.getProjectDirectory().exists()) {
+				return;
+			}
+			
+			if (ams.get(c) != null && ams.get(c).tempManager != null && ams.get(c).tempManager.getEntityManager() != null ) {
+				Log.fine("closing temporary annotations databse of: "+c);
+				ams.get(c).tempManager.close(); // free files
+			}
+			
+			File buildDirectory = new File(c.getProjectDirectory(), "temporary_annotations/" + c.getID());
+			if (buildDirectory.exists()) {
+				DeleteDir.deleteDirectory(buildDirectory);
+			}
+		}
+		else if (r instanceof Project && "clean".equals(state)) {
+			
+			Project p = (Project) r;
+			for (MainCorpus c : p.getChildren(MainCorpus.class)) { // if any MainCorpus is remaining, clean it
+				for (String krname : KRAnnotationEngine.getKnowledgeRepositoryNames(c)) {
+					Log.fine("cleaning KR: " + krname);
+					KRAnnotationEngine.unregisterKnowledgeRepositoryName(c, krname);
+				}
+			}
+			File buildDirectory = new File(p.getProjectDirectory(), "temporary_annotations");
+			if (buildDirectory.exists()) {
+				DeleteDir.deleteDirectory(buildDirectory);
+			}
+		}
+	}
+	
+	@Override
+	public String getDetails() {
+		return "";
+	}
+	
+	public static void registerKnowledgeRepositoryName(CQPCorpus corpus, String name) {
+		if (corpus == null) return;
+		Project project = corpus.getProject();
+		if (project == null) return;
+		try {
+			IEclipsePreferences node = project.getPreferencesScope().getNode("KnowledgeRepository");
+			if (!node.nodeExists(name)) {
+				// create the "DEFAULT" KR configuration
+				Preferences krconf = node.node(name);
+				krconf.put("name", name);
+			}
+		}
+		catch (BackingStoreException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	public static void unregisterKnowledgeRepositoryName(CQPCorpus corpus, String name) {
+		if (corpus == null) return;
+		Project project = corpus.getProject();
+		if (project == null) return;
+		try {
+			IEclipsePreferences node = project.getPreferencesScope().getNode("KnowledgeRepository");
+			if (node.nodeExists(name)) {
+				Preferences krconf = node.node(name);
+				krconf.removeNode();
+			}
+			
+			KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(name);
+			if (kr != null) {
+				Log.fine("Deleting KR database: " + kr);
+				KnowledgeRepositoryManager.deleteKnowledgeRepository(kr);
+			}
+		}
+		catch (BackingStoreException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	@Override
+	public boolean hasAnnotationsToSave(CorpusBuild corpus) {
+		
+		if (KRAnnotationPreferences.getInstance().getBoolean(KRAnnotationPreferences.PRESERVE_ANNOTATIONS)) return false;
+		
+		if (!ams.containsKey(corpus)) return false; // no annotation manager -> not annotations to save
+		return ams.get(corpus).hasChanges();
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/KRAnnotationEngine.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/KnowledgeRepository.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/KnowledgeRepository.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/KnowledgeRepository.java	(revision 3653)
@@ -0,0 +1,503 @@
+package org.txm.annotation.kr.core.repository;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.logging.Level;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Query;
+import javax.persistence.TypedQuery;
+
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.persistence.config.PersistenceUnitProperties;
+import org.eclipse.persistence.jpa.PersistenceProvider;
+import org.txm.Toolbox;
+import org.txm.annotation.kr.core.DatabasePersistenceManager;
+import org.txm.utils.logger.Log;
+
+public abstract class KnowledgeRepository { // extends Vector<AnnotationType>
+	
+	protected String values_base_url = "";
+	
+	protected String types_base_url = "";
+	
+	protected String url = "";
+	
+	protected String dbPath = ""; // the KR database path
+	
+	protected String name;
+	
+	protected int version = 0;
+	
+	protected boolean loginNeeded = false;
+	
+	protected boolean passwordNeeded = false;
+	
+	protected EntityManager jpaem = null;
+	
+	protected HashMap<String, HashMap<String, String>> fieldsTypesProperties;
+	
+	protected String accessType;
+	
+	protected HashMap<String, String> accessProperties;
+
+	private EntityManagerFactory emf;
+	
+	public final static String NAME = "name";
+	
+	public final static String TYPE_URL = "url";
+	
+	public final static String TYPE_RESURL = "resurl";
+	
+	public final static String TYPE_TYPEURL = "typeurl";
+	
+	public final static String TYPE_ID = "id";
+	
+	public final static String TYPE_SIZE = "size";
+	
+	public final static String TYPE_EFFECT = "effect";
+	
+	public final static String TYPE_SQLFIELD_NAME = "sql_name";
+	
+	public final static String TYPE_SQLFIELD_ID = "sql_id";
+	
+	public final static String TYPE_SQLFIELD_QUERY = "sql_query";
+	
+	public final static String LOGIN_KEY = "org.txm.repository.credencies.login.";
+	
+	public final static String PASSWORD_KEY = "org.txm.repository.credencies.password.";
+	
+	public static final boolean[] FALSES = { false, false };
+	
+	public KnowledgeRepository(String name) {
+		this.name = name;
+	}
+	
+	public String toString() {
+		return name;
+	}
+	
+	/**
+	 * Initialize the JPA persistence database
+	 * 
+	 * @return
+	 */
+	public EntityManager initializeEntityManager() {
+		this.dbPath = new File(Toolbox.getTxmHomePath(), "repositories/" + name).getAbsolutePath();
+		// System.out.println("KnowledgeRepository.initializeEntityManager [DB @ "+dbPath+"]");
+		
+		HashMap<String, Object> properties = new HashMap<String, Object>();
+		properties.put(PersistenceUnitProperties.CLASSLOADER, this.getClass().getClassLoader());
+		// ClassLoader loader = BundleUtils.getLoader("org.txm.annotation.core");
+		// URL res = loader.getResource("META-INF/persistence.xml");
+		//
+		// properties.put(PersistenceUnitProperties.ECLIPSELINK_PERSISTENCE_XML, "/home/mdecorde/workspace079/org.txm.annotation.core/META-INF");
+		// //properties.put("javax.persistence.jdbc.driver", "org.hsqldb.jdbcDriver");
+		String urlProperty = "jdbc:hsqldb:file:" + dbPath + "/db;shutdown=true;hsqldb.lock_file=false;";
+		if (Log.getLevel().intValue() < Level.INFO.intValue()) {
+			urlProperty += "";
+		}
+		else {
+			urlProperty += "hsqldb.applog=0;hsqldb.sqllog=0";
+		}
+		properties.put("javax.persistence.jdbc.url", urlProperty);
+		// properties.put("javax.persistence.jdbc.username", "SA");
+		// properties.put(PersistenceUnitProperties.DDL_GENERATION_MODE, "database");
+		properties.put(PersistenceUnitProperties.DDL_GENERATION, "create-or-extend-tables"); // create&update table if needed
+		// properties.put(PersistenceUnitProperties.DDL_GENERATION, "drop-and-create-tables"); // drop all and recreate
+		// if (Log.getLevel().intValue() < Level.WARNING.intValue()) {
+		// properties.put(PersistenceUnitProperties.LOGGING_LEVEL, "WARNING");
+		// properties.put(PersistenceUnitProperties.LOGGING_PARAMETERS, "true");
+		// } else {
+		// properties.put(PersistenceUnitProperties.LOGGING_LEVEL, "OFF");
+		// properties.put(PersistenceUnitProperties.LOGGING_PARAMETERS, "false");
+		// }
+		
+		// Logger.getLogger("org").setLevel(Level.ALL);
+		PersistenceProvider pp = new PersistenceProvider();
+		emf = pp.createEntityManagerFactory(DatabasePersistenceManager.PERSISTENCE_UNIT_NAME, properties);
+		if (emf == null) {
+			Log.warning(NLS.bind("Error: could not create the ''{0}'' EntityManagerFactory and PersistenceProvider={1}.", DatabasePersistenceManager.PERSISTENCE_UNIT_NAME, pp));
+			return null;
+		}
+		EntityManager entityManager = (EntityManager) emf.createEntityManager();
+		this.jpaem = entityManager;
+		
+		return entityManager;
+	}
+	
+	
+	public void setAccessProperties(HashMap<String, String> accessProperties) {
+		this.accessProperties = accessProperties;
+		
+		String sVersion = accessProperties.get("version");
+		if (sVersion.length() > 0) {
+			this.version = Integer.parseInt(sVersion);
+		}
+		this.url = accessProperties.get(TYPE_URL);
+		this.values_base_url = accessProperties.get(TYPE_RESURL);
+		this.types_base_url = accessProperties.get(TYPE_TYPEURL);
+		
+	}
+	
+	public HashMap<String, String> getAccessProperties() {
+		return accessProperties;
+	}
+	
+	public boolean isLoginNeeded() {
+		return loginNeeded;
+	}
+	
+	public boolean isPasswordNeeded() {
+		return passwordNeeded;
+	}
+	
+	public void setCredencialsNeeded(boolean login, boolean password) {
+		this.loginNeeded = login;
+		this.passwordNeeded = password;
+	}
+	
+	public EntityManager getJPAManager() {
+		return this.jpaem;
+	}
+	
+	public abstract String getAccessType(); // local file, sql ...
+	
+	public String getName() {
+		return name;
+	}
+	
+	public List<TypedValue> getValues(AnnotationType type) throws Exception {
+		return getValues(type, -1);
+	}
+	
+	/**
+	 * returns a resource URL for a defined TypedValue (for instance to display in a html viewer)
+	 * 
+	 * @param kr
+	 * @param typedValue
+	 * @return
+	 */
+	public String getValueURL(TypedValue typedValue) {
+		return values_base_url + typedValue.getId();
+	}
+	
+	/**
+	 * returns a resource URL for a defined TypedValue (for instance to display in a html viewer)
+	 * 
+	 * @param kr
+	 * @param typedValue
+	 * @return
+	 */
+	public String getTypeURL(AnnotationType type) {
+		String url = type.getURL();
+		if (url == null || url.length() == 0) {
+			if (types_base_url != null && types_base_url.length() > 0) {
+				url = types_base_url + type.getId();
+			}
+		}
+		return url;
+	}
+	
+	/**
+	 * returns a URL for a defined KnowledgeRepository (for instance to display in a html viewer)
+	 * 
+	 * @param kr
+	 * @param typedValue
+	 * @return
+	 */
+	public String getURL() {
+		return url;
+	}
+	
+	public HashMap<String, HashMap<String, String>> getFieldsTypesProperties() {
+		return fieldsTypesProperties;
+	}
+	
+	public String toHumanString() {
+		StringBuffer buffer = new StringBuffer();
+		buffer.append(this.getName() + " version=" + version + " (" + this.getURL() + "): " + this.getAccessType() + "\n");
+		for (AnnotationType type : getAllAnnotationTypes()) {
+			buffer.append("\t" + type.toHumanString() + "\n");
+		}
+		return buffer.toString();
+	}
+	
+	public void reload() {
+		Log.fine("Reloading KR " + name);
+		
+		clearTypes();
+		buildTypesAndValues();
+	}
+	
+	/**
+	 * returns all typed values with a specified type
+	 * 
+	 * @return
+	 * @throws Exception
+	 */
+	public List<TypedValue> getValues(AnnotationType type, int limit) throws Exception {
+		
+		TypedQuery<TypedValue> query = jpaem.createQuery("SELECT t FROM TypedValue AS t "
+				+ "WHERE t.PK.typeId LIKE '" + type.getId() + "'", TypedValue.class);
+		if (limit != -1) {
+			query.setMaxResults(limit);
+		}
+		
+		return query.getResultList();
+	}
+	
+	/**
+	 * returns all typed values with a specified type
+	 * 
+	 * @return
+	 * @throws Exception
+	 */
+	public boolean hasValues(AnnotationType type) throws Exception {
+		TypedQuery<TypedValue> query = jpaem.createQuery("SELECT t.name FROM TypedValue AS t "
+				+ "WHERE t.PK.typeId LIKE '" + type.getId() + "'", TypedValue.class);
+		query.setMaxResults(1);
+		
+		return query.getResultList().size() > 0;
+	}
+	
+	public TypedValue getValue(AnnotationType type, String id) {
+		TypedValuePK pkval = new TypedValuePK(id, type.getId());
+		return jpaem.find(TypedValue.class, pkval);
+	}
+	
+	// public TypedValue getValue(String typeId, String id) {
+	// TypedValuePK pkval = new TypedValuePK(id, typeId);
+	// return jpaem.find(TypedValue.class, pkval);
+	// }
+	
+	public boolean clearTypes() {
+		// clear type list
+		// super.clear(); // clear vector
+		
+		// clear all persisted values
+		if (jpaem != null) {
+			jpaem.getTransaction().begin();
+			Query query = jpaem.createQuery("DELETE FROM TypedValue");
+			query.executeUpdate();
+			jpaem.getTransaction().commit();
+		}
+		
+		return true;
+	}
+	
+	/**
+	 * Populate the database with typed values if they do not exist yet
+	 * 
+	 * @param kr
+	 * @param dataAccessProperties
+	 * @param fieldsTypesProperties
+	 * @return
+	 */
+	public boolean buildTypesAndValues() {
+		// build from the database (synchronizing with external repository)
+		// will probably modify or erase all types from the cache (database)
+		
+		List<AnnotationType> annotTypes = getAllAnnotationTypes();
+		if (annotTypes != null) {
+			if (annotTypes.isEmpty()) {
+				buildTypes();
+			}
+			else {
+//				Log.warning("KR Annotation Types already exist:");
+//				for (AnnotationType annotType : annotTypes) {
+//					Log.warning(NLS.bind(" - Type : {0}", annotType.getName()));
+//				}
+			}
+		} else {
+			buildTypes();
+		}
+		
+		
+		return buildValues();
+	}
+	
+	private void buildTypes() {
+		// System.out.println("KR build types ... : "+fieldsTypesProperties.size());
+		if (fieldsTypesProperties != null && fieldsTypesProperties.size() != 0) {
+			for (String type : fieldsTypesProperties.keySet()) {
+				HashMap<String, String> typeFieldsContent = fieldsTypesProperties.get(type);
+				
+				String name = typeFieldsContent.get(KnowledgeRepository.NAME);
+				String url = typeFieldsContent.get(KnowledgeRepository.TYPE_URL);
+				String size = typeFieldsContent.get(KnowledgeRepository.TYPE_SIZE);
+				String s_effect = typeFieldsContent.get(KnowledgeRepository.TYPE_EFFECT);
+				if (s_effect == null) s_effect = "SEGMENT";
+				
+				for (String typeField : typeFieldsContent.keySet()) {
+					// System.out.println("Type field : "+typeField+" value : "+typeFieldsContent.get(typeField));
+					if (typeField.equals(KnowledgeRepository.NAME)) {
+						name = typeFieldsContent.get(typeField);
+					}
+					else if (typeField.equals(KnowledgeRepository.TYPE_URL)) {
+						url = typeFieldsContent.get(typeField);
+					}
+				}
+				
+				AnnotationType annotType = addType(name, type, url, AnnotationEffect.valueOf(s_effect));
+				annotType.setSize(size);
+			}
+		}
+		else {
+			// System.out.println("KR should build type (undef) when expert mode is off !!");
+			// AnnotationType annotType = addType("undef", "undef", "", AnnotationEffect.valueOf("SEGMENT"));
+			// annotType.setSize("SMALL");
+		}
+	}
+	
+	/**
+	 * Add and create a type with a default URL
+	 * 
+	 * @param name
+	 * @param id
+	 * @return
+	 */
+	public AnnotationType addType(String name, String id) {
+		return addType(name, id, this.url + "/" + id);
+	}
+	
+	/**
+	 * Add and create a type
+	 * 
+	 * @param name
+	 * @param id
+	 * @param url
+	 * @return
+	 */
+	public AnnotationType addType(String name, String id, String url) {
+		return addType(name, id, url, AnnotationEffect.SEGMENT);
+	}
+	
+	/**
+	 * Add and create a type
+	 * 
+	 * @param name
+	 * @param id
+	 * @param url
+	 * @return
+	 */
+	public AnnotationType addType(String name, String id, String url, AnnotationEffect ae) {
+		AnnotationType annotType = new AnnotationType(this.getName(), id, name, ae);
+		annotType.setURL(url);
+		// System.out.println("KnowledgeRepository.addType () "+ annotType.toHumanString() +" ---- will be persisted");
+		jpaem.getTransaction().begin();
+		jpaem.persist(annotType);
+		jpaem.getTransaction().commit();
+		return annotType;
+	}
+	
+	public TypedValue addValue(String name, String id, String typeId) {
+		TypedValue val = new TypedValue(name, id, typeId);
+		
+		jpaem.getTransaction().begin();
+		jpaem.persist(val);
+		jpaem.getTransaction().commit();
+		return val;
+	}
+	
+	public List<AnnotationType> getAllAnnotationTypes() {
+		TypedQuery<AnnotationType> query = jpaem.createQuery("SELECT t FROM AnnotationType AS t ", AnnotationType.class);
+		return query.getResultList();
+	}
+	
+	public List<TypedValue> getAllTypedValuesForType(String idType) {
+		TypedQuery<TypedValue> query = jpaem.createQuery("SELECT t FROM TypedValue AS t WHERE t.PK.typeId LIKE '" + idType + "'", TypedValue.class);
+		return query.getResultList();
+	}
+	
+	/**
+	 * returns all typed values with a specified type and a specified value
+	 * 
+	 * @return
+	 * @throws Exception
+	 */
+	public List<TypedValue> findTypedValuesWithPrefix(AnnotationType type, String prefix) throws Exception {
+		TypedQuery<TypedValue> query = jpaem.createQuery("SELECT t FROM TypedValue AS t "
+				+ "WHERE t.PK.typeId LIKE '" + type.getId() + "'"
+				+ " AND t.name LIKE '" + prefix + "%'", TypedValue.class);
+		// System.out.println("Query for "+prefix+" has nb results = "+query.getResultList().size());
+		return query.getResultList();
+	}
+	
+	
+	public void setFieldsTypesProperties(HashMap<String, HashMap<String, String>> fields) {
+		this.fieldsTypesProperties = fields;
+	}
+	
+	public abstract boolean buildValues();
+	
+	public int getVersion() {
+		return version;
+	}
+	
+	public abstract boolean[] mustLoginToKnowledgeRepository();
+	
+	public abstract boolean checkConnection();
+	
+	public void deleteType(AnnotationType t) {
+		// Remove all values first
+		List<TypedValue> values;
+		try {
+			values = this.getValues(t);
+			for (TypedValue val : values) {
+				deleteValue(val);
+			}
+			
+			jpaem.getTransaction().begin();
+			jpaem.remove(t);
+			jpaem.getTransaction().commit();
+		}
+		catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	public void deleteValue(TypedValue v) {
+		jpaem.getTransaction().begin();
+		jpaem.remove(v);
+		jpaem.getTransaction().commit();
+	}
+	
+	public AnnotationType getType(String id) {
+		return jpaem.find(AnnotationType.class, id);
+	}
+	
+	HashMap<String, HashMap<String, String>> strings = new HashMap<String, HashMap<String, String>>();
+	
+	public String getString(String lang, String key) {
+		HashMap<String, String> values = null;
+		if (strings.containsKey(lang)) {
+			values = strings.get(lang);
+		}
+		if (values == null) { // get default lang = "en"
+			values = strings.get("en");
+		}
+		if (values == null) { // fail
+			return null;
+		}
+		return values.get(key);
+	}
+	
+	public void setStrings(HashMap<String, HashMap<String, String>> strings) {
+		this.strings = strings;
+	}
+	
+	public void saveConfiguration(File krconf) {
+		// TODO Auto-generated method stub
+		
+	}
+
+	public void close() {
+		
+		if (jpaem != null) jpaem.close();
+		if (emf != null) emf.close();
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/KnowledgeRepository.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/SQLKnowledgeRepository.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/SQLKnowledgeRepository.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/SQLKnowledgeRepository.java	(revision 3653)
@@ -0,0 +1,156 @@
+package org.txm.annotation.kr.core.repository;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+
+import javax.persistence.EntityManager;
+
+import org.eclipse.osgi.util.NLS;
+import org.txm.annotation.kr.core.DatabasePersistenceManager;
+import org.txm.sql.SQLConnection;
+import org.txm.utils.logger.Log;
+
+public class SQLKnowledgeRepository extends KnowledgeRepository {
+	
+	private static final long serialVersionUID = 3813987566658055166L;
+	
+	protected boolean isConnected = false;
+	
+	public SQLKnowledgeRepository(String name) {
+		super(name);
+	}
+	
+	@Override
+	public String getAccessType() {
+		return DatabasePersistenceManager.ACCESS_SQL;
+	}
+	
+	
+	
+	@Override
+	public boolean buildValues() {
+		return true; // values are lazily created
+	}
+	
+	
+	public TypedValue getValue(AnnotationType type, String annotationValue) {
+		// System.out.println("get value KR distant: "+type+"="+annotationValue);
+		String krname = type.getKnowledgeRepository();
+		KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(krname);
+		EntityManager em = kr.getJPAManager();
+		
+		TypedValue value = super.getValue(type, annotationValue);
+		
+		if (value != null) {
+			// System.out.println("Value found in persistence.");
+			return value;
+		}
+		
+		// Looking for the annotation value in the KR remote SQL database and building the value as a TypedValue obj.
+		HashMap<String, String> accessProperties = kr.getAccessProperties();
+		HashMap<String, HashMap<String, String>> fieldsByType = this.getFieldsTypesProperties();
+		
+		String user = null;
+		String password = null;
+		
+		if (kr.isLoginNeeded()) user = System.getProperty(LOGIN_KEY + kr.getName());
+		if (kr.isPasswordNeeded()) password = System.getProperty(PASSWORD_KEY + kr.getName());
+		
+		Connection con = null;
+		try {
+			con = SQLConnection.createConnection(accessProperties.get(SQLConnection.SQL_ADDRESS),
+					accessProperties.get(SQLConnection.SQL_DRIVER),
+					user,
+					password);
+		}
+		catch (Exception e) {
+			Log.warning(NLS.bind("Fails to get SQL connection with {0} with error: {1}.", accessProperties, e)); //$NON-NLS-1$ //$NON-NLS-2$
+			return null;
+		}
+		
+		try {
+			Statement st = con.createStatement();
+			
+			HashMap<String, String> typeFieldsContent = fieldsByType.get(type.getId());
+			
+			String typeQuery = typeFieldsContent.get(KnowledgeRepository.TYPE_SQLFIELD_QUERY);
+			String name = typeFieldsContent.get(KnowledgeRepository.TYPE_SQLFIELD_NAME);
+			String publicid = typeFieldsContent.get(KnowledgeRepository.TYPE_SQLFIELD_ID);
+			typeQuery += " WHERE " + publicid + " LIKE '" + annotationValue + "'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+			
+			ResultSet rs = st.executeQuery(typeQuery);
+			// System.out.println("SQL query : "+typeQuery); //$NON-NLS-1$
+			// System.out.println("Keys for types : " +fieldsByType.keySet().toString()); //$NON-NLS-1$
+			em.getTransaction().begin();
+			int i = 0;
+			while (rs.next()) {
+				HashMap<String, String> fields = fieldsByType.get(type.getId());
+				for (String fieldKey : fields.keySet()) {
+					if (fieldKey.equals(KnowledgeRepository.TYPE_SQLFIELD_NAME)) {
+						name = rs.getString(fields.get(KnowledgeRepository.TYPE_SQLFIELD_NAME));
+					}
+					if (fieldKey.equals(KnowledgeRepository.TYPE_SQLFIELD_ID)) {
+						publicid = rs.getString(fields.get(KnowledgeRepository.TYPE_SQLFIELD_ID));
+					}
+				}
+				value = new TypedValue(name, publicid, type.getId());
+				em.persist(value);
+				// System.out.println("Value : "+annotationValue+" ("+publicid+"/"+name+") is going to be persisted !"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+				if (i > 1) {
+					Log.warning("KR should not return more than one value !"); //$NON-NLS-1$
+				}
+				i++;
+			}
+			em.getTransaction().commit();
+			
+		}
+		catch (SQLException e) {
+			e.printStackTrace();
+		}
+		isConnected = true;
+		SQLConnection.closeConnection(con);
+		return value;
+	}
+	
+	@Override
+	public boolean[] mustLoginToKnowledgeRepository() {
+		boolean[] ret = { false, false };
+		
+		if (isConnected) return ret;
+		Log.warning("KR is not connected, checking credential requirement.");
+		if (DatabasePersistenceManager.ACCESS_SQL.equals(accessProperties.get("mode"))) {
+			ret[0] = "true".equals(accessProperties.get(SQLConnection.SQL_USER));
+			ret[1] = "true".equals(accessProperties.get(SQLConnection.SQL_PASSWORD));
+		}
+		return ret;
+	}
+	
+	@Override
+	public boolean checkConnection() {
+		Connection con = null;
+		try {
+			String user = accessProperties.get(SQLConnection.SQL_USER);
+			String password = accessProperties.get(SQLConnection.SQL_PASSWORD);
+			
+			// get user+password values stores in System.properties. these values must be set before
+			if (isLoginNeeded()) user = System.getProperty(LOGIN_KEY + getName());
+			if (isPasswordNeeded()) password = System.getProperty(PASSWORD_KEY + getName());
+			
+			con = SQLConnection.createConnection(accessProperties.get(SQLConnection.SQL_ADDRESS),
+					accessProperties.get(SQLConnection.SQL_DRIVER),
+					user,
+					password);
+			isConnected = true;
+			con.close();
+			return true;
+		}
+		catch (Exception e) {
+			Log.warning(NLS.bind("Fail to get SQL connection with the {0} properties, error={1}", accessProperties, e));
+		}
+		isConnected = false;
+		return false;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/SQLKnowledgeRepository.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/TypedValue.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/TypedValue.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/TypedValue.java	(revision 3653)
@@ -0,0 +1,55 @@
+package org.txm.annotation.kr.core.repository;
+
+import java.io.Serializable;
+
+import javax.persistence.*;
+
+/**
+ * A value defined in a Knowledge repository
+ * 
+ * @author mdecorde
+ *
+ */
+@Entity
+public class TypedValue implements Serializable {
+	
+	private static final long serialVersionUID = 7158271997193537962L;
+	
+	// primaryKey corresponds to the publicId and the type name
+	@EmbeddedId
+	private TypedValuePK PK;
+	
+	private String name;
+	
+	public TypedValue() {}
+	
+	// ex: standardName = "Municipalité de Lyon" publicid = "CoAc1349", type = "CoAc"
+	public TypedValue(String name, String publicId, String typeId) {
+		this.PK = new TypedValuePK(publicId, typeId);
+		this.name = name;
+	}
+	
+	protected TypedValuePK getPK() {
+		return PK;
+	}
+	
+	public String getId() {
+		return PK.getId();
+	}
+	
+	public String getTypeID() {
+		return PK.getType();
+	}
+	
+	public String getStandardName() {
+		return name;
+	}
+	
+	public String toString() {
+		return PK.toString() + "(" + name + ")";
+	}
+	
+	public String toHumanString() {
+		return name + "(" + PK.getId() + ")";
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/TypedValue.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/messages.properties
===================================================================

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/messages.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/AnnotationEffect.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/AnnotationEffect.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/AnnotationEffect.java	(revision 3653)
@@ -0,0 +1,24 @@
+package org.txm.annotation.kr.core.repository;
+
+/**
+ * Defines is the annotation target is a segment, a single token or another annotation
+ * 
+ * @author mdecorde
+ *
+ */
+public enum AnnotationEffect {
+	SEGMENT, // annotate a token sequence
+	TOKEN, // annotate a token position
+	ANNOTATION; // annotate an annotation
+	
+	/**
+	 * 
+	 * 
+	 * @return Effet suffix used to display the annotation type in messages
+	 */
+	public String toSuffix() {
+		if (this.equals(TOKEN)) return " (T)";
+		else if (this.equals(ANNOTATION)) return " (A)";
+		else return "";
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/AnnotationEffect.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/Messages.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/Messages.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/Messages.java	(revision 3653)
@@ -0,0 +1,12 @@
+package org.txm.annotation.kr.core.repository;
+
+import org.txm.utils.messages.Utf8NLS;
+
+public class Messages extends Utf8NLS {
+	
+	static {
+		Utf8NLS.initializeMessages(Messages.class);
+	}
+	
+	private Messages() {}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/Messages.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/KnowledgeRepositoryManager.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/KnowledgeRepositoryManager.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/KnowledgeRepositoryManager.java	(revision 3653)
@@ -0,0 +1,350 @@
+package org.txm.annotation.kr.core.repository;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+
+import org.apache.commons.io.FileUtils;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+import org.txm.Toolbox;
+import org.txm.annotation.kr.core.DatabasePersistenceManager;
+import org.txm.annotation.kr.core.KRAnnotationEngine;
+import org.txm.objects.Project;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.sql.SQLConnection;
+import org.txm.utils.logger.Log;
+import org.txm.utils.xml.DomUtils;
+import org.w3c.dom.Element;
+
+
+public class KnowledgeRepositoryManager extends DatabasePersistenceManager {
+	
+	// private static KnowledgeRepositoryManager INSTANCE = null;
+	/**
+	 * repositories cache. shared between corpus	
+	 */
+	private static HashMap<String, KnowledgeRepository> repositories = new HashMap<>();
+	
+	// public static KnowledgeRepositoryManager getInstance(){
+	// if (INSTANCE == null) {
+	// INSTANCE = new KnowledgeRepositoryManager();
+	// }
+	// return INSTANCE;
+	// }
+	
+	/**
+	 * Lazy load KR.
+	 * 
+	 * @param name
+	 * @param conf
+	 * @return
+	 */
+	@SuppressWarnings("unchecked")
+	public static KnowledgeRepository createKnowledgeRepository(String name, Element element) {
+		HashMap<String, HashMap<String, ?>> conf = KRAnnotationEngine.getKnowledgeRepositoryConfiguration(name, element);
+		return createKnowledgeRepository(name, conf);
+	}
+	
+	/**
+	 * Lazy load KR.
+	 * 
+	 * @param name
+	 * @param conf
+	 * @return
+	 * @throws BackingStoreException
+	 */
+	@SuppressWarnings("unchecked")
+	public static KnowledgeRepository createKnowledgeRepository(String name, Preferences preferences) throws BackingStoreException {
+		HashMap<String, HashMap<String, ?>> conf = KRAnnotationEngine.getKnowledgeRepositoryConfiguration(name, preferences);
+		return createKnowledgeRepository(name, conf);
+	}
+	
+	/**
+	 * Lazy load KR.
+	 * 
+	 * @param name
+	 * @param conf
+	 * @return
+	 */
+	@SuppressWarnings("unchecked")
+	public static KnowledgeRepository createKnowledgeRepository(String name, HashMap<String, HashMap<String, ?>> conf) {
+		
+		// System.out.println("Creating Knowledge repository ["+name+"] with configuration="+conf);
+		
+		HashMap<String, String> access = (HashMap<String, String>) conf.get(KRAnnotationEngine.KNOWLEDGE_ACCESS);
+		HashMap<String, HashMap<String, String>> fields = (HashMap<String, HashMap<String, String>>) conf.get(KRAnnotationEngine.KNOWLEDGE_TYPES);
+		HashMap<String, HashMap<String, String>> strings = (HashMap<String, HashMap<String, String>>) conf.get(KRAnnotationEngine.KNOWLEDGE_STRINGS);
+		String access_type = access.get("mode");
+		
+		KnowledgeRepository kr = null;
+		if (!access_type.equals(DatabasePersistenceManager.ACCESS_SQL)
+				&& !access_type.equals(DatabasePersistenceManager.ACCESS_FILE)) {
+			Log.fine("Unknowned repository type: " + access_type + ". Assuming it's a 'file' KR.");
+			access.put("mode", "file");
+			access_type = "file";
+		}
+		
+		if (access_type.equals(DatabasePersistenceManager.ACCESS_SQL)) {
+			kr = new SQLKnowledgeRepository(name);
+			kr.setCredencialsNeeded("true".equals(access.get(SQLConnection.SQL_USER)), "true".equals(access.get(SQLConnection.SQL_PASSWORD)));
+		}
+		else if (access_type.equals(DatabasePersistenceManager.ACCESS_FILE)) {
+			kr = new LocalKnowledgeRepository(name);
+		}
+		else {
+			Log.warning("Unknowned repository type: " + access_type);
+		}
+		
+		if (kr != null) {
+			// System.out.println("------- KnowledgeRepositoryManager : KR is been created "+kr.getName()+"--------");
+			kr.setAccessProperties(access);
+			kr.setStrings(strings);
+			kr.setFieldsTypesProperties(fields);
+			EntityManager em = kr.initializeEntityManager();
+			if (em == null) return null;
+			kr.buildTypesAndValues();
+		}
+		else {
+			Log.warning("Error. KR not created.");
+		}
+		
+		return kr;
+	}
+	
+	/**
+	 * get all KR stored
+	 * 
+	 * @return
+	 */
+	public static KnowledgeRepository[] getKnowledgeRepositories() {
+		return repositories.values().toArray(new KnowledgeRepository[repositories.size()]);
+	}
+	
+	/**
+	 * Creates&Registerd a simple KR with a given name
+	 * 
+	 * @param name
+	 * @return a KR. If the KR already exists returns the KR
+	 */
+	public static KnowledgeRepository createSimpleKnowledgeRepository(String name) {
+		if (getKnowledgeRepository(name) != null) {
+			return getKnowledgeRepository(name);
+		}
+		
+		HashMap<String, HashMap<String, ?>> conf = new HashMap<>();
+		HashMap<String, String> access = new HashMap<>();
+		conf.put(KRAnnotationEngine.KNOWLEDGE_ACCESS, access);
+		HashMap<String, HashMap<String, String>> fields = new HashMap<>();
+		conf.put(KRAnnotationEngine.KNOWLEDGE_TYPES, fields);
+		HashMap<String, HashMap<String, String>> strings = new HashMap<>();
+		conf.put(KRAnnotationEngine.KNOWLEDGE_STRINGS, strings);
+		
+		access.put("mode", DatabasePersistenceManager.ACCESS_FILE); //$NON-NLS-1$
+		access.put("version", "0"); //$NON-NLS-1$ //$NON-NLS-2$
+		KnowledgeRepository currentKnowledgeRepository = KnowledgeRepositoryManager.createKnowledgeRepository(name, conf);
+		KnowledgeRepositoryManager.registerKnowledgeRepository(currentKnowledgeRepository);
+		// KRAnnotationEngine.registerKnowledgeRepositoryName(corpus, corpus.getMainCorpus().getName());
+		return currentKnowledgeRepository;
+	}
+	
+	public static KnowledgeRepository getKnowledgeRepository(String name) {
+		KnowledgeRepository kr = null;
+		File krconf = new File(Toolbox.getTxmHomePath(), "repositories/" + name + "/conf.xml");
+		if (repositories.containsKey(name)) {
+			kr = repositories.get(name);
+		}
+		else {
+			if (krconf.exists()) {
+				try {
+					kr = createKnowledgeRepository(name, DomUtils.load(krconf).getDocumentElement());
+					if (kr == null) return null;
+					repositories.put(name, kr);
+				}
+				catch (Exception e) {
+					Log.warning(NLS.bind("Fail to load the {0} KR from configuration file: {1}.", krconf, e));
+					Log.printStackTrace(e);
+				}
+			}
+		}
+		return kr;
+	}
+	
+	/**
+	 * get and lazy load a stored KR (initialized and all)
+	 * 
+	 * @param name
+	 * @return
+	 * @throws BackingStoreException
+	 */
+	public static KnowledgeRepository getKnowledgeRepository(String name, MainCorpus corpus) throws BackingStoreException {
+		KnowledgeRepository kr = null;
+		
+		File krconf = new File(Toolbox.getTxmHomePath(), "repositories/" + name + "/conf.xml");
+		
+		if (repositories.containsKey(name)) { // kr already loaded
+			kr = repositories.get(name);
+		}
+		else {
+			if (krconf.exists()) {
+				try {
+					kr = createKnowledgeRepository(name, DomUtils.load(krconf).getDocumentElement());
+					if (kr != null) {
+						repositories.put(name, kr);
+					}
+					else {
+						Log.warning(NLS.bind("KR not created: {0}.", name));
+						return null;
+					}
+				}
+				catch (Exception e) {
+					Log.warning(NLS.bind("Fail to load the KR from the {0} configuration file with error {1}.", krconf, e));
+					Log.printStackTrace(e);
+				}
+			}
+		}
+		
+		// test if the corpus has a new configuration for this KR
+		// FIXME read KR configuration from Project preferences
+		Project project = corpus.getProject();
+		Preferences corpusprefkrconf = project.getPreferencesScope().getNode("KnowledgeRepository").node(name);
+		String sKRCorpusVersion = corpusprefkrconf.get("version", "0");
+		if (kr != null) {
+			int version = kr.getVersion();
+			
+			int krCorpusVersion = 0;
+			if (sKRCorpusVersion.length() > 0)
+				krCorpusVersion = Integer.parseInt(sKRCorpusVersion);
+			// System.out.println("Versions KR : "+version+" >= "+krCorpusVersion);
+			if (version >= krCorpusVersion) { // version is more recent
+				return kr;
+			}
+			else {
+				// replace the KR
+				Log.fine("REPLACE OLD KR=" + kr + " (version=" + version + ") WITH corpus KR configuration (version=" + krCorpusVersion + ")");
+				KnowledgeRepository krNew = createKnowledgeRepository(name, corpusprefkrconf);
+				
+				try { // write the new configuration file in krconf File
+					krNew.saveConfiguration(krconf);
+				}
+				catch (Exception e) {
+					Log.warning(NLS.bind("Fail to create KR from the {0} corpus configuration.", corpus));
+					Log.printStackTrace(e);
+					return kr;
+				}
+				if (krNew != null) {
+					repositories.put(name, krNew);
+					kr = krNew;
+				}
+			}
+		}
+		else {
+			// replace the KR
+			// System.out.println("CREATE KR="+kr+" WITH corpus KR configuration");
+			KnowledgeRepository krNew = createKnowledgeRepository(name, corpusprefkrconf);
+			
+			if (krNew != null) {
+				repositories.put(name, krNew);
+				kr = krNew;
+			}
+			else {
+				Log.warning(NLS.bind("Internal error: the new {0} KR is null.", name));
+				return null;
+			}
+			
+			try {
+				krNew.saveConfiguration(krconf);
+			}
+			catch (Exception e) {
+				Log.warning(NLS.bind("Fail to create KR from the {0} corpus configuration with error", corpus, e));
+				Log.printStackTrace(e);
+				return kr;
+			}
+		}
+		
+		return kr;
+	}
+	
+	public static void registerKnowledgeRepository(KnowledgeRepository kr) {
+		repositories.put(kr.getName(), kr);
+	}
+	
+	public static boolean[] mustLoginToKnowledgeRepository(String kr_name,
+			MainCorpus corpus) {
+		
+		KnowledgeRepository kr;
+		try {
+			kr = getKnowledgeRepository(kr_name, corpus);
+		}
+		catch (BackingStoreException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+			return KnowledgeRepository.FALSES;
+		}
+		if (kr == null) return KnowledgeRepository.FALSES;
+		
+		return kr.mustLoginToKnowledgeRepository();
+	}
+	
+	private static String generateTemplateURLPage() {
+		String html = "<html><head><title$title</title></head><body>$body</body></html>";
+		return html;
+	}
+	
+	public static String generateLocalURLPage(String krname, String name, String id) {
+		
+		KnowledgeRepository kr = getKnowledgeRepository(krname);
+		String path = Toolbox.getTxmHomePath() + "/repositories/" + krname;
+		// File htmlTemplateFile = new File(path+"/template.html");
+		File newHtmlFile = null;
+		String htmlString;
+		
+		if (kr != null) {
+			AnnotationType t = kr.getType(id);
+			try {
+				// htmlString = FileUtils.readFileToString(htmlTemplateFile);
+				htmlString = generateTemplateURLPage();
+				String title = "<p>Information about " + name + " (" + id + ")</p>";
+				String body = "<p>Name : " + name + "(" + id + ")</p>";
+				if (t != null) {
+					List<TypedValue> values = kr.getValues(t);
+					
+					body += "<p>Values : </p>";
+					for (TypedValue value : values) {
+						body += "<p>" + value.toHumanString() + "</p>";
+					}
+					
+				}
+				htmlString = htmlString.replace("$title", title);
+				htmlString = htmlString.replace("$body", body);
+				newHtmlFile = new File(path + "/" + id + ".html");
+				FileUtils.writeStringToFile(newHtmlFile, htmlString);
+			}
+			catch (Exception e) {
+				Log.warning(NLS.bind("Error while generating the HTML Page failed for the {0} id with error: {1}.", id, e));
+				Log.printStackTrace(e);
+			}
+			
+		}
+		else {
+			Log.warning(NLS.bind("Error: the {0} KR is null !", krname));
+		}
+		
+		return newHtmlFile.getAbsolutePath();
+	}
+	
+	public static void deleteKnowledgeRepository(KnowledgeRepository kr) {
+		// Delete all Annotation Types and Typed Values
+		List<AnnotationType> annotTypes = kr.getAllAnnotationTypes();
+		for (AnnotationType annotType : annotTypes) {
+			kr.deleteType(annotType);
+		}
+		repositories.remove(kr.getName());
+		kr.close();
+	}
+	
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/KnowledgeRepositoryManager.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/LocalKnowledgeRepository.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/LocalKnowledgeRepository.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/LocalKnowledgeRepository.java	(revision 3653)
@@ -0,0 +1,104 @@
+package org.txm.annotation.kr.core.repository;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.HashSet;
+
+import org.txm.Toolbox;
+import org.txm.annotation.kr.core.DatabasePersistenceManager;
+import org.txm.sql.SQLConnection;
+import org.txm.utils.logger.Log;
+
+public class LocalKnowledgeRepository extends KnowledgeRepository {
+	
+	private File currentDirectory;
+	
+	public LocalKnowledgeRepository(String name) {
+		super(name);
+	}
+	
+	public String getAccessType() {
+		return DatabasePersistenceManager.ACCESS_FILE;
+	}
+	
+	@Override
+	public boolean buildValues() {
+		
+		String path = accessProperties.get(SQLConnection.SQL_ADDRESS);
+		if (path == null || path.trim().length() == 0) { // no address, forge one
+			path = Toolbox.getTxmHomePath() + "/repositories/" + getName();
+			Log.finest("No address given to build values. No values created");
+			return true;
+		}
+		currentDirectory = new File(path);
+		
+		if (!currentDirectory.exists()) {
+			Log.finest("Values address given does not exists: " + currentDirectory);
+			return false;
+		}
+		try {
+			for (String type : fieldsTypesProperties.keySet()) {
+				File f = new File(currentDirectory, type);
+				BufferedReader reader = new BufferedReader(new FileReader(f));
+				String line = reader.readLine();
+				int i = 0;
+				jpaem.getTransaction().begin();
+				HashSet<String> values = new HashSet<String>();
+				while (line != null) {
+					if (line.length() > 0) {
+						String split[] = line.split("\t", 2);
+						TypedValue val = null;
+						if (split.length == 2) {
+							val = new TypedValue(split[1], split[0], type);
+						}
+						else if (split.length == 1) {
+							val = new TypedValue(split[0], split[0], type);
+						}
+						
+						if (values.contains(val.getPK().getId())) {
+							Log.warning("WARNING: duplicate '" + val.getId() + "' value ID in '" + type + "' type of '" + name + "' knowledge repository. Ignoring the value.");
+						}
+						else {
+							values.add(val.getPK().getId());
+							jpaem.persist(val);
+						}
+					}
+					line = reader.readLine();
+					i++;
+					if ((i % 10000) == 0) {
+						jpaem.flush();
+						jpaem.clear();
+					}
+				}
+				reader.close();
+				jpaem.getTransaction().commit();
+			}
+			return true;
+		}
+		catch (Exception e) {
+			Log.severe("Error while loading types from file: " + currentDirectory);
+			e.printStackTrace();
+			return false;
+		}
+	}
+	
+	static final boolean[] FALSES = { false, false };
+	
+	@Override
+	public boolean[] mustLoginToKnowledgeRepository() {
+		return FALSES;
+		
+	}
+	
+	@Override
+	public boolean checkConnection() {
+		return true; // no connection :-)
+	}
+	
+	
+	public boolean addTypeDeclaration(AnnotationType type) {
+		// What's the use ? Persistence
+		return false;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/LocalKnowledgeRepository.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/AnnotationType.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/AnnotationType.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/AnnotationType.java	(revision 3653)
@@ -0,0 +1,111 @@
+package org.txm.annotation.kr.core.repository;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.Table;
+
+/**
+ * An annotation typed defined in a named Knowledge repository
+ * 
+ * @author mdecorde
+ *
+ */
+@Entity
+public class AnnotationType implements Serializable {
+	
+	private static final long serialVersionUID = -4968506428668515803L;
+	
+	@Id
+	String id;
+	
+	String name;
+	
+	String webaccess;
+	
+	ValuesSize size = ValuesSize.SMALL;
+	
+	String krname;
+	
+	AnnotationEffect effect = AnnotationEffect.SEGMENT;
+	
+	public enum ValuesSize {
+		SMALL, AVERAGE, LARGE
+	};
+	
+	public AnnotationType() {
+		
+	}
+	
+	public AnnotationEffect setEffect(AnnotationEffect e) {
+		effect = e;
+		return e;
+	}
+	
+	public AnnotationEffect getEffect() {
+		return effect;
+	}
+	
+	public ValuesSize getSize() {
+		return size;
+	}
+	
+	public void setSize(ValuesSize size) {
+		this.size = size;
+	}
+	
+	public void setSize(String size) {
+		this.size = ValuesSize.valueOf(size);
+	}
+	
+	public AnnotationType(String krname, String id, String name) {
+		this.krname = krname;
+		this.id = id;
+		this.name = name;
+		// System.out.println("New Annotation Type : "+name+" / "+id);
+	}
+	
+	public AnnotationType(String krname, String id, String name, AnnotationEffect effect) {
+		this.krname = krname;
+		this.id = id;
+		this.name = name;
+		this.effect = effect;
+		// System.out.println("New Annotation Type : "+name+" / "+id);
+	}
+	
+	public String getId() {
+		return id;
+	}
+	
+	public String getName() {
+		return name;
+	}
+	
+	public String getKnowledgeRepository() {
+		return krname;
+	}
+	
+	public String toString() {
+		return name + "(" + effect + ")";
+	}
+	
+	public void setURL(String webaccess) {
+		this.webaccess = webaccess;
+	}
+	
+	public String getURL() {
+		return this.webaccess;
+	}
+	
+	public String toHumanString() {
+		return this.getName() + " (" + this.getId() + "): " + this.webaccess;
+	}
+	
+	public TypedValue getTypedValue(String value) {
+		KnowledgeRepository kr = KnowledgeRepositoryManager.getKnowledgeRepository(krname);
+		return kr.getValue(this, value);
+	}
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/AnnotationType.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/TypedValuePK.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/TypedValuePK.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/TypedValuePK.java	(revision 3653)
@@ -0,0 +1,49 @@
+package org.txm.annotation.kr.core.repository;
+
+import java.io.Serializable;
+
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class TypedValuePK implements Serializable {
+	
+	public static final long serialVersionUID = -2624411297196922947L;
+	
+	private String id;
+	
+	private String typeId;
+	
+	public TypedValuePK() {
+		
+	}
+	
+	public TypedValuePK(String publicId, String typeId) {
+		this.typeId = typeId;
+		this.id = publicId;
+	}
+	
+	
+	public void setType(String typeId) {
+		this.typeId = typeId;
+	}
+	
+	public void setPublicId(String publicId) {
+		this.id = publicId;
+	}
+	
+	public String getType() {
+		return typeId;
+	}
+	
+	public String getId() {
+		return this.id;
+	}
+	
+	public int hashCode() {
+		return id.hashCode() + typeId.hashCode();
+	}
+	
+	public String toString() {
+		return typeId + "=" + id;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/repository/TypedValuePK.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/PropertiesRecoder.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/PropertiesRecoder.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/PropertiesRecoder.java	(revision 3653)
@@ -0,0 +1,115 @@
+package org.txm.annotation.kr.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+
+import javax.xml.stream.XMLStreamException;
+
+import org.txm.importer.StaxIdentityParser;
+
+public class PropertiesRecoder extends StaxIdentityParser {
+	
+	public PropertiesRecoder(File xmlFile, HashSet<String> fromProperties, HashSet<String> toProperties) throws IOException, XMLStreamException {
+		super(xmlFile);
+	}
+	
+	boolean startW = false, startAna = false;
+	
+	ArrayList<String[]> anaValues = new ArrayList<String[]>();
+	
+	String[] currentAnaValues = { "", "", "" };
+	
+	StringBuilder anaValue = new StringBuilder();
+	
+	String EMPTY = "";
+	
+	@Override
+	public void processStartElement() throws XMLStreamException, IOException {
+		if (localname.equals("w")) {
+			startW = true;
+			anaValues.clear();
+			super.processStartElement();
+		}
+		else if (localname.equals("ana")) {
+			if (startW) {
+				startAna = true;
+				anaValue.setLength(0);
+				currentAnaValues[0] = EMPTY;
+				currentAnaValues[1] = EMPTY;
+				currentAnaValues[2] = EMPTY;
+				for (int i = 0; i < parser.getAttributeCount(); i++) {
+					if (parser.getAttributeLocalName(i).equals("resp")) {
+						currentAnaValues[0] = parser.getAttributeValue(i);
+					}
+					else if (parser.getAttributeLocalName(i).equals("type")) {
+						currentAnaValues[1] = parser.getAttributeValue(i);
+					}
+				}
+			}
+		}
+		else {
+			super.processStartElement();
+		}
+	}
+	
+	@Override
+	public void processCharacters() throws XMLStreamException {
+		if (startAna) {
+			anaValue.append(parser.getText());
+		}
+		else {
+			super.processCharacters();
+		}
+	};
+	
+	@Override
+	public void processEndElement() throws XMLStreamException {
+		if (localname.equals("w")) {
+			startW = false;
+			
+			for (String[] values : anaValues) {
+				try {
+					writer.writeStartElement("txm:ana");
+					writer.writeAttribute("resp", values[0]);
+					writer.writeAttribute("type", values[1]);
+					writer.writeCharacters(values[2]);
+					writer.writeEndElement();
+				}
+				catch (XMLStreamException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+			}
+			
+			super.processEndElement();
+		}
+		else if (localname.equals("ana")) {
+			if (startW) {
+				currentAnaValues[2] = anaValue.toString();
+				anaValues.add(currentAnaValues);
+				startAna = false;
+			}
+		}
+		else {
+			super.processEndElement();
+		}
+	}
+	
+	public static void main(String args[]) {
+		try {
+			File xmlFile = new File("/home/mdecorde/TEMP/test.xml");
+			File outfile = new File("/home/mdecorde/TEMP/test-o.xml");
+			HashSet<String> fromProperties = new HashSet<String>();
+			HashSet<String> toProperties = new HashSet<String>();
+			
+			PropertiesRecoder recoder = new PropertiesRecoder(xmlFile, fromProperties, toProperties);
+			System.out.println("Result: " + recoder.process(outfile));
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/PropertiesRecoder.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/CreateAnnotation.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/CreateAnnotation.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/CreateAnnotation.java	(revision 3653)
@@ -0,0 +1,30 @@
+package org.txm.annotation.kr.core.temporary;
+
+import static org.junit.Assert.*;
+
+import java.util.HashMap;
+
+import org.junit.Test;
+import org.txm.Toolbox;
+import org.txm.annotation.kr.core.storage.temporary.TemporaryAnnotationManager;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.clientExceptions.InvalidCqpIdException;
+import org.txm.searchengine.cqp.corpus.CorpusManager;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+
+public class CreateAnnotation {
+	
+	@Test
+	public void test() throws CqiClientException, InvalidCqpIdException {
+		if (!Toolbox.isInitialized()) fail("Toolbox not initialized.");
+		MainCorpus corpus = CorpusManager.getCorpusManager().getCorpus("VOEUX");
+		if (corpus == null) fail("Corpus Voeux not loaded.");
+		
+		HashMap<String, Object> properties = TemporaryAnnotationManager.getInitialisationProperties(this.getClass(), corpus);
+		properties.put("eclipselink.persistencexml", System.getProperty("user.home") + "/workspace442/org.txm.core/META-INF/persistence.xml");
+		
+		TemporaryAnnotationManager tam = new TemporaryAnnotationManager(corpus, properties);
+		System.out.println(tam);
+	}
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/CreateAnnotation.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/AllTests.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/AllTests.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/AllTests.java	(revision 3653)
@@ -0,0 +1,13 @@
+package org.txm.annotation.kr.core.temporary;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+import org.txm.StartToolbox;
+
+@RunWith(Suite.class)
+@SuiteClasses({ StartToolbox.class, CreateAnnotation.class, DeleteAnnotation.class,
+		UpdateAnnotation.class })
+public class AllTests {
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/AllTests.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/DeleteAnnotation.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/DeleteAnnotation.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/DeleteAnnotation.java	(revision 3653)
@@ -0,0 +1,14 @@
+package org.txm.annotation.kr.core.temporary;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class DeleteAnnotation {
+	
+	@Test
+	public void test() {
+		fail("Not yet implemented");
+	}
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/DeleteAnnotation.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/UpdateAnnotation.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/UpdateAnnotation.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/UpdateAnnotation.java	(revision 3653)
@@ -0,0 +1,14 @@
+package org.txm.annotation.kr.core.temporary;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class UpdateAnnotation {
+	
+	@Test
+	public void test() {
+		fail("Not yet implemented");
+	}
+	
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/temporary/UpdateAnnotation.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationComparator.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationComparator.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationComparator.java	(revision 3653)
@@ -0,0 +1,50 @@
+package org.txm.annotation.kr.core;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Comparator;
+import java.util.StringTokenizer;
+
+public class AnnotationComparator implements Comparator<Annotation> {
+	
+	public int compare(Annotation a1, Annotation a2) {
+		// comparer e1 et e2
+		
+		DateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
+		// System.out.println("Date 1 : "+a1.getDate() + " => "+dateformat.format(a1.getDate()));
+		// System.out.println("Date 2 : "+a2.getDate() + " => "+dateformat.format(a2.getDate()));
+		StringTokenizer tokenizer1 = new StringTokenizer(dateformat.format(a1.getDate()), "-");
+		StringTokenizer tokenizer2 = new StringTokenizer(dateformat.format(a2.getDate()), "-");
+		
+		for (int i = 0; i < 2 && tokenizer1.hasMoreTokens() && tokenizer2.hasMoreTokens(); ++i) {
+			String token1 = tokenizer1.nextToken();
+			String token2 = tokenizer2.nextToken();
+			int valint1 = new Integer(token1).intValue();
+			int valint2 = new Integer(token2).intValue();
+			// System.out.println(valint1+" | "+valint2);
+			if (valint1 < valint2) {
+				return -1;
+			}
+			else {
+				if (valint1 > valint2) {
+					return 1;
+				}
+				else {
+					// System.out.println("idem ["+i+"]");
+				}
+				
+			}
+		}
+		
+		return 0;
+		
+	}
+	
+	public static void main(String[] args) {
+		AnnotationComparator comp = new AnnotationComparator();
+		Annotation a1 = new Annotation("truc", "bidule", 3, 10);
+		Annotation a2 = new Annotation("truc", "bidule", 6, 8);
+		int ret = comp.compare(a1, a2);
+		System.out.println("Le retour est : " + ret);
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationComparator.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/DatabasePersistenceManager.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/DatabasePersistenceManager.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/DatabasePersistenceManager.java	(revision 3653)
@@ -0,0 +1,56 @@
+package org.txm.annotation.kr.core;
+
+import java.util.HashMap;
+
+import javax.persistence.EntityManager;
+
+public class DatabasePersistenceManager {
+	
+	// Object can be Corpus or KnowledgeRepository
+	protected HashMap<Object, EntityManager> managers;
+	
+	public static final String PERSISTENCE_UNIT_NAME = "HSQLKRPERSISTENCE";
+	
+	public static String ACCESS_SQL = "sql";
+	
+	public static String ACCESS_FILE = "file";
+	
+	public static String ACCESS_SPARQL = "sparql";
+	
+	/**
+	 * Instantiates a new database manager.
+	 */
+	public DatabasePersistenceManager() {
+		managers = new HashMap<Object, EntityManager>();
+	}
+	
+	/**
+	 * The Object can be a Corpus or a KnowledgeRepository
+	 * 
+	 * @param obj
+	 * @return
+	 */
+	public EntityManager getJPAEntityManager(Object obj) {
+		if (managers.containsKey(obj)) {
+			return managers.get(obj);
+		}
+		return null;
+	}
+	
+	public void closeManager(Object key) {
+		if (!managers.keySet().contains(key)) return;
+		
+		managers.get(key).close();
+		managers.remove(key);
+	}
+	
+	public void closeAllManagers() {
+		for (Object key : managers.keySet()) {
+			EntityManager m = managers.get(key);
+			m.flush();
+			m.createNativeQuery("SHUTDOWN;");
+			m.close();
+		}
+		managers.clear();
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/DatabasePersistenceManager.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationPK.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationPK.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationPK.java	(revision 3653)
@@ -0,0 +1,67 @@
+package org.txm.annotation.kr.core;
+
+import java.io.Serializable;
+
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class AnnotationPK implements Serializable {
+	
+	private static final long serialVersionUID = -2360693333015275209L;
+	
+	// corresponding to the start and end positions (in the corpus)
+	private int startpos;
+	
+	private int endpos;
+	
+	private String refType;
+	
+	public AnnotationPK() {}
+	
+	public AnnotationPK(int start, int end, String refType) {
+		this.startpos = start;
+		this.endpos = end;
+		this.refType = refType;
+	}
+	
+	public void setRefType(String refType) {
+		this.refType = refType;
+	}
+	
+	public void setStartPosition(int start) {
+		this.startpos = start;
+	}
+	
+	public void setEndPosition(int end) {
+		this.endpos = end;
+	}
+	
+	public String getRefType() {
+		return refType;
+	}
+	
+	public int getStartPosition() {
+		return startpos;
+	}
+	
+	public int getEndPosition() {
+		return endpos;
+	}
+	
+	public boolean equals(Object obj) {
+		if (obj == null) return false;
+		if (obj == this) return true;
+		if (!(obj instanceof AnnotationPK)) return false;
+		
+		AnnotationPK other = (AnnotationPK) obj;
+		return startpos == other.startpos && endpos == other.endpos && refType.equals(other.refType);
+	}
+	
+	public int hashCode() {
+		return refType.hashCode() + startpos + endpos;
+	}
+	
+	public String toString() {
+		return getRefType() + "[" + getStartPosition() + "-" + getEndPosition() + "]";
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationPK.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/conversion/XMLTXMFileRuledConversion.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/conversion/XMLTXMFileRuledConversion.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/conversion/XMLTXMFileRuledConversion.java	(revision 3653)
@@ -0,0 +1,332 @@
+package org.txm.annotation.kr.core.conversion;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.regex.Pattern;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.txm.importer.StaxIdentityParser;
+import org.txm.utils.logger.Log;
+
+public class XMLTXMFileRuledConversion extends StaxIdentityParser {
+	
+	public boolean debug = false;
+	
+	protected LinkedHashMap<Pattern, String> rules = new LinkedHashMap<>();
+	
+	protected String elementName = null;
+	
+	boolean fixingElement = false; // true when the current element needs to be fixed
+	
+	protected String oldType;
+	
+	protected String newType;
+	
+	public static final String DELETE = "supprimer";
+	
+	public static final String COPY = "copier";
+	
+	public static final String ABANDON = "abandon";
+	
+	HashSet<String> noMatchValues = new HashSet<>();
+	
+	/**
+	 * 
+	 * @param infile the file to read
+	 * @param rules the conversion rules
+	 * @param elementPath if null, the conversion happens
+	 * @param oldType word type or element attribute to read
+	 * @param newType word type or element attribute to write
+	 * @param mode XMLTXMFileRuledConversion.DELETE or XMLTXMFileRuledConversion.COPY or XMLTXMFileRuledConversion.ABANDON
+	 * @throws IOException
+	 * @throws XMLStreamException
+	 */
+	public XMLTXMFileRuledConversion(File infile, LinkedHashMap<Pattern, String> rules, String elementPath, String oldType, String newType, String mode) throws IOException, XMLStreamException {
+		super(infile);
+		this.rules = rules;
+		this.oldType = oldType;
+		this.newType = newType;
+		
+		this.mode = mode;
+		
+		if (elementPath != null && elementPath.length() > 0) {
+			this.elementName = elementPath;
+		}
+		
+		if (elementPath == null) { // where fixing txm:words
+			if (!this.newType.startsWith("#")) this.newType = "#" + this.newType;
+			if (!this.oldType.startsWith("#")) this.oldType = "#" + this.oldType;
+		}
+	}
+	
+	boolean inW = false, inAna = false, inForm;
+	
+	LinkedHashMap<String, String> anaValues = new LinkedHashMap<>();
+	
+	LinkedHashMap<String, String> anaResps = new LinkedHashMap<>();
+	
+	String typeName = null;
+	
+	String respName = null;
+	
+	String formValue, typeValue = null;
+	
+	private Object mode;
+	
+	public static class Converter {
+		
+		public Converter() {
+			
+		}
+		
+		public String getValue(XMLStreamReader parser, String localname, String attribute, String value) {
+			return value;
+		}
+	}
+	
+	private Converter converter = null;
+	
+	@Override
+	protected void writeAttributes() throws XMLStreamException {
+		if (fixingElement) {
+			String newValue = null;
+			for (int i = 0; i < parser.getAttributeCount(); i++) {
+				String att = parser.getAttributeLocalName(i);
+				String value = parser.getAttributeValue(i);
+				if (oldType != null && oldType.equals(att)) {
+					if (converter != null) {
+						if (debug) Log.finer("CALL CONVERTER with attribute "+att);
+						newValue = converter.getValue(parser, localname, att, value);
+					}
+					else {
+						newValue = getValueIfMatch(value);
+					}
+				}
+				if (!newType.equals(att)) { // don't write the newType, it will be done at the end
+					writeAttribute(parser.getAttributePrefix(i), att, value);
+				}
+			}
+			
+			if (oldType == null && converter != null) {
+				if (debug) Log.finer("CALL CONVERTER with no attribute set");
+				newValue = converter.getValue(parser, localname, null, null);
+			}
+			
+			if (newValue != null) {
+				if (debug) Log.finer("WRITE NEWTYPE: " + newType + "=" + newValue);
+				writeAttribute(null, newType, newValue);
+			}
+		}
+		else {
+			super.writeAttributes();
+		}
+	}
+	
+	@Override
+	public void processStartElement() throws XMLStreamException, IOException {
+		
+		
+		if (elementName != null) {
+			if (this.localname.equals(elementName)) {
+				fixingElement = true;
+			}
+			
+			super.processStartElement();
+			fixingElement = false;
+		}
+		else {
+			
+			if (!inW) super.processStartElement(); // don't write W content
+			
+			if (localname.equals("w")) {
+				inW = true;
+				anaValues.clear();
+				anaResps.clear();
+				
+				// initialize the new type to a empty value in case there is transformation rule
+				anaValues.put(newType, "");
+				anaResps.put(newType, "#txm_recode");
+			}
+			else if (localname.equals("ana")) {
+				inAna = true;
+				typeName = parser.getAttributeValue(null, "type");
+				respName = parser.getAttributeValue(null, "resp");
+				anaResps.put(typeName, respName);
+				// if (typeName != null) typeName = typeName.substring(1); // remove #
+				typeValue = "";
+			}
+			else if (localname.equals("form")) {
+				inForm = true;
+				formValue = "";
+			}
+		}
+	}
+	
+	@Override
+	public void processCharacters() throws XMLStreamException {
+		if (elementName != null) {
+			super.processCharacters();
+		}
+		else {
+			if (inW && inAna) typeValue += parser.getText();
+			else if (inW && inForm) formValue += parser.getText();
+			else super.processCharacters();
+		}
+	}
+	
+	@Override
+	public void processEndElement() throws XMLStreamException {
+		
+		if (elementName != null) {
+			super.processEndElement();
+		}
+		else {
+			
+			if (localname.equals("w")) {
+				inW = false;
+				
+				// write W content
+				try {
+					// get the value to test
+					String value = null;
+					if (oldType.equals("word")) {
+						value = formValue;
+					}
+					else {
+						value = anaValues.get(oldType);
+					}
+					
+					if (newType.equals("word")) { // update form property
+						updateFormValueIfMatch(value);
+					}
+					else { // update a ana property
+						if (value != null) {
+							updateAnaValuesIfMatch(value);
+						}
+					}
+					
+					// write the word element
+					writer.writeStartElement("txm:form");
+					writer.writeCharacters(formValue);
+					writer.writeEndElement();
+					
+					for (String k : anaValues.keySet()) {
+						String resp = anaResps.get(k);
+						if (resp == null) resp = "#txm_recode";
+						
+						writer.writeStartElement("txm:ana");
+						writer.writeAttribute("resp", resp);
+						writer.writeAttribute("type", k);
+						writer.writeCharacters(anaValues.get(k));
+						writer.writeEndElement();
+					}
+				}
+				catch (XMLStreamException e) {
+					e.printStackTrace();
+				}
+			}
+			else if (localname.equals("ana")) {
+				anaValues.put(typeName, typeValue);
+				inAna = false;
+			}
+			else if (localname.equals("form")) {
+				inForm = false;
+			}
+			
+			if (!inW) super.processEndElement(); // don't write W content
+		}
+	}
+	
+	protected String getValueIfMatch(String value) {
+		for (Pattern rule : rules.keySet()) {
+			if (rule.matcher(value).matches()) {
+				return rules.get(rule); // ok stop
+			}
+		}
+		
+		return value;
+	}
+	
+	protected void updateFormValueIfMatch(String value) {
+		
+		if (converter != null) {
+			String v = converter.getValue(parser, localname, null, value);
+			if (v != null) {
+				formValue = v;
+				return; // ok stop
+			}
+		}
+		else {
+			for (Pattern rule : rules.keySet()) {
+				if (rule.matcher(value).matches()) {
+					formValue = rules.get(rule);
+					return; // ok stop
+				}
+			}
+		}
+		
+		
+		noMatchValues.add(value);
+	}
+	
+	protected void updateAnaValuesIfMatch(String value) {
+		
+		if (converter != null) {
+			String v = converter.getValue(parser, localname, null, value);
+			if (v != null) {
+				anaValues.put(newType, v); // do a replace if newType == oldType :-)
+				anaResps.put(newType, "#txm_recode");
+				return; // ok stop
+			}
+		}
+		else {
+			
+			for (Pattern rule : rules.keySet()) {
+				if (rule.matcher(value).matches()) {
+					value = rules.get(rule);
+					anaValues.put(newType, value); // do a replace if newType == oldType :-)
+					anaResps.put(newType, "#txm_recode");
+					return;
+				}
+			}
+		}
+		if (DELETE.equals(mode)) anaValues.put(newType, ""); // do a replace if newType == oldType :-)
+		else if (ABANDON.equals(mode)) anaValues.put(newType, "ERROR(" + value + ")"); // do a replace if newType == oldType :-)
+		
+		noMatchValues.add(value);
+	}
+	
+	public HashSet<String> getNoMatchValues() {
+		return noMatchValues;
+	}
+	
+	public static void main(String args[]) {
+		try {
+			File xmlFile = new File("/home/mdecorde/xml/recode/test.xml");
+			File tmpFile = new File("/home/mdecorde/xml/recode/test-o.xml");
+			String oldType = "myattr";
+			String newType = "myattr";
+			LinkedHashMap<Pattern, String> rules = new LinkedHashMap<>();
+			rules.put(Pattern.compile(".+"), "NEWW");
+			rules.put(Pattern.compile("x.+"), "XWORD");
+			rules.put(Pattern.compile("y"), "YWORD");
+			rules.put(Pattern.compile("y.*"), "YMULTIWORD");
+			XMLTXMFileRuledConversion converter = new XMLTXMFileRuledConversion(xmlFile, rules, "w", oldType, newType, ABANDON);
+			converter.converter = new Converter() {
+				
+				@Override
+				public String getValue(XMLStreamReader parser, String localname, String attribute, String value) {
+					return "NEW" + value;
+				}
+			};
+			System.out.println(converter.process(tmpFile));
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/conversion/XMLTXMFileRuledConversion.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/conversion/CorpusRuledConvertion.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/conversion/CorpusRuledConvertion.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/conversion/CorpusRuledConvertion.java	(revision 3653)
@@ -0,0 +1,125 @@
+package org.txm.annotation.kr.core.conversion;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.regex.Pattern;
+
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.commons.lang.StringUtils;
+import org.eclipse.osgi.util.NLS;
+import org.txm.Toolbox;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.utils.ConsoleProgressBar;
+import org.txm.utils.io.IOUtils;
+import org.txm.utils.logger.Log;
+
+public class CorpusRuledConvertion {
+	
+	LinkedHashMap<Pattern, String> rules = new LinkedHashMap<>();
+	
+	private String oldType;
+	
+	private String newType;
+	
+	public CorpusRuledConvertion(File conversionFile, String oldType, String newType) throws IOException {
+		this.oldType = oldType;
+		this.newType = newType;
+		
+		BufferedReader reader = IOUtils.getReader(conversionFile);
+		String line = reader.readLine();
+		while (line != null) {
+			int idx = line.indexOf("\t");
+			if (idx > 0) {
+				String k = line.substring(0, idx);
+				String v = line.substring(idx + 1);
+				rules.put(Pattern.compile(k), v);
+			}
+			line = reader.readLine();
+		}
+		
+		Log.info(NLS.bind("Conversion rules: {0}.", rules));
+	}
+	
+	public CorpusRuledConvertion(LinkedHashMap<Pattern, String> rules,
+			String oldType, String newType) {
+		this.oldType = oldType;
+		this.newType = newType;
+		
+		this.rules = rules;
+	}
+	
+	public boolean process(MainCorpus corpus) throws XMLStreamException, IOException {
+		File binaryCorpusDirectory = corpus.getProjectDirectory();
+		File txmDirectory = new File(binaryCorpusDirectory, "txm");
+		if (!txmDirectory.exists()) {
+			Log.warning(NLS.bind("The 'txm' directory was not found in {0}.", binaryCorpusDirectory.getAbsolutePath()));
+			return false;
+		}
+		File txmCorpusDirectory = new File(txmDirectory, corpus.getID());
+		if (!txmCorpusDirectory.exists()) {
+			Log.warning(NLS.bind("The ''{0}'' corpus directory was not found in {1}.", corpus.getName(), txmDirectory.getAbsolutePath()));
+			return false;
+		}
+		File[] files = txmCorpusDirectory.listFiles(IOUtils.HIDDENFILE_FILTER);
+		if (files == null || files.length == 0) {
+			Log.warning(NLS.bind("No file found in the {0} directory.", txmCorpusDirectory));
+			return false;
+		}
+		ConsoleProgressBar cpb = new ConsoleProgressBar(files.length);
+		for (File xmlFile : files) {
+			cpb.tick();
+			if (xmlFile.isDirectory()) continue;
+			if (xmlFile.isHidden()) continue;
+			if (!xmlFile.getName().endsWith(".xml")) continue;
+			
+			File tmpFile = new File(xmlFile.getParentFile(), "tmp_" + xmlFile.getName());
+			XMLTXMFileRuledConversion converter = new XMLTXMFileRuledConversion(xmlFile, rules, null, oldType, newType, XMLTXMFileRuledConversion.ABANDON);
+			if (converter.process(tmpFile)) {
+				xmlFile.delete();
+				// try {
+				// FileCopy.copy(tmpFile, new File("/tmp/"+tmpFile.getName()));
+				// } catch (IOException e) {
+				// // TODO Auto-generated catch block
+				// e.printStackTrace();
+				// }
+				
+				HashSet<String> errors = converter.getNoMatchValues();
+				if (errors.size() > 0) {
+					Log.warning("Some values did not match rule: ");
+					int i = 0;
+					for (String error : errors) {
+						Log.warning("\t" + error);
+						if (i >= 10) break;
+					}
+					if (errors.size() > 10) {
+						try {
+							File errorFile = new File(Toolbox.getTxmHomePath(), "errors.txt");
+							IOUtils.write(errorFile, StringUtils.join(errors, "\t"));
+							Log.warning(NLS.bind("More errors, see the {0} errors file.", errorFile.getAbsolutePath()));
+						}
+						catch (Exception e) {
+							e.printStackTrace();
+						}
+					}
+					return false;
+				}
+				
+				tmpFile.renameTo(xmlFile);
+				if (tmpFile.exists()) {
+					Log.warning(NLS.bind("Could not replace original file with the {0} result file with {1}.", xmlFile, tmpFile));
+					return false;
+				}
+			}
+			else {
+				Log.warning(NLS.bind("Fail to process the {0} XML file.", xmlFile));
+				return false;
+			}
+		}
+		cpb.done();
+		return true;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/conversion/CorpusRuledConvertion.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationManager.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationManager.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationManager.java	(revision 3653)
@@ -0,0 +1,618 @@
+package org.txm.annotation.kr.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.service.prefs.BackingStoreException;
+import org.txm.annotation.kr.core.messages.KRAnnotationCoreMessages;
+import org.txm.annotation.kr.core.repository.AnnotationEffect;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.KnowledgeRepository;
+import org.txm.annotation.kr.core.repository.TypedValue;
+import org.txm.annotation.kr.core.storage.temporary.TemporaryAnnotationManager;
+import org.txm.core.preferences.TBXPreferences;
+import org.txm.core.preferences.TXMPreferences;
+import org.txm.objects.Match;
+import org.txm.objects.Match2P;
+import org.txm.searchengine.cqp.AbstractCqiClient;
+import org.txm.searchengine.cqp.CQPSearchEngine;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.searchengine.cqp.corpus.QueryResult;
+import org.txm.searchengine.cqp.corpus.query.CQLQuery;
+import org.txm.searchengine.cqp.serverException.CqiServerError;
+import org.txm.utils.ConsoleProgressBar;
+import org.txm.utils.CsvReader;
+import org.txm.utils.io.IOUtils;
+import org.txm.utils.logger.Log;
+
+/**
+ * Manage annotations and is able to return annotation saved in JPA
+ * 
+ * @author mdecorde
+ *
+ */
+public class AnnotationManager {
+	
+	MainCorpus corpus;
+	
+	TemporaryAnnotationManager tempManager;
+	
+	CQPAnnotationManager cqpManager;
+	
+	boolean dirty = false;
+	
+	public AnnotationManager(MainCorpus mainCorpus) {
+		this.corpus = mainCorpus;
+	}
+	
+	public TemporaryAnnotationManager getTemporaryManager() {
+		return tempManager;
+	}
+	
+	public CQPAnnotationManager getCQPManager() {
+		return cqpManager;
+	}
+	
+	public boolean saveAnnotations(IProgressMonitor monitor) throws Exception {
+		
+		List<Annotation> annots = tempManager.getAnnotations();
+		if (annots.isEmpty()) {
+			Log.info("No annotation to save. Aborting.");
+			dirty = false;
+			return true;
+		}
+		
+		if (monitor != null) {
+			monitor.beginTask(KRAnnotationCoreMessages.savingAnnotations, annots.size());
+			monitor.setTaskName("Writing annotations in XML-TXM files");
+		}
+		
+		AnnotationWriter writer = new AnnotationWriter(corpus);
+		if (writer.writeAnnotations(annots, monitor)) {
+			Log.info(KRAnnotationCoreMessages.annotationSuccesfullyWritten);
+			tempManager.deleteAnnotations();
+			dirty = false;
+			return true;
+		}
+		return false;
+	}
+	
+	public boolean exportAnnotationsToSyMoGIH(File resultZipFile) throws Exception {
+		AnnotationWriter writer = new AnnotationWriter(corpus);
+		
+		if (writer.writeAnnotationsInStandoff(resultZipFile)) {
+			Log.info(NLS.bind(KRAnnotationCoreMessages.annotationSuccesfullyWrittenIntheP0File, resultZipFile));
+			return true;
+		}
+		return false;
+	}
+	
+	// TODO: not ended?
+	/**
+	 * Deletes the annotations stored in the temporary annotation manager
+	 * 
+	 * @param type
+	 * @param job
+	 * @return
+	 * @throws Exception
+	 */
+	public boolean deleteAnnotations(AnnotationType type, IProgressMonitor job) throws Exception {
+		List<Annotation> temporaryAnnotations = null;
+		List<Annotation> cqpAnnotations = null;
+		try {
+			temporaryAnnotations = tempManager.getAnnotations(type);
+			tempManager.getEntityManager().getTransaction().begin();
+			for (Annotation a : temporaryAnnotations) {
+				if (job != null && job.isCanceled()) {
+					Log.info("Delete annotation canceled.");
+					return false;
+				}
+				tempManager.deleteAnnotation(type, a.getStart(), a.getEnd());
+			}
+			tempManager.getEntityManager().getTransaction().commit();
+			
+			cqpAnnotations = cqpManager.getAnnotations(type);
+			tempManager.getEntityManager().getTransaction().begin();
+			for (Annotation a : cqpAnnotations) {
+				if (job != null && job.isCanceled()) {
+					Log.info("Delete annotation canceled.");
+					return false;
+				}
+				String value = cqpManager.getCQPAnnotationValue(a.getStart(), a.getEnd(), type);
+				if (value != null) {
+					tempManager.createAnnotationNoCommit(type, new TypedValue("#del", "#del", type.getId()), a.getStart(), a.getEnd());
+				}
+				else {
+					tempManager.deleteAnnotationNoCommit(type, a.getStart(), a.getEnd());
+				}
+			}
+			dirty = true;
+			tempManager.getEntityManager().getTransaction().commit();
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+			return false;
+		}
+		return true;
+	}
+	
+	public boolean deleteAnnotations(AnnotationType type, List<? extends Match> matches, IProgressMonitor job) throws Exception {
+		try {
+			tempManager.getEntityManager().getTransaction().begin();
+			for (Match match : matches) {
+				
+				int start, end;
+				if (match.getTarget() >= 0) {
+					start = end = match.getTarget();
+				}
+				else {
+					start = match.getStart();
+					end = match.getEnd();
+					if (type.getEffect().equals(AnnotationEffect.TOKEN)) {
+						end = start;
+					}
+				}
+				
+				if (job != null && job.isCanceled()) {
+					Log.info("Delete annotation canceled.");
+					return false;
+				}
+				
+				String value = cqpManager.getCQPAnnotationValue(start, end, type);
+				
+				if (value != null) {
+					tempManager.createAnnotationNoCommit(type, new TypedValue("#del", "#del", type.getId()), start, end);
+				}
+				else {
+					tempManager.deleteAnnotationNoCommit(type, start, end);
+				}
+			}
+			dirty = true;
+			tempManager.getEntityManager().getTransaction().commit();
+		}
+		catch (Exception e) {
+			Log.printStackTrace(e);
+			return false;
+		}
+		return true;
+	}
+	
+	/**
+	 * Returns the annotation saved in the temporary database and in the CQP corpus indexes
+	 * 
+	 * CQP Annotations must be shadowed by temporary annotations of the same type and positions
+	 */
+	public List<Annotation> getAnnotationsForMatches(AnnotationType type, List<Match> matches, boolean overlap) {
+		List<Annotation> temporaryAnnotations = null;
+		List<Annotation> resultAnnotations = new ArrayList<>();
+		try {
+			temporaryAnnotations = tempManager.getAnnotations(type, matches, null, false, overlap);
+			temporaryAnnotations = tempManager.getAnnotationsForMatches(matches, temporaryAnnotations, overlap);
+			
+			List<? extends Annotation> cqpAnnotations = cqpManager.getAnnotationsForMatches(matches, type, overlap);
+			
+			// System.out.println("Temporary annotations: "+temporaryAnnotations);
+			// System.out.println("CQP annotations: "+cqpAnnotations);
+			if (cqpAnnotations.size() != matches.size() || temporaryAnnotations.size() != matches.size()) {
+				Log.info("ERROR in getAnnotationsForMatches methods! ");
+				return new ArrayList<>(matches.size());
+			}
+			// merge the 2 results
+			for (int i = 0; i < matches.size(); i++) {
+				if (cqpAnnotations.get(i) == null && temporaryAnnotations.get(i) == null) {
+					resultAnnotations.add(null);
+				}
+				else if (temporaryAnnotations.get(i) != null) {
+					resultAnnotations.add(temporaryAnnotations.get(i));
+				}
+				else if (cqpAnnotations.get(i) != null) {
+					resultAnnotations.add(cqpAnnotations.get(i));
+				}
+				else {
+					resultAnnotations.add(null);
+				}
+			}
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+			return new ArrayList<>(matches.size());
+		}
+		return resultAnnotations;
+	}
+	
+	public void clearInstance() {
+		try {
+			tempManager.close();
+		}
+		catch (Exception e) {
+			Log.warning(NLS.bind("Fail to clear AnnotationManager instance with error: {0}", e));
+			Log.printStackTrace(e);
+		}
+	}
+	
+	public void checkData() {
+		try {
+			tempManager.checkData();
+		}
+		catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	public boolean hasChanges() {
+		return tempManager.hasChanges();
+	}
+	
+	/**
+	 * 
+	 * @param annotSelectedType not null
+	 * @param annotSelectedTypedValue not null
+	 * @param matches not null
+	 * @param job may be null
+	 * @return
+	 */
+	public HashMap<Match, List<Annotation>> createAnnotations(AnnotationType annotSelectedType,
+			TypedValue annotSelectedTypedValue, List<? extends Match> matches, IProgressMonitor job) {
+		
+		HashMap<Match, List<Annotation>> allAnnotationsThatCollides = new HashMap<>();
+		tempManager.getEntityManager().getTransaction().begin(); // warning
+		int nCreation = 0;
+		ConsoleProgressBar cpb = new ConsoleProgressBar(matches.size());
+		long t = System.currentTimeMillis();
+		for (Match match : matches) {
+			cpb.tick();
+			allAnnotationsThatCollides.put(match, new ArrayList<Annotation>());
+			
+			int start, end;
+			if (match.getTarget() >= 0) {
+				start = end = match.getTarget();
+			}
+			else {
+				start = match.getStart();
+				end = match.getEnd();
+			}
+			
+			if (job != null && job.isCanceled()) { // check if user canceled the job
+				Log.info("Affect annotation canceled.");
+				return null;
+			}
+			
+			try {
+				List<Annotation> cqpAnnotations = null;
+				if (annotSelectedType.getEffect().equals(AnnotationEffect.SEGMENT)) {
+					cqpAnnotations = cqpManager.getAnnotations(null, match, null, true); // get all annotations
+					// remove A)the wrapping annotations and B) the annotation with same type and same positions
+					for (int i = 0; i < cqpAnnotations.size(); i++) {
+						Annotation a = cqpAnnotations.get(i);
+						
+						// exact match + exact type
+						if (a.getType().equals(annotSelectedType.getId()) && a.getStart() == start && a.getEnd() == end) {
+							cqpAnnotations.remove(i);
+							i--;
+						}
+						else if (!a.getType().equals(annotSelectedType.getId()) && (// different type and inner or outer wrap
+								(a.getStart() <= start && end <= a.getEnd()) ||
+								(start <= a.getStart() && a.getEnd() <= end))) {
+							cqpAnnotations.remove(i);
+							i--;
+						}
+					}
+				}
+				else {
+					// no need to test collision (AnnotationType=TOKEN)
+					cqpAnnotations = new ArrayList<>();
+				}
+				
+				if (cqpAnnotations.size() > 0) {
+					allAnnotationsThatCollides.get(match).addAll(cqpAnnotations);
+					continue; // don't create annotation, process next match
+				}
+				else { // test with temporary annotation manager
+					List<Annotation> tempAnnotations = null;
+					if (annotSelectedType.getEffect() == AnnotationEffect.TOKEN) { // only annotate the first word
+						tempAnnotations = tempManager.createAnnotationNoCommit(annotSelectedType, annotSelectedTypedValue, start, start);
+					}
+					else {
+						tempAnnotations = tempManager.createAnnotationNoCommit(annotSelectedType, annotSelectedTypedValue, start, end);
+					}
+					if (tempAnnotations.size() > 0)
+						allAnnotationsThatCollides.get(match).addAll(tempAnnotations);
+				}
+				
+				nCreation++;
+				
+				if ((nCreation % 1000) == 0) {
+					tempManager.getEntityManager().flush(); // warning
+					tempManager.getEntityManager().clear(); // warning
+				}
+				if ((nCreation % 20000) == 0) {
+					tempManager.getEntityManager().getTransaction().commit(); // warning
+					tempManager.getEntityManager().getTransaction().begin(); // warning
+				}
+				
+			}
+			catch (Throwable e) {
+				Log.info(NLS.bind("Error during annotation creation: {0}.", e));
+				Log.printStackTrace(e);
+				
+				if (tempManager.getEntityManager().getTransaction().isActive()) {
+					tempManager.getEntityManager().getTransaction().rollback(); // reset state
+				}
+			}
+			
+			if (allAnnotationsThatCollides.get(match).size() == 0) allAnnotationsThatCollides.remove(match); // keep only colision lists
+		}
+		
+		cpb.done();
+		// System.out.println("T=" + (System.currentTimeMillis() - t));
+		
+		dirty = true;
+		tempManager.getEntityManager().getTransaction().commit(); // warning
+		return allAnnotationsThatCollides;
+	}
+	
+	public List<Annotation> getAnnotations(AnnotationType type, int start, int end, boolean overlap) {
+		List<Annotation> temporaryAnnotations = null;
+		List<Annotation> cqpAnnotations = null;
+		try {
+			temporaryAnnotations = tempManager.getAnnotations(type, Arrays.asList(new Match2P(start, end)), null, false, overlap);
+			cqpAnnotations = cqpManager.getAnnotations(type, start, end, overlap);
+			
+			int i = 0;
+			for (Annotation a : cqpAnnotations) {
+				while (temporaryAnnotations.get(i).getStart() < a.getStart()) {
+					i++;
+				}
+				temporaryAnnotations.add(i, a);
+			}
+		}
+		catch (Exception e) {
+			
+		}
+		return temporaryAnnotations;
+	}
+	
+	public List<Annotation> getAnnotations(AnnotationType type, int i, int j) {
+		return getAnnotations(type, i, j, false);
+	}
+	
+	public void closeAll() {
+		Log.fine("Closing annotation manager of " + corpus);
+		tempManager.close();
+		cqpManager.close();
+	}
+	
+	public boolean isOpen() {
+		return tempManager.getEntityManager() != null && tempManager.getEntityManager().isOpen();
+	}
+	
+	
+	public boolean initialize() throws Exception {
+		tempManager = new TemporaryAnnotationManager(corpus);
+		dirty = tempManager.getAnnotations().size() > 0;
+		cqpManager = new CQPAnnotationManager(corpus);
+		return false;
+	}
+	
+	/**
+	 * 
+	 * @return true if some annotations are not saved
+	 */
+	public boolean isDirty() {
+		return dirty;
+	}
+	
+	public boolean exportAnnotationsToTable(File resultFile) throws Exception {
+		
+		final String encoding = TBXPreferences.getInstance().getString(TBXPreferences.EXPORT_ENCODING);
+		String colseparator = TBXPreferences.getInstance().getString(TBXPreferences.EXPORT_COL_SEPARATOR);
+		String txtseparator = TBXPreferences.getInstance().getString(TBXPreferences.EXPORT_TXT_SEPARATOR);
+		
+		List<String> krnames = KRAnnotationEngine.getKnowledgeRepositoryNames(corpus);
+		if (krnames.size() == 0) {
+			Log.severe(NLS.bind("** Error: no knowledge repository found in {0} corpus.", corpus));
+			throw new IllegalArgumentException("No kr in " + corpus);
+		}
+		String firtsKRName = krnames.get(0);
+		KnowledgeRepository defaultKR = KRAnnotationEngine.getKnowledgeRepository(corpus, firtsKRName);
+		if (defaultKR == null) {
+			Log.severe(NLS.bind("** Error: no knowledge repository {0} found in {0} corpus.", defaultKR, corpus));
+			throw new IllegalArgumentException("No kr " + defaultKR + " in " + corpus);
+		}
+		
+		PrintWriter writer = IOUtils.getWriter(resultFile, encoding, false);
+		String cols [] = {"text_id", "id", "end_id", "start", "end", "type", "value", "mode", "date", "annotator"};
+		writer.println(StringUtils.join(cols, colseparator));
+		
+		if (this.getTemporaryManager().getAnnotations().size() == 0) {
+			Log.warning("Warning: no annotations to export. Aborting.");
+			return false;
+		}
+		
+		String[] textsIds = corpus.getCorpusTextIdsList();
+		int[] textsEndPositions = corpus.getTextEndLimits();
+		
+		HashMap<Integer, String> positions2Ids = new HashMap<Integer, String>();
+		HashMap<Integer, String> positions2TextIds = new HashMap<Integer, String>();
+		for (Annotation a : this.getTemporaryManager().getAnnotations()) {
+			positions2Ids.put(a.getStart(), null);
+			positions2Ids.put(a.getEnd(), null);
+		}
+		int[] positions = new int[positions2Ids.keySet().size()];
+		int i = 0;
+		for (int p : positions2Ids.keySet()) {
+			positions[i++] = p;
+		}
+		String values[] = corpus.getProperty("id").cpos2Str(positions);
+		for (i = 0 ; i < positions.length ; i++) {
+			positions2Ids.put(positions[i], values[i]);
+		}
+		
+		List<Annotation> annotations = this.getTemporaryManager().getAnnotations();
+		annotations.sort(new Comparator<Annotation>() {
+			@Override
+			public int compare(Annotation arg0, Annotation arg1) {
+				return arg0.getStart() - arg1.getStart();
+			}
+		});
+		
+		Log.info(NLS.bind("Exporting {0} annotations.", annotations.size()));
+		ConsoleProgressBar cpb = new ConsoleProgressBar(annotations.size());
+		
+		int currentText = 0;
+		for (Annotation a : annotations) {
+			cpb.tick();
+			// text_id	id	start	end	type	value	effect	date	annotator
+			String effect = defaultKR.getType(a.getType()).getEffect().name();
+			String startId = positions2Ids.get(a.getStart());
+			String endId = positions2Ids.get(a.getEnd());
+
+			while (textsEndPositions[currentText] < a.getStart()) {
+				// System.out.println("currentText="+currentText+" a="+a.getStart()+" text start="+textsEndPositions[currentText]+" text id="+textsIds[currentText]);
+				currentText++;// go to next text
+			}
+			String textid = textsIds[currentText];
+			
+			writer.println(
+					txtseparator+textid.replace(txtseparator, txtseparator+txtseparator)				+txtseparator
+					+colseparator+txtseparator+startId.replace(txtseparator, txtseparator+txtseparator)				+txtseparator
+					+colseparator+txtseparator+endId.replace(txtseparator, txtseparator+txtseparator)				+txtseparator
+					+colseparator+txtseparator+a.getStart()															+txtseparator
+					+colseparator+txtseparator+a.getEnd()															+txtseparator
+					+colseparator+txtseparator+a.getType().replace(txtseparator, txtseparator+txtseparator)			+txtseparator
+					+colseparator+txtseparator+a.getValue().replace(txtseparator, txtseparator+txtseparator)		+txtseparator
+					+colseparator+txtseparator+effect.replace(txtseparator, txtseparator+txtseparator)				+txtseparator
+					+colseparator+txtseparator+a.getDate().replace(txtseparator, txtseparator+txtseparator)			+txtseparator
+					+colseparator+txtseparator+a.getAnnotator().replace(txtseparator, txtseparator+txtseparator)	+txtseparator);
+		}
+		writer.close();
+		cpb.done();
+		return true;
+	}
+
+	public boolean importAnnotationsFromTable(File annotationsFile) throws Exception {
+		
+		if (!isOpen()) {
+			this.initialize();
+		}
+		
+		final String encoding = TBXPreferences.getInstance().getString(TBXPreferences.EXPORT_ENCODING);
+		String colseparator = TBXPreferences.getInstance().getString(TBXPreferences.EXPORT_COL_SEPARATOR);
+		String txtseparator = TBXPreferences.getInstance().getString(TBXPreferences.EXPORT_TXT_SEPARATOR);
+		
+		List<String> krnames = KRAnnotationEngine.getKnowledgeRepositoryNames(corpus);
+		if (krnames.size() == 0) {
+			Log.severe(NLS.bind("** Error: no knowledge repository found in {0} corpus.", corpus));
+			throw new IllegalArgumentException("No kr in " + corpus);
+		}
+		String firtsKRName = krnames.get(0);
+		KnowledgeRepository defaultKR = KRAnnotationEngine.getKnowledgeRepository(corpus, firtsKRName);
+		if (defaultKR == null) {
+			Log.severe(NLS.bind("** Error: no knowledge repository {0} found in {0} corpus.", defaultKR, corpus));
+			throw new IllegalArgumentException("No kr " + defaultKR + " in " + corpus);
+		}
+		
+		CsvReader reader = new CsvReader(annotationsFile.getAbsolutePath(), colseparator.charAt(0), Charset.forName(encoding));
+		if (txtseparator.length() > 0) reader.setTextQualifier(txtseparator.charAt(0));
+		reader.readHeaders();
+		String headers [] = reader.getHeaders();
+		String cols [] = {"text_id", "id", "end_id", "start", "end", "type", "value", "mode", "date", "annotator"};
+		if (headers.length != cols.length) {
+			Log.warning("Error: annotation file header format is not well-formatted: "+StringUtils.join(headers, ", ")+". Should be: "+StringUtils.join(cols, ", "));
+			return false;
+		}
+		for (int i = 0 ; i < cols.length ; i++) {
+			if (!(headers[i].equals(cols[i]))) {
+				Log.warning("Error: annotation file header format is not well-formatted: "+StringUtils.join(headers, ", ")+". Should be: "+StringUtils.join(cols, ", "));
+				return false;
+			}
+		}
+		
+		int nLines = 0;
+		while (reader.readRecord()) {
+			nLines++;
+		}
+		reader.close();
+		
+		if (nLines == 0) {
+			Log.warning("Error: no annotation line found");
+			return false;
+		}
+		
+		Log.info(NLS.bind("Importing {0} annotations...", nLines));
+		reader = new CsvReader(annotationsFile.getAbsolutePath(), colseparator.charAt(0), Charset.forName(encoding));
+		if (txtseparator.length() > 0) reader.setTextQualifier(txtseparator.charAt(0));
+		reader.readHeaders();
+		ConsoleProgressBar cpb = new ConsoleProgressBar(nLines);
+		this.tempManager.getEntityManager().getTransaction().begin();
+		while (reader.readRecord()) {
+			cpb.tick();
+			String[] record = reader.getValues();
+			String typeName = record[5].trim();
+			String typeEffect = record[7].trim();
+			if (defaultKR.getType(typeName) == null) {
+				defaultKR.addType(typeName, typeName, null, AnnotationEffect.valueOf(typeEffect));
+			}
+			AnnotationType type = defaultKR.getType(typeName);
+			String startId = record[1].trim();
+			String endId = record[2].trim();
+			int startPos = -1;
+			int endPos = -1;
+			if (startId.length() > 0 && endId.length() > 0) { // use the word id if present
+				String textId = record[0].trim();
+				if (startId.equals(endId)) {
+					CQLQuery cql = new CQLQuery(NLS.bind("[id=\"{0}\" & _.text_id=\"{1}\"]", startId, textId));
+					QueryResult qr = corpus.query(cql , "TMP", false);
+					if (qr.getNMatch() == 0) {
+						Log.warning("No match found with CQL="+cql);
+						continue;
+					}
+					startPos = qr.getMatch(0).getStart();
+					endPos = startPos;
+				} else {
+					CQLQuery cql = new CQLQuery(NLS.bind("[id=\"{0}\" & _.text_id=\"{1}\"]", startId, textId));
+					QueryResult qr = corpus.query(cql , "TMP", false);
+					if (qr.getNMatch() == 0) {
+						Log.warning("No match found with CQL="+cql);
+						continue;
+					}
+					startPos = qr.getMatch(0).getStart();
+					qr.drop();
+					cql = new CQLQuery(NLS.bind("[id=\"{0}\" & _.text_id=\"{1}\"]", endId, textId));
+					qr = corpus.query(cql , "TMP", false);
+					if (qr.getNMatch() == 0) {
+						Log.warning("No match found with CQL="+cql);
+						continue;
+					}
+					endPos = qr.getMatch(0).getStart();
+					qr.drop();
+				}
+			} else {
+				startPos = Integer.parseInt(record[3]);
+				endPos = Integer.parseInt(record[4]);
+				
+			}
+			if (type.getTypedValue(record[6]) == null) {
+				defaultKR.addValue(record[6], record[6], typeName);
+			}
+			TypedValue value = type.getTypedValue(record[6]);
+			List<Annotation> a = this.tempManager.createAnnotationNoCommit(type, value, startPos, endPos);
+		}
+		this.tempManager.getEntityManager().getTransaction().commit();
+		cpb.done();
+		
+		return true;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationManager.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationWriter.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationWriter.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationWriter.java	(revision 3653)
@@ -0,0 +1,312 @@
+package org.txm.annotation.kr.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.logging.Level;
+
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.commons.lang.StringUtils;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.service.prefs.BackingStoreException;
+import org.txm.Toolbox;
+import org.txm.annotation.kr.core.messages.KRAnnotationCoreMessages;
+import org.txm.annotation.kr.core.repository.AnnotationEffect;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.annotation.kr.core.repository.KnowledgeRepository;
+import org.txm.core.preferences.TBXPreferences;
+import org.txm.core.preferences.TXMPreferences;
+import org.txm.importer.ValidateXml;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.clientExceptions.InvalidCqpIdException;
+import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.searchengine.cqp.serverException.CqiServerError;
+import org.txm.utils.ConsoleProgressBar;
+import org.txm.utils.DeleteDir;
+import org.txm.utils.logger.Log;
+import org.txm.utils.zip.Zip;
+
+
+public class AnnotationWriter {
+	
+	MainCorpus corpus;
+	
+	private List<AnnotationType> types;
+	
+	private KnowledgeRepository defaultKR;
+	
+	public AnnotationWriter(MainCorpus corpus) throws BackingStoreException {
+		this.corpus = corpus;
+		List<String> krnames = KRAnnotationEngine.getKnowledgeRepositoryNames(corpus);
+		if (krnames.size() == 0) {
+			Log.severe(NLS.bind("** Error: no knowledge repository found in {0} corpus.", corpus));
+			throw new IllegalArgumentException("No kr in " + corpus);
+		}
+		String firtsKRName = krnames.get(0);
+		defaultKR = KRAnnotationEngine.getKnowledgeRepository(corpus, firtsKRName);
+		if (defaultKR == null) {
+			Log.severe(NLS.bind("** Error: no knowledge repository {0} found in {0} corpus.", defaultKR, corpus));
+			throw new IllegalArgumentException("No kr " + defaultKR + " in " + corpus);
+		}
+		
+		types = new ArrayList<AnnotationType>();
+		for (AnnotationType type : defaultKR.getAllAnnotationTypes()) {
+			if (type.getEffect().equals(AnnotationEffect.SEGMENT)) {
+				types.add(type);
+			}
+		}
+	}
+	
+	/**
+	 * process a text to build standoff files
+	 * 
+	 * @param textid
+	 * @param currentXMLFile
+	 * @param currentXMLStandoffFile
+	 * @param xmlStandOffDirectory
+	 * @return
+	 * @throws IOException
+	 * @throws CqiServerError
+	 * @throws CqiClientException
+	 * @throws InvalidCqpIdException
+	 * @throws XMLStreamException
+	 */
+	protected boolean writeTextAnnotationToSyMoGIH(String textid, File currentXMLFile, File currentXMLStandoffFile, File xmlStandOffDirectory) throws IOException, CqiServerError, CqiClientException, InvalidCqpIdException, XMLStreamException {
+		Log.info("  text=" + textid);
+		boolean show_debug = Log.getLevel().intValue() < Level.INFO.intValue();
+		
+		AnnotationSyMoGIHWriter annotationstdoff = new AnnotationSyMoGIHWriter(textid, currentXMLFile, xmlStandOffDirectory, types, show_debug);
+		
+		/// rather test on the new xml standoff files
+		if (annotationstdoff.process(currentXMLStandoffFile)) {
+			if (ValidateXml.test(currentXMLStandoffFile)) { // TODO ALSO check if annotations are well-written
+				return true;
+			}
+			else {
+				Log.warning(NLS.bind("Error: the {0} result file is malformed.", currentXMLStandoffFile));
+			}
+		}
+		else {
+			Log.warning(NLS.bind("Error: while processing the {0} file in standoff dir", currentXMLStandoffFile));
+		}
+		return false;
+		
+	}
+	
+	/**
+	 * Writing annotations in standoff files for each text of the corpus
+	 * 
+	 * @param allCorpusAnnotations
+	 * @return
+	 * @throws IOException
+	 * @throws CqiServerError
+	 * @throws CqiClientException
+	 * @throws InvalidCqpIdException
+	 * @throws XMLStreamException
+	 */
+	public boolean writeAnnotationsInStandoff(File resultZipFile) throws IOException, CqiServerError, CqiClientException, InvalidCqpIdException, XMLStreamException {
+		
+		List<String> textsIds = Arrays.asList(corpus.getCorpusTextIdsList());
+		Log.info(NLS.bind("Exporting annotations of the {0} text(s).", StringUtils.join(textsIds, ", ")));
+		
+		File resultDirectory = new File(Toolbox.getTxmHomePath(), "results/" + corpus.getID() + "_annotations");
+		DeleteDir.deleteDirectory(resultDirectory);
+		resultDirectory.mkdirs();
+		if (!(resultDirectory.exists() && resultDirectory.canWrite())) {
+			Log.warning(NLS.bind("ERROR: could not create/write temporary directory: {0}.", resultDirectory));
+			return false;
+		}
+		
+		File inputDirectory = corpus.getProjectDirectory();
+		File corpusTxmDirectory = new File(inputDirectory, "txm/" + corpus.getID());
+		
+		Log.info(NLS.bind("Writing annotations XML files in {0}.", resultDirectory));
+		for (String textid : textsIds) {
+			File currentXMLFile = new File(corpusTxmDirectory, textid + ".xml");
+			if (!currentXMLFile.exists()) {
+				Log.warning(NLS.bind("Error: cannot found ab XML-TXM file for text with the ''{0}'' id.", textid));
+				return false;
+			}
+			File currentXMLStandoffFile = new File(resultDirectory, textid + ".xml"); // To Be Changed ?
+			if (!writeTextAnnotationToSyMoGIH(textid, currentXMLFile, currentXMLStandoffFile, resultDirectory)) {
+				Log.warning(NLS.bind("Error while writing annotations of text in {0}.", currentXMLStandoffFile));
+				return false;
+			}
+		}
+		
+		Zip.compress(resultDirectory, resultZipFile, new ConsoleProgressBar(1));
+		DeleteDir.deleteDirectory(resultDirectory);
+		
+		Log.info(NLS.bind("Annotations saved in ''{0}''.", resultZipFile.getAbsolutePath()));
+		return resultZipFile.exists();
+	}
+	
+	/**
+	 * 
+	 * @param allCorpusAnnotations ordered annotations
+	 * @param monitor
+	 * @return
+	 * @throws IOException
+	 * @throws CqiServerError
+	 * @throws CqiClientException
+	 * @throws InvalidCqpIdException
+	 * @throws XMLStreamException
+	 * @throws BackingStoreException
+	 */
+	public boolean writeAnnotations(List<Annotation> allCorpusAnnotations, IProgressMonitor monitor) throws IOException, CqiServerError, CqiClientException, InvalidCqpIdException, XMLStreamException,
+			BackingStoreException {
+		// MainCorpus corpus = CorpusManager.getCorpusManager().getCorpus(c.getName());
+		Log.info(NLS.bind(KRAnnotationCoreMessages.savingP0Annotations, allCorpusAnnotations.size()));
+		
+		int[] end_limits = corpus.getTextEndLimits();
+		int[] start_limits = corpus.getTextStartLimits();
+		List<String> textsIds = Arrays.asList(corpus.getCorpusTextIdsList());
+		
+		File inputDirectory = corpus.getProjectDirectory();
+		File txmDirectory = new File(inputDirectory, "txm/" + corpus.getID());
+		
+		ArrayList<Annotation> textAnnotations = new ArrayList<Annotation>();
+		HashMap<String, ArrayList<Annotation>> annotationsPerTexts = new HashMap<String, ArrayList<Annotation>>();
+		
+		int currentText = 0;
+		File currentXMLFile = new File(txmDirectory, textsIds.get(currentText) + ".xml");
+		
+		textAnnotations = new ArrayList<Annotation>();
+		annotationsPerTexts.put(textsIds.get(currentText), textAnnotations);
+		
+		allCorpusAnnotations.sort(new Comparator<Annotation>() {
+			@Override
+			public int compare(Annotation arg0, Annotation arg1) {
+				int r = arg0.getStart() - arg1.getStart();
+				if (r == 0) {
+					return arg0.getEnd() - arg1.getEnd();
+				} else {
+					return r;
+				}
+			}
+		});
+		
+		// group annotations per text ; annotations are now sorted by position
+		for (Annotation currentAnnot : allCorpusAnnotations) { // parse all annotations
+			// System.out.println(" Annotation: "+currentAnnot);
+			int pos = currentAnnot.getPK().getEndPosition();
+			
+			while (pos > end_limits[currentText]) { // while pos is not in the currentText.end
+				currentText++;
+				textAnnotations = new ArrayList<Annotation>();
+				annotationsPerTexts.put(textsIds.get(currentText), textAnnotations);
+			}
+			
+			textAnnotations.add(currentAnnot);
+		}
+		
+		File tmpXMLTXMDirectory = new File(txmDirectory.getAbsolutePath() + "_tmp");
+		DeleteDir.deleteDirectory(tmpXMLTXMDirectory);
+		tmpXMLTXMDirectory.mkdirs();
+		if (!(tmpXMLTXMDirectory.exists() && tmpXMLTXMDirectory.canWrite())) {
+			Log.warning(NLS.bind("ERROR: could not create directory: {0}.", tmpXMLTXMDirectory));
+			return false;
+		}
+		
+		File previousXMLTXMDirectory = new File(txmDirectory.getAbsolutePath() + "_previous");
+		// DeleteDir.deleteDirectory(tmpXMLTXMDirectory);
+		previousXMLTXMDirectory.mkdirs();
+		if (!(previousXMLTXMDirectory.exists() && previousXMLTXMDirectory.canWrite())) {
+			Log.warning(NLS.bind("ERROR: could not create directory: {0}.", previousXMLTXMDirectory));
+			return false;
+		}
+		
+		Log.fine("Annotations grouped per text for " + annotationsPerTexts.size() + " text" + (annotationsPerTexts.size() > 0 ? "s" : ""));
+		Log.fine(" - Writing temporary XML files in: " + tmpXMLTXMDirectory);
+		Log.fine(" - Copying previous version of XML files in: " + previousXMLTXMDirectory);
+		// for all annotation PER TEXT, update the XML-TXM files
+		currentText = 0;
+		ConsoleProgressBar cpb = new ConsoleProgressBar(annotationsPerTexts.size());
+		while (currentText < end_limits.length) { // end limits : 10, 30, 45, 55, 103
+			currentXMLFile = new File(txmDirectory, textsIds.get(currentText) + ".xml");
+			ArrayList<Annotation> allAnnotations = annotationsPerTexts.get(textsIds.get(currentText));
+			if (allAnnotations != null && allAnnotations.size() > 0) {
+				ArrayList<Annotation> allSegmentAnnotations = new ArrayList<Annotation>();
+				ArrayList<Annotation> allTokenAnnotations = new ArrayList<Annotation>();
+				
+				// System.out.println("Using KR="+defaultKR);
+				for (Annotation a : allAnnotations) {
+					AnnotationType type = defaultKR.getType(a.getType());
+					if (type != null) {
+						if (AnnotationEffect.SEGMENT.equals(type.getEffect())) {
+							allSegmentAnnotations.add(a);
+						}
+						else if (AnnotationEffect.TOKEN.equals(type.getEffect())) {
+							allTokenAnnotations.add(a);
+						}
+						else {
+							Log.fine("Annotation " + a + " with type=" + a.getType() + " not found in default KR=" + defaultKR);
+						}
+					}
+					else {
+						Log.warning("Warning: unknowed type: " + a.getType());
+					}
+				}
+				
+				if (!writeAnnotationsInFile(currentXMLFile, start_limits[currentText],
+						allSegmentAnnotations, allTokenAnnotations,
+						tmpXMLTXMDirectory, previousXMLTXMDirectory)) {
+					Log.severe("Error while writing annotations of text " + currentXMLFile);
+					return false;
+				}
+				else {
+					if (monitor != null) {
+						monitor.worked(allSegmentAnnotations.size() + allTokenAnnotations.size());
+					}
+				}
+			}
+			currentText++;
+			cpb.tick();
+		}
+		cpb.done();
+		
+		return true;
+	}
+	
+	// writeAnnotationInStandoffFile(currentXMLStandoffFile, allAnnotations, annotator, tmpXMLTXMDirectory, previousXMLTXMDirectory))
+	
+	protected boolean writeAnnotationsInFile(File xmlFile, int text_start_position,
+			ArrayList<Annotation> segmentAnnotations, ArrayList<Annotation> tokenAnnotations, File tmpXMLTXMDirectory, File previousXMLTXMDirectory) throws CqiClientException, IOException,
+			CqiServerError, InvalidCqpIdException, XMLStreamException {
+		Log.fine("Writing annotations for text " + xmlFile + " segment annotations=" + segmentAnnotations.size() + " token annotations=" + tokenAnnotations.size());
+		// System.out.println(segmentAnnotations);
+		// System.out.println(tokenAnnotations);
+		
+		boolean show_debug = Log.getLevel().intValue() < Level.INFO.intValue();
+		AnnotationInjector annotationInjector = new AnnotationInjector(xmlFile, segmentAnnotations, tokenAnnotations, text_start_position, show_debug);
+		
+		File tmpfile = new File(tmpXMLTXMDirectory, xmlFile.getName());
+		File previousfile = new File(previousXMLTXMDirectory, xmlFile.getName());
+		
+		if (annotationInjector.process(tmpfile)) {
+			if (ValidateXml.test(tmpfile)) { // TODO ALSO check if annotations are well-written
+				previousfile.delete(); // in case there is one
+				if (!previousfile.exists() && xmlFile.renameTo(previousfile)) {
+					tmpfile.renameTo(xmlFile);
+					return true;
+				}
+				else {
+					Log.severe("Error: could not replace XML-TXM file: " + xmlFile + " with " + tmpfile);
+				}
+			}
+			else {
+				Log.severe("Error: result file " + tmpfile + " is malformed.");
+			}
+		}
+		else {
+			Log.severe("Error: while processing " + xmlFile + " in temp dir");
+		}
+		return false;
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationWriter.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationSyMoGIHWriter.java
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationSyMoGIHWriter.java	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationSyMoGIHWriter.java	(revision 3653)
@@ -0,0 +1,396 @@
+package org.txm.annotation.kr.core;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.eclipse.osgi.util.NLS;
+import org.txm.annotation.kr.core.repository.AnnotationType;
+import org.txm.importer.StaxIdentityParser;
+import org.txm.utils.logger.Log;
+
+/**
+ * The Class AnnotationStandoffInjector.
+ *
+ * @author sgedzelman, mdecorde
+ *
+ *         copy a XML-TXM file without annotations elements
+ *         and creates annotations XML-TEI-SymoGIH annotation files for each annotation author
+ * 
+ */
+public class AnnotationSyMoGIHWriter extends StaxIdentityParser {
+	
+	File xmlStandOffDirectory;
+	
+	boolean debug = false;
+	
+	String currentRef;
+	
+	String currentAuthor;
+	
+	String currentDate;
+	
+	String currentStartPos;
+	
+	String currentEndPos;
+	
+	// read xmlFile, to find annotations and update/write to xmlstandofffile
+	// order annotations by annotator
+	////// order annotations by date
+	HashSet<String> types = new HashSet<String>();
+	
+	ArrayList<String> positions;
+	
+	HashMap<String, ArrayList<String>> annotationsPositions;
+	
+	XMLStreamWriter currentWriter;
+	
+	XMLStreamWriter standoffWriter;
+	
+	String currentType;
+	
+	boolean startAnnotation = false;
+	
+	private String filename;
+	
+	// author -> date -> annotation_values
+	HashMap<String, HashMap<String, ArrayList<String[]>>> allannotations = new HashMap<String, HashMap<String, ArrayList<String[]>>>();
+	
+	HashMap<String, HashMap<String, ArrayList<ArrayList<String>>>> allannotationspositions = new HashMap<String, HashMap<String, ArrayList<ArrayList<String>>>>();
+	
+	private String textid;
+	
+	/**
+	 * 
+	 * @param xmlStandOffFile
+	 * @param tokenAnnotations
+	 * @param annotationsToAddByStartPos
+	 * @param annotationsToAddByEndPos
+	 * @param corpus_start_position
+	 * @param debug
+	 * @throws XMLStreamException
+	 * @throws IOException
+	 */
+	public AnnotationSyMoGIHWriter(String textid, File xmlFile, File xmlStandOffDirectory, List<AnnotationType> types, boolean debug) throws IOException, XMLStreamException {
+		super(xmlFile.toURI().toURL()); // init reader and writer
+		this.textid = textid;
+		this.filename = xmlFile.getName();
+		this.debug = debug;
+		this.xmlStandOffDirectory = xmlStandOffDirectory;
+		factory = XMLInputFactory.newInstance();
+		annotationsPositions = new HashMap<String, ArrayList<String>>();
+		// System.out.println("AnnotationStandoff - ");
+		for (AnnotationType type : types) {
+			this.types.add(type.getId()); // .getName().toLowerCase());
+			// System.out.println("Annotation Types in TXM : "+type.getName().toLowerCase() +" vs "+ type.getId());
+		}
+	}
+	
+	/*
+	 * <TEI xmlns="http://www.tei-c.org/ns/1.0">
+	 * <teiHeader>
+	 * <fileDesc>
+	 * <titleStmt>
+	 * <title>Title</title>
+	 * </titleStmt>
+	 * <publicationStmt>
+	 * <p>Publication Information</p>
+	 * </publicationStmt>
+	 * <sourceDesc>
+	 * <p>Ce document permet l'annotation sémantique de tous les textes concernant l'association avec des unités de connaissance</p>
+	 * </sourceDesc>
+	 * </fileDesc>
+	 * </teiHeader>
+	 * <text>
+	 * <body>
+	 * <div>
+	 * <div>
+	 * <!-- La date dans le header indique la date d'annotation -->
+	 * <head>
+	 * <date type="annotation_date" when="2016-06-16"/>
+	 * </head>
+	 * <span type="identification d'entités nommées" ana="CoAc56389"
+	 * target="#w_article_baip_1254-0714_1850_num_01_005_974_tei_2152
+	 * #w_article_baip_1254-0714_1850_num_01_005_974_tei_2153
+	 * #w_article_baip_1254-0714_1850_num_01_005_974_tei_2154
+	 * #w_article_baip_1254-0714_1850_num_01_005_974_tei_2155
+	 * #w_article_baip_1254-0714_1850_num_01_005_974_tei_2156" />
+	 * </div>
+	 * </div>
+	 * </body>
+	 * </text>
+	 * </TEI>
+	 */
+	
+	protected void processStartElement() throws XMLStreamException, IOException {
+		// <coac author="gazelledess" ref="CoAc397" start="5" end="5">
+		
+		/*
+		 * if(localname.startsWith("actr")){
+		 * System.out.println("Check existence of actr in Corpus !!!! "+localname);
+		 * }
+		 */
+		boolean foundAnnot = false;
+		
+		if (types.contains(localname) && parser.getPrefix().equals("txm")) { // don't write txm annotation elements
+			// System.out.println(" START "+ localname);
+			foundAnnot = true;
+			currentType = localname;
+			// <txm:actr author="gazelledess" ref="PhileasFogg" date="2016-09-05" start="56" end="57">
+			currentAuthor = parser.getAttributeValue(null, "author");
+			currentRef = parser.getAttributeValue(null, "ref");
+			currentStartPos = parser.getAttributeValue(null, "start");
+			currentEndPos = parser.getAttributeValue(null, "end");
+			currentDate = parser.getAttributeValue(null, "date");
+			// annotation is here
+			startAnnotation = true;
+			positions = new ArrayList<String>();
+			annotationsPositions.put(currentType, positions);
+			
+			// initialize allannotations
+			if (!allannotations.containsKey(currentAuthor)) {
+				allannotations.put(currentAuthor, new HashMap<String, ArrayList<String[]>>());
+				allannotationspositions.put(currentAuthor, new HashMap<String, ArrayList<ArrayList<String>>>());
+			}
+			HashMap<String, ArrayList<String[]>> authorsAnnotation = allannotations.get(currentAuthor);
+			HashMap<String, ArrayList<ArrayList<String>>> authorsAnnotationPositions = allannotationspositions.get(currentAuthor);
+			if (!authorsAnnotation.containsKey(currentDate)) {
+				authorsAnnotation.put(currentDate, new ArrayList<String[]>());
+				authorsAnnotationPositions.put(currentDate, new ArrayList<ArrayList<String>>());
+			}
+			
+			storeAnnotation();
+		}
+		
+		if (!foundAnnot) {
+			super.processStartElement(); /// continue writing in file all elements, except the tags that are now in stand-off files
+			
+			// get words ids of the current annotations
+			if (localname.equals("w") && startAnnotation) {
+				String id = parser.getAttributeValue(null, "id");
+				for (String typeIn : annotationsPositions.keySet()) {
+					positions = annotationsPositions.get(typeIn);
+					positions.add(id);
+					// System.out.println("Positions of w id="+posW+" for ["+typeIn+"] ");
+				}
+			}
+		}
+	}
+	
+	
+	/**
+	 * ends the current author stand-off file
+	 * 
+	 * @param currentWriter
+	 */
+	private void writeEndStandOffFile(XMLStreamWriter currentWriter) {
+		// System.out.println("writeEndStandOffFile ...");
+		
+		try {
+			currentWriter.writeEndElement();
+			currentWriter.writeEndDocument();
+			
+			currentWriter.flush();
+			currentWriter.close();
+		}
+		catch (XMLStreamException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	/**
+	 * Create the stand-off file for one author
+	 * 
+	 * @param file
+	 * @return
+	 */
+	private XMLStreamWriter writeStartStandOffFile(File file) {
+		// System.out.println("writeStartStandOffFile ...");
+		
+		String ns = "http://www.tei-c.org/ns/1.0";
+		XMLOutputFactory output = XMLOutputFactory.newInstance();
+		XMLStreamWriter writer = null;
+		try {
+			writer = output.createXMLStreamWriter(new FileWriter(file));
+			writer.writeStartDocument();
+			writer.setPrefix("tei", ns);
+			writer.setDefaultNamespace(ns);
+			
+			writer.writeStartElement("TEI");
+			
+			writer.writeStartElement("teiHeader");
+			writer.writeStartElement("fileDesc");
+			
+			writer.writeStartElement("titleStmt");
+			writer.writeStartElement("title");
+			writer.writeCharacters(textid);
+			writer.writeEndElement(); // title
+			writer.writeEndElement(); // titleStmt
+			
+			writer.writeStartElement("publicationStmt");
+			writer.writeStartElement("p");
+			writer.writeCharacters("PUBLICATION INFO à renseigner");
+			writer.writeEndElement(); // p
+			writer.writeEndElement(); // publicationStmt
+			
+			writer.writeStartElement("sourceDesc");
+			writer.writeStartElement("p");
+			writer.writeCharacters("Ce document permet l'annotation sémantique de tous les textes, par auteur");
+			writer.writeEndElement(); // p
+			writer.writeEndElement(); // sourceDesc
+			
+			writer.writeEndElement(); // </fileDesc>
+			writer.writeStartElement("encodingDesc");
+			writer.writeStartElement("projectDesc");
+			writer.writeStartElement("p");
+			writer.writeCharacters("Annotations created by " + currentAuthor + ", for the use in Symogih XML platform");
+			writer.writeEndElement(); // p
+			writer.writeEndElement(); // </projectDesc>
+			writer.writeEndElement(); // </encodingDesc>
+			writer.writeEndElement(); // </teiHeader>
+			
+			
+			writer.writeStartElement("text");
+			writer.writeStartElement("body");
+			writer.writeCharacters("\n");
+			writer.writeStartElement("div");
+			writer.writeCharacters("\n");
+		}
+		catch (XMLStreamException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return writer;
+	}
+	
+	private void storeAnnotation() {
+		allannotations.get(currentAuthor).get(currentDate).add(new String[] { currentDate, currentRef, currentType });
+	}
+	
+	private void storeAnnotationPositions() {
+		allannotationspositions.get(currentAuthor).get(currentDate).add(positions);
+	}
+	
+	/**
+	 * write stand-off annotation
+	 */
+	private void writeStartAnnotationToStandoffFile(String[] data, ArrayList<String> positions) {
+		// System.out.println("writeStartAnnotationToStandoffFile ...");
+		try {
+			currentWriter.writeStartElement("span");
+			currentWriter.writeAttribute("type", data[2]);
+			currentWriter.writeAttribute("ana", data[1]);
+			StringBuffer listWids = new StringBuffer();
+			for (String posW : positions) {
+				listWids.append("#" + posW + " ");
+			}
+			currentWriter.writeAttribute("target", listWids.toString().trim());
+			currentWriter.writeEndElement(); // span
+			currentWriter.writeCharacters("\n");
+		}
+		catch (XMLStreamException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	protected void processEndElement() throws XMLStreamException {
+		boolean foundAnnot = false;
+		if (types.contains(localname) && parser.getPrefix().equals("txm")) { // skip annotation end element
+			// System.out.println(" END "+ localname);
+			foundAnnot = true;
+			// annotation ends here
+			storeAnnotationPositions();
+			
+			if (annotationsPositions.containsKey(localname)) {
+				annotationsPositions.remove(localname);
+			}
+			
+			startAnnotation = false;
+		}
+		
+		if (!foundAnnot) {
+			if (localname.equals("TEI")) {
+				try {
+					for (String author : allannotations.keySet()) {
+						Log.info("    author=" + author);
+						File currentXmlFile = new File(xmlStandOffDirectory, filename.substring(0, filename.length() - 4) + "_" + currentAuthor + "_annotations.xml");
+						
+						// write start of the stand-off file
+						currentWriter = writeStartStandOffFile(currentXmlFile);
+						
+						// write annotations grouped per date
+						HashMap<String, ArrayList<String[]>> dates = allannotations.get(author);
+						HashMap<String, ArrayList<ArrayList<String>>> datesPositions = allannotationspositions.get(author);
+						for (String date : datesPositions.keySet()) {
+							ArrayList<String[]> datas = dates.get(date);
+							ArrayList<ArrayList<String>> positions = datesPositions.get(date);
+							
+							currentWriter.writeStartElement("div");
+							currentWriter.writeCharacters("\n");
+							currentWriter.writeStartElement("head");
+							currentWriter.writeStartElement("date");
+							currentWriter.writeAttribute("type", "annotation_date");
+							currentWriter.writeAttribute("when", date);
+							currentWriter.writeEndElement(); // date
+							currentWriter.writeEndElement(); // head
+							currentWriter.writeCharacters("\n");
+							
+							for (int i = 0; i < datas.size(); i++) {
+								writeStartAnnotationToStandoffFile(datas.get(i), positions.get(i));
+							}
+							
+							currentWriter.writeEndElement(); // div
+							currentWriter.writeCharacters("\n");
+						}
+						
+						// write the end of the stand-off file
+						writeEndStandOffFile(currentWriter);
+					}
+				}
+				catch (Exception e) {
+					Log.warning(NLS.bind("Error with current writer: {0}.", currentWriter));
+					Log.printStackTrace(e);
+				}
+			}
+			super.processEndElement();
+		}
+	}
+	
+	public static void main(String strs[]) {
+		try {
+			File xmlFile = new File("/home/mdecorde/TXM/corpora/TDM80J/txm/TDM80J", "tdm80j.xml");
+			File outfile = new File(xmlFile.getParentFile(), "tdm80j-tei.xml");
+			
+			File xmlStandOffDirectory = xmlFile.getParentFile();
+			List<AnnotationType> types = new ArrayList<AnnotationType>();
+			types.add(new AnnotationType("local", "actr_id", "actr"));
+			AnnotationSyMoGIHWriter annotStdff;
+			try {
+				annotStdff = new AnnotationSyMoGIHWriter("TDBM80J", xmlFile, xmlStandOffDirectory, types, true);
+				annotStdff.process(outfile);
+			}
+			catch (MalformedURLException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+}

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/src/org/txm/annotation/kr/core/AnnotationSyMoGIHWriter.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/libs/sqlite-jdbc-3.8.11.2.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/libs/sqlite-jdbc-3.8.11.2.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/libs/postgresql-9.4.1207.jre6.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/libs/postgresql-9.4.1207.jre6.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/build.properties
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/build.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/build.properties	(revision 3653)
@@ -0,0 +1,8 @@
+#Fri Jul 06 10:25:03 CEST 2018
+output..=bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml,\
+               OSGI-INF/
+source..=src/
+#qualifier=svn

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/build.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/OSGI-INF/l10n/bundle.properties
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/OSGI-INF/l10n/bundle.properties	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/OSGI-INF/l10n/bundle.properties	(revision 3653)
@@ -0,0 +1,4 @@
+#TXM OSGI messages generated by the PluginMessagesManager class
+#Fri Jun 10 16:36:03 CEST 2022
+Bundle-Name=KR Annotation Core
+Bundle-Vendor=Textometrie.org

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/OSGI-INF/l10n/bundle.properties
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/plugin.xml
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/plugin.xml	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/plugin.xml	(revision 3653)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>  
+   <extension
+         point="org.eclipse.core.runtime.preferences">
+      <initializer
+            class="org.txm.annotation.kr.core.preferences.KRAnnotationPreferences">
+      </initializer>
+   </extension>
+   <extension
+         point="org.txm.annotation.core.AnnotationEngine">
+      <AnnotationEngine
+            class="org.txm.annotation.kr.core.KRAnnotationEngine"
+            description="Annotate with a Knowledge repository">
+      </AnnotationEngine>
+   </extension>
+
+</plugin>

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/plugin.xml
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/.settings/org.eclipse.core.resources.prefs
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/.settings/org.eclipse.core.resources.prefs	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/.settings/org.eclipse.core.resources.prefs	(revision 3653)
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+encoding//src/org/txm/annotation/kr/core/messages/messages.properties=UTF-8
+encoding//src/org/txm/annotation/kr/core/messages/messages_fr.properties=UTF-8

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/.settings/org.eclipse.core.resources.prefs
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/.classpath
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/.classpath	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/.classpath	(revision 3653)
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins">
+		<accessrules>
+			<accessrule kind="accessible" pattern="**"/>
+		</accessrules>
+	</classpathentry>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="lib" path="libs/postgresql-9.4.1207.jre6.jar"/>
+	<classpathentry kind="lib" path="libs/sqlite-jdbc-3.8.11.2.jar"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/.classpath
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/META-INF/persistence.xml
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/META-INF/persistence.xml	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/META-INF/persistence.xml	(revision 3653)
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<persistence version="2.1"
+	xmlns="http://xmlns.jcp.org/xml/ns/persistence"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
+	<persistence-unit name="HSQLKRPERSISTENCE"
+		transaction-type="RESOURCE_LOCAL">
+		<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+
+		<class>org.txm.annotation.kr.core.Annotation</class>
+		<class>org.txm.annotation.kr.core.repository.AnnotationType</class>
+		<class>org.txm.annotation.kr.core.repository.TypedValue</class>
+		<!-- <class>org.txm.functions.dictionary_jpa.EntryId</class> <class>org.txm.functions.dictionary_jpa.EntryProperty</class> 
+			<class>org.txm.functions.dictionary_jpa.EntryPropertyType</class> -->
+		<properties>
+			<property name="javax.persistence.jdbc.driver"
+				value="org.hsqldb.jdbcDriver" />
+			<property name="javax.persistence.jdbc.url"
+				value="jdbc:hsqldb:file:txmdb/db;shutdown=true;hsqldb.write_delay=false;hsqldb.lock_file=false;hsqldb.applog=0;hsqldb.sqllog=0" />
+			<property name="javax.persistence.jdbc.user" value="SA" />
+
+			<property name="eclipselink.logging.level" value="OFF" />
+			<!-- <property name="eclipselink.jdbc.read-connections.min" value="1" 
+				/> <property name="eclipselink.jdbc.write-connections.min" value="1" /> <property 
+				name="eclipselink.jdbc.batch-writing" value="JDBC" /> -->
+
+			<!-- Logging <property name="eclipselink.logging.file" value="output.log"/> 
+				<property name="eclipselink.logging.logger" value="JavaLogger"/> <property 
+				name="eclipselink.logging.parameters" value="false"/> <property name="eclipselink.logging.level" 
+				value="FINE" /> <property name="eclipselink.logging.timestamp" value="false" 
+				/> <property name="eclipselink.logging.session" value="false" /> <property 
+				name="eclipselink.logging.thread" value="false" /> -->
+
+			<!-- <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/> -->
+			<!-- <property name="eclipselink.ddl-generation.output-mode" value="database"/> -->
+		</properties>
+
+	</persistence-unit>
+</persistence>
\ No newline at end of file

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/META-INF/persistence.xml
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/META-INF/MANIFEST.MF
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/META-INF/MANIFEST.MF	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/META-INF/MANIFEST.MF	(revision 3653)
@@ -0,0 +1,60 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: org.txm.annotation.kr.core
+Bundle-SymbolicName: org.txm.annotation.kr.core;singleton:=true
+Require-Bundle: org.txm.searchengine.cqp.core;visibility:=reexport,
+ org.txm.annotation.core;visibility:=reexport,
+ org.eclipse.persistence.core,
+ org.eclipse.persistence.jpa,
+ org.eclipse.persistence.asm,
+ org.eclipse.persistence.jpa.jpql,
+ org.eclipse.persistence.antlr,
+ jakarta.persistence
+Meta-Persistence: META-INF/persistence.xml
+Bundle-ActivationPolicy: lazy
+Bundle-ManifestVersion: 2
+Bundle-RequiredExecutionEnvironment: JavaSE-16
+Bundle-Vendor: Textometrie.org
+Export-Package: org.postgresql,
+ org.postgresql.copy,
+ org.postgresql.core,
+ org.postgresql.core.v2,
+ org.postgresql.core.v3,
+ org.postgresql.ds,
+ org.postgresql.ds.common,
+ org.postgresql.fastpath,
+ org.postgresql.geometric,
+ org.postgresql.gss,
+ org.postgresql.hostchooser,
+ org.postgresql.jdbc,
+ org.postgresql.jdbc2,
+ org.postgresql.jdbc2.optional,
+ org.postgresql.jdbc3,
+ org.postgresql.largeobject,
+ org.postgresql.osgi,
+ org.postgresql.ssl,
+ org.postgresql.ssl.jdbc4,
+ org.postgresql.sspi,
+ org.postgresql.translation,
+ org.postgresql.util,
+ org.postgresql.xa,
+ org.sqlite,
+ org.sqlite.core,
+ org.sqlite.date,
+ org.sqlite.javax,
+ org.sqlite.jdbc3,
+ org.sqlite.jdbc4,
+ org.sqlite.util,
+ org.txm.annotation.kr.core,
+ org.txm.annotation.kr.core.conversion,
+ org.txm.annotation.kr.core.messages,
+ org.txm.annotation.kr.core.preferences,
+ org.txm.annotation.kr.core.repository,
+ org.txm.annotation.kr.core.storage.temporary,
+ org.txm.annotation.kr.core.temporary
+Bundle-Version: 1.0.0.qualifier
+Bundle-Name: KR Annotation Core
+Bundle-ClassPath: .,
+ libs/postgresql-9.4.1207.jre6.jar,
+ libs/sqlite-jdbc-3.8.11.2.jar
+Bundle-Activator: org.txm.annotation.kr.core.Activator
+

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/META-INF/MANIFEST.MF
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/bundles/org.txm.annotation.kr.core/.project
===================================================================
--- TXM/trunk/bundles/org.txm.annotation.kr.core/.project	(revision 0)
+++ TXM/trunk/bundles/org.txm.annotation.kr.core/.project	(revision 3653)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.txm.annotation.kr.core</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core/.project
___________________________________________________________________
Added: svn:mime-type
   + text/plain


Property changes on: TXM/trunk/bundles/org.txm.annotation.kr.core
___________________________________________________________________
Added: svn:ignore
   + bin

target


