Index: TXM/trunk/org.txm.statsengine.r.rcp/src/org/txm/statsengine/r/rcp/messages/messages.properties
===================================================================
--- TXM/trunk/org.txm.statsengine.r.rcp/src/org/txm/statsengine/r/rcp/messages/messages.properties	(revision 3554)
+++ TXM/trunk/org.txm.statsengine.r.rcp/src/org/txm/statsengine/r/rcp/messages/messages.properties	(revision 3555)
@@ -19,12 +19,12 @@
 remoteConnection=Remote connection
 rPackageDiagnostic=R package diagnostic
 rserveArgs=Rserve arguments
-runRServeInDebugMode=Run RServe in debug mode
+runRServeInDebugMode=Run Rserve in debug mode
 sendingToRWorkspaceColon=Sending to R Workspace\: 
 serverAddress=Server address
 showEvalLogs=Showing R evaluation logs
 somePackagesAreMissingSeeConsoleForDetails=Some packages are missing. See the console for details.
-theRStatEngineIsNotRunningTryingToReinstallThePackagesRServeFactoMineRTextometry=The R statistical engine is not accessible. Try to reinstall R packets needed for TXM (RServe, FactoMineR, textometry...)
+theRStatEngineIsNotRunningTryingToReinstallThePackagesRServeFactoMineRTextometry=The R statistical engine is not accessible. Try to reinstall R packets needed for TXM (Rserve, FactoMineR, textometry...)
 tXMCouldNotLoadTheFactoMineRRPackageTheCorrespondanceAnalysisClassificationCommandsWontBeAvailable=TXM could not load the 'FactoMineR' R package. The Correspondance analysis, Classification commands won't be available
 tXMCouldNotLoadTheTextometryRPackageTheCooccurenceSpecificityAndProgressionCommandsWontBeAvailable=TXM could not load the 'textometry' R package. The Cooccurence, Specificity and Progression commands will not be available
 tXMCouldNotReinstallRPackagesPleaseDoItManuallySeeManual=TXM could not re-install R packages. Please do it manually (see manual).
Index: TXM/trunk/org.txm.statsengine.r.rcp/src/org/txm/statsengine/r/rcp/messages/messages_fr.properties
===================================================================
--- TXM/trunk/org.txm.statsengine.r.rcp/src/org/txm/statsengine/r/rcp/messages/messages_fr.properties	(revision 3554)
+++ TXM/trunk/org.txm.statsengine.r.rcp/src/org/txm/statsengine/r/rcp/messages/messages_fr.properties	(revision 3555)
@@ -19,12 +19,12 @@
 remoteConnection=Connexion à distance
 rPackageDiagnostic=Diagnostic de package R
 rserveArgs=Arguments Rserve
-runRServeInDebugMode=Exécuter RServe en mode debug
+runRServeInDebugMode=Exécuter Rserve en mode debug
 sendingToRWorkspaceColon=Transfert vers l'espace de travail R \: 
 serverAddress=Adresse du serveur
 showEvalLogs=Affichage du journal des évaluations R
 somePackagesAreMissingSeeConsoleForDetails=Certains paquets sont manquants. Voir la console pour les détails.
-theRStatEngineIsNotRunningTryingToReinstallThePackagesRServeFactoMineRTextometry=Le moteur statistique R n'est pas accessible. Essayez de réinstaller les paquets R nécessaires au fonctionnement de TXM (RServe, FactoMineR, textometry…)
+theRStatEngineIsNotRunningTryingToReinstallThePackagesRServeFactoMineRTextometry=Le moteur statistique R n'est pas accessible. Essayez de réinstaller les paquets R nécessaires au fonctionnement de TXM (Rserve, FactoMineR, textometry…)
 tXMCouldNotLoadTheFactoMineRRPackageTheCorrespondanceAnalysisClassificationCommandsWontBeAvailable=TXM n'a pas pu charger le package R 'FactoMineR'. L'analyse des correspondances et les commandes de classification ne seront pas disponibles
 tXMCouldNotLoadTheTextometryRPackageTheCooccurenceSpecificityAndProgressionCommandsWontBeAvailable=TXM n'a pas pu charger le package R 'textometry'. Les commandes Cooccurence, Spécificité et Progression ne seront pas disponibles
 tXMCouldNotReinstallRPackagesPleaseDoItManuallySeeManual=TXM n'a pas pu ré-installer les packages R. Veuillez le faire manuellement (voir manuel).
Index: TXM/trunk/org.txm.connlu.core/src/org/txm/conllu/core/function/UDSearch.java
===================================================================
--- TXM/trunk/org.txm.connlu.core/src/org/txm/conllu/core/function/UDSearch.java	(revision 3554)
+++ TXM/trunk/org.txm.connlu.core/src/org/txm/conllu/core/function/UDSearch.java	(revision 3555)
@@ -63,7 +63,7 @@
 	}
 	
 	@Override
-	public boolean toSVG(File svgFile, int sent, int sub, String T, String NT) {
+	public boolean toSVG(File svgFile, int sent, int sub, List<String> T, String NT) {
 		
 		if (!isDrawn()) return false; // no result
 		try {
@@ -90,10 +90,24 @@
 			
 			String prefix = UDPreferences.getInstance().getProjectPreferenceValue(corpus.getProject(), UDPreferences.UDPREFIX, UDPreferences.getInstance().getString(UDPreferences.UDPREFIX));
 			
-			String[] Tvalues = null;
-			if (T != null && corpus.getProperty(T) != null && !T.equals(prefix+"form")) {
-				Tvalues = corpus.getProperty(T).cpos2Str(positions);
+			String[] Tvalues = new String[positions.length];
+			for (int i = 0 ; i < Tvalues.length ; i++) {
+				Tvalues[i] += "";
 			}
+			
+			if (T != null && T.size() > 0) {
+				for (int iT = 0 ; iT < T.size() ; iT++) {
+					String t = T.get(iT);
+					if (corpus.getProperty(t) != null) {
+						String[] tvalues = corpus.getProperty(t).cpos2Str(positions);
+						for (int i = 0 ; i < tvalues.length ; i++) {
+							if (iT > 0) Tvalues[i] += "/";
+							Tvalues[i] += tvalues[i];
+						}
+					}
+				}
+			}
+			
 			String[] NTvalues = null;
 			if (NT != null && corpus.getProperty(NT) != null) {
 				NTvalues = corpus.getProperty(NT).cpos2Str(positions);
@@ -262,7 +276,7 @@
 	
 	@Override
 	public boolean loadParameters() throws Exception {
-		return true;
+		return super.loadParameters();
 	}
 	
 	@Override
@@ -272,7 +286,7 @@
 		
 		
 		if (pQuery == null || pQuery.getQueryString().length() == 0) {
-			pQuery = new CQLQuery("["+prefix+"id=\"1\"]");
+			pQuery = new CQLQuery("["+prefix+"deprel=\"root\"]"); // [ud-deprel="root"]
 		}
 		
 		udSentences = corpus.getSubcorpusByName(corpus.getName()+"/ud-sentences");
@@ -294,8 +308,8 @@
 	}
 	
 	public void setIndexAndSubIndex(int sent, int sub) {
-		this.index = sent;
-		this.subIndex = sub;
+		this.pIndex = sent;
+		this.pSubIndex = sub;
 	}
 	
 	@Override
@@ -341,7 +355,7 @@
 		WordProperty pid = corpus.getProperty("id");
 		StructuralUnitProperty ptextid = corpus.getStructuralUnitProperty("text_id");
 		
-		org.txm.objects.Match match = this.udSentences.getMatches().get(this.index);
+		org.txm.objects.Match match = this.udSentences.getMatches().get(this.pIndex);
 		int[] positions = new int[match.size()];
 		for (int i = 0 ; i < match.size() ; i++) {
 			positions[i] = match.getStart() + i;
Index: TXM/trunk/org.txm.treesearch.core/src/org/txm/treesearch/function/TreeSearch.java
===================================================================
--- TXM/trunk/org.txm.treesearch.core/src/org/txm/treesearch/function/TreeSearch.java	(revision 3554)
+++ TXM/trunk/org.txm.treesearch.core/src/org/txm/treesearch/function/TreeSearch.java	(revision 3555)
@@ -1,6 +1,9 @@
 package org.txm.treesearch.function;
 
 import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 import org.eclipse.osgi.util.NLS;
 import org.txm.core.preferences.TXMPreferences;
@@ -19,20 +22,20 @@
 	/**
 	 * from 0 to N-1 sentences
 	 */
-	@Parameter(key = TXMPreferences.INDEX)
-	protected int index;
+	@Parameter(key = TXMPreferences.INDEX, type = Parameter.RENDERING)
+	protected int pIndex;
 	
 	/**
 	 * from 0 to N-1 sentence subgraphs
 	 */
-	@Parameter(key = TXMPreferences.SUB_INDEX)
-	protected int subIndex;
+	@Parameter(key = TXMPreferences.SUB_INDEX, type = Parameter.RENDERING)
+	protected int pSubIndex;
 
 	@Parameter(key = TXMPreferences.QUERY)
 	protected IQuery pQuery;
 	
 	@Parameter(key = TreeSearchPreferences.TFEATURE)
-	protected String T;
+	protected List<String> T;
 	
 	@Parameter(key = TreeSearchPreferences.NTFEATURE)
 	protected String NT;
@@ -114,16 +117,29 @@
 	
 	public abstract int getSub(int matchNo);
 	
-	public final String getT() {
+	public final List<String> getT() {
 		return T;
 	}
 	
+	@Override
+	public boolean loadParameters() throws Exception {
+		
+		this.T = new ArrayList<>();
+		String values = getStringParameterValue(TreeSearchPreferences.TFEATURE);
+
+		if (values != null && !values.isEmpty() && values.length() > 0) {
+			this.T.addAll(Arrays.asList(values.split(",")));
+		}
+		
+		return true;
+	}
+	
 	public abstract boolean hasSubMatchesStrategy();
 	
 	@Override
 	public abstract boolean setParameters(TXMParameters parameters);
 	
-	public abstract boolean toSVG(File svgFile, int sent, int sub, String T, String NT);
+	public abstract boolean toSVG(File svgFile, int sent, int sub, List<String> T, String NT);
 
 	public abstract boolean isReady();
 
@@ -143,12 +159,12 @@
 
 	public int getCurrentMatchIndex() {
 		
-		return index;
+		return pIndex;
 	}
 
 	public int getCurrentSubMatchIndex() {
 		
-		return this.subIndex;
+		return this.pSubIndex;
 	}
 
 	public void setQuery(IQuery query) {
Index: TXM/trunk/org.txm.chartsengine.rcp/src/org/txm/chartsengine/rcp/swt/AdvancedChartEditorToolBar.java
===================================================================
--- TXM/trunk/org.txm.chartsengine.rcp/src/org/txm/chartsengine/rcp/swt/AdvancedChartEditorToolBar.java	(revision 3554)
+++ TXM/trunk/org.txm.chartsengine.rcp/src/org/txm/chartsengine/rcp/swt/AdvancedChartEditorToolBar.java	(revision 3555)
@@ -36,6 +36,15 @@
 public class AdvancedChartEditorToolBar extends ChartEditorToolBar {
 	
 	public final static String ID = "AdvancedChartEditorToolBar";
+	private ToolItem showTitleButton;
+	private ToolItem showLegendButton;
+	private ToolItem showGridButton;
+	private Combo renderingModeCombo;
+	private Combo fontCombo;
+	private Combo fontSizeCombo;
+	private Combo chartTypeCombo;
+	private Font currentFont;
+	//private Combo fontStyleCombo;
 	
 	/**
 	 *
@@ -45,82 +54,80 @@
 	public AdvancedChartEditorToolBar(ChartEditor<? extends ChartResult> chartEditor, Composite parent, GLComposite subWidgetsComposite, int style) {
 		super(chartEditor, parent, subWidgetsComposite, style, AdvancedChartEditorToolBar.ID);
 		
-		
-		final ToolItem showTitleButton = new ToolItem(this, SWT.CHECK);
-		// showTitle.setText(SWTComponentsProviderMessages.showhideTitle);
-		showTitleButton.setImage(IImageKeys.getImage(getClass(), "icons/show_title.png"));
-		showTitleButton.setDisabledImage(IImageKeys.getImage(getClass(), "icons/show_title_disabled.png"));
-		showTitleButton.setToolTipText(ChartsUIMessages.showhideTitle);
-		
 		if (!chartEditor.getResult().isEmptyPreference(ChartsEnginePreferences.SHOW_TITLE)) {
+			showTitleButton = new ToolItem(this, SWT.CHECK);
+			// showTitle.setText(SWTComponentsProviderMessages.showhideTitle);
+			showTitleButton.setImage(IImageKeys.getImage(getClass(), "icons/show_title.png"));
+			showTitleButton.setDisabledImage(IImageKeys.getImage(getClass(), "icons/show_title_disabled.png"));
+			showTitleButton.setToolTipText(ChartsUIMessages.showhideTitle);
+			
 			showTitleButton.setSelection(chartEditor.getResult().isTitleVisible());
 		}
-		// disable if not managed by the command
-		else {
-			showTitleButton.setEnabled(false);
-		}
+		//		// disable if not managed by the command
+		//		else {
+		//			showTitleButton.setEnabled(false);
+		//		}
 		
-		
-		final ToolItem showLegendButton = new ToolItem(this, SWT.CHECK);
-		// showLegend.setText(SWTComponentsProviderMessages.showhideLegend);
-		showLegendButton.setImage(IImageKeys.getImage(getClass(), "icons/show_legend.png"));
-		showLegendButton.setDisabledImage(IImageKeys.getImage(getClass(), "icons/show_legend_disabled.png"));
-		showLegendButton.setToolTipText(ChartsUIMessages.showhideLegend);
-		
 		if (!chartEditor.getResult().isEmptyPreference(ChartsEnginePreferences.SHOW_LEGEND)) {
+			showLegendButton = new ToolItem(this, SWT.CHECK);
+			// showLegend.setText(SWTComponentsProviderMessages.showhideLegend);
+			showLegendButton.setImage(IImageKeys.getImage(getClass(), "icons/show_legend.png"));
+			showLegendButton.setDisabledImage(IImageKeys.getImage(getClass(), "icons/show_legend_disabled.png"));
+			showLegendButton.setToolTipText(ChartsUIMessages.showhideLegend);
+			
 			showLegendButton.setSelection(chartEditor.getResult().isLegendVisible());
 		}
-		// disable if not managed by the command
-		else {
-			showLegendButton.setEnabled(false);
-		}
+		//		// disable if not managed by the command
+		//		else {
+		//			showLegendButton.setEnabled(false);
+		//		}
 		
-		
-		final ToolItem showGridButton = new ToolItem(this, SWT.CHECK);
-		// showGrid.setText(SWTComponentsProviderMessages.showhideGrid);
-		showGridButton.setImage(IImageKeys.getImage(getClass(), "icons/show_grid.png"));
-		showGridButton.setDisabledImage(IImageKeys.getImage(getClass(), "icons/show_grid_disabled.png"));
-		showGridButton.setToolTipText(ChartsUIMessages.showhideGrid);
-		
 		if (!chartEditor.getResult().isEmptyPreference(ChartsEnginePreferences.SHOW_GRID)) {
+			showGridButton = new ToolItem(this, SWT.CHECK);
+			// showGrid.setText(SWTComponentsProviderMessages.showhideGrid);
+			showGridButton.setImage(IImageKeys.getImage(getClass(), "icons/show_grid.png"));
+			showGridButton.setDisabledImage(IImageKeys.getImage(getClass(), "icons/show_grid_disabled.png"));
+			showGridButton.setToolTipText(ChartsUIMessages.showhideGrid);
+			
+			
 			showGridButton.setSelection(chartEditor.getResult().isGridVisible());
 		}
-		// disable if not managed by the command
-		else {
-			showGridButton.setEnabled(false);
-		}
+		//		// disable if not managed by the command
+		//		else {
+		//			showGridButton.setEnabled(false);
+		//		}
 		
 		
-		
-		// Rendering colors mode selection
-		new ToolItem(this, SWT.SEPARATOR);
-		final Combo renderingModeCombo = new Combo(this, SWT.READ_ONLY);
-		String colorsModes[] = new String[] { ChartsUIMessages.colors,
-				ChartsUIMessages.grayscale,
-				ChartsUIMessages.blackAndWhite,
-				ChartsUIMessages.monochrome
-		};
-		renderingModeCombo.setItems(colorsModes);
-		
-		ToolItem renderingComboItem = new ToolItem(this, SWT.SEPARATOR);
-		renderingComboItem.setControl(renderingModeCombo);
-		renderingModeCombo.pack();
-		renderingComboItem.setWidth(renderingModeCombo.getBounds().width);
-		
 		if (!chartEditor.getResult().isEmptyPreference(ChartsEnginePreferences.RENDERING_COLORS_MODE)) {
+			// Rendering colors mode selection
+			new ToolItem(this, SWT.SEPARATOR);
+			renderingModeCombo = new Combo(this, SWT.READ_ONLY);
+			String colorsModes[] = new String[] { ChartsUIMessages.colors,
+					ChartsUIMessages.grayscale,
+					ChartsUIMessages.blackAndWhite,
+					ChartsUIMessages.monochrome
+			};
+			renderingModeCombo.setItems(colorsModes);
+			
+			ToolItem renderingComboItem = new ToolItem(this, SWT.SEPARATOR);
+			renderingComboItem.setControl(renderingModeCombo);
+			renderingModeCombo.pack();
+			renderingComboItem.setWidth(renderingModeCombo.getBounds().width);
+			
+			
 			renderingModeCombo.select(chartEditor.getResult().getRenderingColorsMode());
 		}
-		// disable if not managed
-		else {
-			renderingModeCombo.setEnabled(false);
-		}
+		//		// disable if not managed
+		//		else {
+		//			renderingModeCombo.setEnabled(false);
+		//		}
 		
 		
 		// Font selection
-		final Font currentFont = ChartsEngine.createFont(chartEditor.getResult().getFont());
+		currentFont = ChartsEngine.createFont(chartEditor.getResult().getFont());
 		
-		final Combo fontCombo = new Combo(this, SWT.READ_ONLY);
-		String fonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); // FIXME: SJ: may be better here to get the fonts from SWT rather than from Java
+		fontCombo = new Combo(this, SWT.READ_ONLY);
+		String fonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); // FIXME: SJ: may be better here to get the fonts from SWT rather than from Java, see  java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
 		fontCombo.setItems(fonts);
 		
 		ToolItem fontsComboItem = new ToolItem(this, SWT.SEPARATOR);
@@ -137,9 +144,8 @@
 		}
 		fontCombo.select(currentFontIndex);
 		
-		
 		// Font size
-		final Combo fontSizeCombo = new Combo(this, SWT.READ_ONLY);
+		fontSizeCombo = new Combo(this, SWT.READ_ONLY);
 		String fontSizes[] = new String[30];
 		int currentFontSizeIndex = 0;
 		for (int i = 0; i < fontSizes.length; i++) {
@@ -158,54 +164,70 @@
 		
 		fontSizeCombo.select(currentFontSizeIndex);
 		
+		// Font size
+//		fontStyleCombo = new Combo(this, SWT.READ_ONLY);
+//		String fontStyles[] = new String[] {"normal", "bold", "italic"};
+//		int currentFontStyleIndex = 0;
+//		fontStyleCombo.setItems(fontStyles);
+//		
+//		ToolItem fontStyleComboItem = new ToolItem(this, SWT.SEPARATOR);
+//		fontStyleComboItem.setControl(fontStyleCombo);
+//		fontStyleCombo.pack();
+//		fontStyleComboItem.setWidth(fontStyleCombo.getBounds().width);
+//		
+//		fontStyleCombo.select(currentFontStyleIndex);
 		
+		
+		
 		// Chart types from installed chart creators in all installed charts engines
-		final Combo chartTypeCombo = new Combo(this, SWT.READ_ONLY);
+		
 		if (TBXPreferences.getInstance().getBoolean(TBXPreferences.EXPERT_USER)) {
 			
+			chartTypeCombo = new Combo(this, SWT.READ_ONLY);
+			
 			ArrayList<String> chartsEngineNames = new ArrayList<>();
 			ArrayList<ChartCreator> allChartCreators = new ArrayList<>();
 			
-			for (ChartsEngine engine : ChartsEnginesManager.getChartsEngines()) {
-				for (ChartCreator creator : engine.getChartCreators(this.getEditorPart().getResult())) {
-					chartsEngineNames.add(engine.getName());
-					allChartCreators.add(creator);
+			if (allChartCreators.size() > 1) {
+				for (ChartsEngine engine : ChartsEnginesManager.getChartsEngines()) {
+					for (ChartCreator creator : engine.getChartCreators(this.getEditorPart().getResult())) {
+						chartsEngineNames.add(engine.getName());
+						allChartCreators.add(creator);
+					}
 				}
-			}
-			
-			
-			String chartTypes[] = new String[allChartCreators.size()];
-			int currentChartCreatorIndex = 0;
-			
-			for (int i = 0; i < allChartCreators.size(); i++) {
 				
-				chartTypes[i] = allChartCreators.get(i).getChartType();
-				if (chartTypes[i] == null) {
-					chartTypes[i] = ChartsEnginePreferences.DEFAULT_CHART_TYPE;
-				}
 				
-				// preselected combo index
-				if (this.getEditorPart().getChartType() != null && this.getEditorPart().getChartType().equals(chartTypes[i])
-						&& this.getEditorPart().getResult().getChartsEngine().getName().equals(chartsEngineNames.get(i))) {
-					currentChartCreatorIndex = i;
+				String chartTypes[] = new String[allChartCreators.size()];
+				int currentChartCreatorIndex = 0;
+				
+				for (int i = 0; i < allChartCreators.size(); i++) {
+					
+					chartTypes[i] = allChartCreators.get(i).getChartType();
+					if (chartTypes[i] == null) {
+						chartTypes[i] = ChartsEnginePreferences.DEFAULT_CHART_TYPE;
+					}
+					
+					// preselected combo index
+					if (this.getEditorPart().getChartType() != null && this.getEditorPart().getChartType().equals(chartTypes[i])
+							&& this.getEditorPart().getResult().getChartsEngine().getName().equals(chartsEngineNames.get(i))) {
+						currentChartCreatorIndex = i;
+					}
+					
+					chartTypes[i] = chartsEngineNames.get(i) + " / " + chartTypes[i]; //$NON-NLS-1$
+					
 				}
+				chartTypeCombo.setItems(chartTypes);
+				chartTypeCombo.select(currentChartCreatorIndex);
 				
-				chartTypes[i] = chartsEngineNames.get(i) + " / " + chartTypes[i]; //$NON-NLS-1$
+				ToolItem chartTypeComboItem = new ToolItem(this, SWT.SEPARATOR);
+				chartTypeComboItem.setControl(chartTypeCombo);
+				chartTypeCombo.pack();
+				chartTypeComboItem.setWidth(chartTypeCombo.getBounds().width);
 				
+				
+				
+				//chartTypeCombo.setVisible(false);
 			}
-			chartTypeCombo.setItems(chartTypes);
-			
-			ToolItem chartTypeComboItem = new ToolItem(this, SWT.SEPARATOR);
-			chartTypeComboItem.setControl(chartTypeCombo);
-			chartTypeCombo.pack();
-			chartTypeComboItem.setWidth(chartTypeCombo.getBounds().width);
-			
-			chartTypeCombo.select(currentChartCreatorIndex);
-			
-			
-			if (allChartCreators.size() < 2) {
-				chartTypeCombo.setVisible(false);
-			}
 		}
 		
 		
@@ -217,7 +239,6 @@
 				
 				boolean update = true;
 				
-				
 				// FIXME: SJ: title, legend, grid visibility etc. should use the autoUpdateEditor annotation parameters copy functions
 				if (e.getSource() == showTitleButton) {
 					getEditorPart().getResult().setTitleVisible(showTitleButton.getSelection());
@@ -234,8 +255,8 @@
 				// end of FIXME
 				
 				// Font
-				else if (e.getSource() == fontCombo || e.getSource() == fontSizeCombo) {
-					getEditorPart().getResult().setFont("1|" + fontCombo.getItem(fontCombo.getSelectionIndex()) + "|" + fontSizeCombo.getItem(fontSizeCombo.getSelectionIndex()) + "|0"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+				else if (e.getSource() == fontCombo || e.getSource() == fontSizeCombo) { //  || e.getSource() == fontStyleCombo) {
+					getEditorPart().getResult().setFont("1|" + fontCombo.getItem(fontCombo.getSelectionIndex()) + "|" + fontSizeCombo.getItem(fontSizeCombo.getSelectionIndex()) + "|1"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ +fontStyleCombo.getSelectionIndex()
 				}
 				// Chart type / chart creators
 				else if (e.getSource() == chartTypeCombo) {
@@ -273,13 +294,14 @@
 				
 			}
 		};
-		showTitleButton.addSelectionListener(listener);
-		showLegendButton.addSelectionListener(listener);
-		showGridButton.addSelectionListener(listener);
-		renderingModeCombo.addSelectionListener(listener);
-		fontCombo.addSelectionListener(listener);
-		fontSizeCombo.addSelectionListener(listener);
-		chartTypeCombo.addSelectionListener(listener);
+		if (showTitleButton != null) showTitleButton.addSelectionListener(listener);
+		if (showLegendButton != null) showLegendButton.addSelectionListener(listener);
+		if (showGridButton != null) showGridButton.addSelectionListener(listener);
+		if (renderingModeCombo != null) renderingModeCombo.addSelectionListener(listener);
+		if (fontCombo != null) fontCombo.addSelectionListener(listener);
+		if (fontSizeCombo != null) fontSizeCombo.addSelectionListener(listener);
+		//if (fontStyleCombo != null) fontStyleCombo.addSelectionListener(listener);
+		if (chartTypeCombo != null) chartTypeCombo.addSelectionListener(listener);
 	}
 	
 	
Index: TXM/trunk/org.txm.statsengine.r.core/src/org/txm/statsengine/r/core/RStatsEngine.java
===================================================================
--- TXM/trunk/org.txm.statsengine.r.core/src/org/txm/statsengine/r/core/RStatsEngine.java	(revision 3554)
+++ TXM/trunk/org.txm.statsengine.r.core/src/org/txm/statsengine/r/core/RStatsEngine.java	(revision 3555)
@@ -19,7 +19,7 @@
 import org.txm.utils.logger.Log;
 
 /**
- * R statistics engine. Contains methods to start, stop, kill, etc. the R and RServe process.
+ * R statistics engine. Contains methods to start, stop, kill, etc. the R and Rserve process.
  * 
  * @author mdecorde
  * @author sjacquot
@@ -41,7 +41,7 @@
 
 
 	/**
-	 * Starts the stats engine if the engine is not remote then launch RServe.
+	 * Starts the stats engine if the engine is not remote then launch Rserve.
 	 *
 	 * @return true, if successful
 	 */
Index: TXM/trunk/org.txm.statsengine.r.core/src/org/txm/statsengine/r/core/StartRserve.java
===================================================================
--- TXM/trunk/org.txm.statsengine.r.core/src/org/txm/statsengine/r/core/StartRserve.java	(revision 3554)
+++ TXM/trunk/org.txm.statsengine.r.core/src/org/txm/statsengine/r/core/StartRserve.java	(revision 3555)
@@ -73,7 +73,7 @@
 		if (new File(cmd).exists() && !new File(cmd).isDirectory()
 				&& new File(cmd).canExecute())
 			return launchRserve(cmd,
-					"--no-init-file --no-save --encoding utf8 " + rArgs, "--RS-encoding utf8 --no-save --encoding utf8 " + rServeArgs, port, debug); //$NON-NLS-1$ //$NON-NLS-2$
+					"--vanilla --encoding utf8 " + rArgs, "--RS-encoding utf8 --vanilla --encoding utf8 " + rServeArgs, port, debug); //$NON-NLS-1$ //$NON-NLS-2$
 		return false; // checkLocalRserve(port, debug, rArgs, rServeArgs);
 	}
 	
Index: TXM/trunk/org.txm.statsengine.r.core/src/org/txm/statsengine/r/core/messages/messages_fr.properties
===================================================================
--- TXM/trunk/org.txm.statsengine.r.core/src/org/txm/statsengine/r/core/messages/messages_fr.properties	(revision 3554)
+++ TXM/trunk/org.txm.statsengine.r.core/src/org/txm/statsengine/r/core/messages/messages_fr.properties	(revision 3555)
@@ -11,7 +11,7 @@
 error_failedToInitializeFileTransfert=** Échec de l''initialisation du transfert \: {0}.
 error_failedToLoadLibrary=** La librairie {0} n''a pas pu être chargée \: {1}.
 error_failedToRunREG=** Échec du lancement de REG pour localiser le programme R.
-error_failedToStartRServe=** Impossible de démarrer le moteur statistique (RServe).
+error_failedToStartRServe=** Impossible de démarrer le moteur statistique (Rserve).
 error_failedToStartRServeWithCommand=** Échec du lancement de Rserve avec la commande \: 
 error_matrixIsEmpty=La matrice est vide.
 error_requestedObjectNotFoundInR=L''objet demandé ({0}) n''a pas été trouvé dans l''espace de travail R.
Index: TXM/trunk/org.txm.tigersearch.rcp/src/org/txm/searchengine/ts/TSCorpus.java
===================================================================
--- TXM/trunk/org.txm.tigersearch.rcp/src/org/txm/searchengine/ts/TSCorpus.java	(revision 3554)
+++ TXM/trunk/org.txm.tigersearch.rcp/src/org/txm/searchengine/ts/TSCorpus.java	(revision 3555)
@@ -232,8 +232,17 @@
 	}
 	
 	public void setDisplayProperties(Header header, List<String> tprops, String ntprop) {
-		config.setDisplayedTFeatures(header, tprops);
-		config.setDisplayedNTFeature(header, ntprop);
+		
+		if (tprops != null && tprops.size() > 0) {
+			config.setDisplayedTFeatures(header, tprops);
+		} else {
+			config.setDisplayedTFeatures(header, header.getAllTFeatureNames().subList(0, 1));
+		}
+		if (ntprop != null && ntprop.length() > 0) {
+			config.setDisplayedNTFeature(header, ntprop);
+		} else {
+			config.setDisplayedNTFeature(header, header.getAllNTFeatureNames().get(0).toString());
+		}
 	}
 	
 	public InternalCorpusQueryManager getInternalManager() {
Index: TXM/trunk/org.txm.tigersearch.rcp/src/org/txm/searchengine/ts/TSResult.java
===================================================================
--- TXM/trunk/org.txm.tigersearch.rcp/src/org/txm/searchengine/ts/TSResult.java	(revision 3554)
+++ TXM/trunk/org.txm.tigersearch.rcp/src/org/txm/searchengine/ts/TSResult.java	(revision 3555)
@@ -186,7 +186,8 @@
 		return matches[matchNo];
 	}
 	
-	public void setDisplayProperties(ArrayList<String> tprops, String feature) {
+	public void setDisplayProperties(List<String> tprops, String feature) {
+		
 		tsCorpus.setDisplayProperties(this.header, tprops, feature);
 	}
 	
Index: TXM/trunk/org.txm.tigersearch.rcp/src/org/txm/searchengine/ts/TIGERSearchEngine.java
===================================================================
--- TXM/trunk/org.txm.tigersearch.rcp/src/org/txm/searchengine/ts/TIGERSearchEngine.java	(revision 3554)
+++ TXM/trunk/org.txm.tigersearch.rcp/src/org/txm/searchengine/ts/TIGERSearchEngine.java	(revision 3555)
@@ -37,6 +37,7 @@
 import org.txm.utils.logger.Log;
 
 import ims.tiger.index.reader.Index;
+import ims.tiger.index.reader.IndexException;
 import ims.tiger.index.writer.IndexBuilderErrorHandler;
 import ims.tiger.index.writer.SimpleErrorHandler;
 import ims.tiger.index.writer.XMLIndexing;
@@ -191,6 +192,12 @@
 			Log.finest("QUERYING sentences: " + sent_min + " -> " + sent_max);
 			result = tcorpus.query(query.getQueryString().replace("\n", " "), sent_min, sent_max + 1, -1);
 		}
+		
+		return fromTIGERMatchToSelection(tcorpus, result, query, corpus);
+	}
+	
+	public static Selection fromTIGERMatchToSelection(TSCorpus tcorpus, TSResult result, IQuery query, CorpusBuild corpus) throws IndexException {
+		
 		MatchResult mresult = result.getMatchResult();
 		int size = mresult.size();
 		// System.out.println("size: "+size);
Index: TXM/trunk/org.txm.tigersearch.rcp/src/org/txm/function/tigersearch/TIGERSearch.java
===================================================================
--- TXM/trunk/org.txm.tigersearch.rcp/src/org/txm/function/tigersearch/TIGERSearch.java	(revision 3554)
+++ TXM/trunk/org.txm.tigersearch.rcp/src/org/txm/function/tigersearch/TIGERSearch.java	(revision 3555)
@@ -16,6 +16,8 @@
 import org.txm.searchengine.cqp.corpus.StructuralUnitProperty;
 import org.txm.searchengine.cqp.corpus.WordProperty;
 import org.txm.searchengine.ts.TIGERQuery;
+import org.txm.searchengine.ts.TIGERSearchEngine;
+import org.txm.searchengine.ts.TIGERSelection;
 import org.txm.searchengine.ts.TSCorpus;
 import org.txm.searchengine.ts.TSCorpusManager;
 import org.txm.searchengine.ts.TSMatch;
@@ -23,10 +25,12 @@
 import org.txm.tigersearch.rcp.Messages;
 import org.txm.treesearch.function.TreeSearch;
 import org.txm.treesearch.function.TreeSearchSelector;
+import org.txm.treesearch.preferences.TreeSearchPreferences;
 import org.txm.utils.TXMProgressMonitor;
 import org.txm.utils.logger.Log;
 
 import ims.tiger.index.reader.Index;
+import ims.tiger.index.reader.IndexException;
 
 public class TIGERSearch extends TreeSearch {
 	
@@ -38,6 +42,8 @@
 	
 	protected TSResult tsresult;
 	
+	private Selection tigerSelection;
+	
 	//protected String T, NT;
 	
 	public TIGERSearch(CQPCorpus corpus) {
@@ -93,7 +99,7 @@
 		return tsresult != null && T != null && NT != null;
 	}
 	
-	public boolean toSVG(File svgFile, int sent, int sub, String T, String NT) {
+	public boolean toSVG(File svgFile, int sent, int sub, List<String> T, String NT) {
 		
 		if (tsresult == null) return false; // no result
 		this.T = T;
@@ -101,7 +107,7 @@
 		
 		if (tsresult.getNumberOfMatch() == 0) return false;
 		
-		tsresult.setDisplayProperties(new ArrayList<>(Arrays.asList(T)), NT);
+		tsresult.setDisplayProperties(T, NT);
 		
 		try {
 			// iterate to the sub th subgraph
@@ -226,6 +232,8 @@
 	@Override
 	public boolean loadParameters() throws Exception {
 		
+		super.loadParameters();
+		
 		this.pQuery = new TIGERQuery(this.getStringParameterValue(ConcordancePreferences.QUERY));
 		
 		return true;
@@ -234,17 +242,23 @@
 	@Override
 	protected boolean _compute(TXMProgressMonitor monitor) throws Exception {
 		
-		if (tscorpus == null) return false;
+		//if (hasParameterChanged(TreeSearchPreferences.QUERY)) {
+			
+			if (tscorpus == null) return false;
+			
+			tsresult = null;
+			tigerSelection = null;
+			
+			if (pQuery == null || pQuery.getQueryString().length() == 0) {
+				pQuery = new TIGERQuery("root(#n1)"); //$NON-NLS-1$
+			}
+			
+			tsresult = tscorpus.query(pQuery.getQueryString());
+			tsresult.getFirst();
+//		} else {
+//			
+//		}
 		
-		tsresult = null;
-		
-		if (pQuery == null || pQuery.getQueryString().length() == 0) {
-			pQuery = new TIGERQuery("root(#n1)"); //$NON-NLS-1$
-		}
-		
-		tsresult = tscorpus.query(pQuery.getQueryString());
-		tsresult.getFirst();
-		
 		return true;
 	}
 	
@@ -254,28 +268,28 @@
 	}
 	
 	public void setIndexAndSubIndex(int sent, int sub) {
-		this.index = sent;
-		this.subIndex = sub;
+		this.pIndex = sent;
+		this.pSubIndex = sub;
 	}
-
+	
 	@Override
 	public boolean hasSubMatchesStrategy() {
 		
 		return true;
 	}
-
+	
 	@Override
 	public String getEngine() {
 		
 		return TIGERTreeSearchSelector.TIGER;
 	}
-
+	
 	@Override
 	public TreeSearchSelector getSelector() {
 		
 		return new TIGERTreeSearchSelector();
 	}
-
+	
 	@Override
 	public String[] getTextAndWordIDSOfCurrentSentence() throws Exception {
 		
@@ -290,7 +304,7 @@
 		int[] starts = tscorpus.getSentenceStartPositions();
 		
 		//TSMatch s = tsresult.getMatch(this.index);
-		int sent = tsresult.getMatchResult().getSentenceNumberAt(this.index);
+		int sent = tsresult.getMatchResult().getSentenceNumberAt(this.pIndex);
 		
 		int sent_start = starts[sent];
 		
@@ -304,10 +318,10 @@
 		for (int i = 0 ; i < l ; i++) {
 			positions[i] = left + i;
 		}
-//		int right = sent_start + index.getRightCorner(sent, index.getSentence(sent).getTerminalsSize());
-//		if (offsetsMapped != null) { // the TIGER token is not in the CQP corpus
-//			right += offsetsMapped.getInt(right * Integer.BYTES);
-//		}
+		//		int right = sent_start + index.getRightCorner(sent, index.getSentence(sent).getTerminalsSize());
+		//		if (offsetsMapped != null) { // the TIGER token is not in the CQP corpus
+		//			right += offsetsMapped.getInt(right * Integer.BYTES);
+		//		}
 		WordProperty pid = corpus.getProperty("id"); //$NON-NLS-1$
 		StructuralUnitProperty ptextid = corpus.getStructuralUnitProperty("text_id"); //$NON-NLS-1$
 		
@@ -320,20 +334,28 @@
 		
 		return textAndWord;
 	}
-
+	
 	@Override
 	public String getIconPath() {
 		
 		return "platform:/plugin/org.txm.tigersearch.rcp/icons/functions/TS.png"; //$NON-NLS-1$
 	}
-
+	
 	@Override
 	public Selection getSelection() {
 		
-		// TODO Auto-generated method stub
-		return null;
+		if (tigerSelection == null) {
+			try {
+				tigerSelection =  TIGERSearchEngine.fromTIGERMatchToSelection(this.tscorpus, getTSResult(), pQuery, corpus);
+			}
+			catch (IndexException e) {
+				e.printStackTrace();
+				return null;
+			}
+		}
+		return tigerSelection;
 	}
-
+	
 	@Override
 	public File createTemporaryFile(File resultDir) {
 		
@@ -346,7 +368,7 @@
 			return null;
 		} //$NON-NLS-1$ //$NON-NLS-2$ull;
 	}
-
+	
 	@Override
 	public String[] getAvailableVisualisations() {
 		
Index: TXM/trunk/org.txm.chartsengine.core/src/org/txm/chartsengine/core/ChartsEngine.java
===================================================================
--- TXM/trunk/org.txm.chartsengine.core/src/org/txm/chartsengine/core/ChartsEngine.java	(revision 3554)
+++ TXM/trunk/org.txm.chartsengine.core/src/org/txm/chartsengine/core/ChartsEngine.java	(revision 3555)
@@ -338,7 +338,9 @@
 	 */
 	public static Font createFont(String encodedStr) {
 		String[] data = encodedStr.split("\\|");
-		Font font = new Font(data[1], Integer.valueOf(data[3]), Integer.parseInt(data[2].split("\\.")[0]));
+		Font font = new Font(data[1], // font name
+					Integer.valueOf(data[3]), // font style
+					Integer.parseInt(data[2].split("\\.")[0])); // font size
 		return font;
 	}
 	
Index: TXM/trunk/org.txm.ca.rcp/src/org/txm/ca/rcp/editors/CAFactorialMapChartEditor.java
===================================================================
--- TXM/trunk/org.txm.ca.rcp/src/org/txm/ca/rcp/editors/CAFactorialMapChartEditor.java	(revision 3554)
+++ TXM/trunk/org.txm.ca.rcp/src/org/txm/ca/rcp/editors/CAFactorialMapChartEditor.java	(revision 3555)
@@ -364,16 +364,16 @@
 			}
 		}
 		
-//		Label l = new Label(this.getExtendedParametersGroup(), SWT.NONE);
-//		l.setText("Supplementary row names:");
-//		
-//		supRowNamesText = new Text(this.getExtendedParametersGroup(), SWT.BORDER);
-//		
-//		l = new Label(this.getExtendedParametersGroup(), SWT.NONE);
-//		l.setText("Supplementary col names:");
-//		
-//		supColNamesText = new Text(this.getExtendedParametersGroup(), SWT.BORDER);
+		Label l = new Label(this.getExtendedParametersGroup(), SWT.NONE);
+		l.setText("Supplementary row names:");
 		
+		supRowNamesText = new Text(this.getExtendedParametersGroup(), SWT.BORDER);
+		
+		l = new Label(this.getExtendedParametersGroup(), SWT.NONE);
+		l.setText("Supplementary col names:");
+		
+		supColNamesText = new Text(this.getExtendedParametersGroup(), SWT.BORDER);
+		
 		this.chartToolBar.pack();
 	}
 	
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/export/office/MergeExcelDirMacro.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/export/office/MergeExcelDirMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/export/office/MergeExcelDirMacro.groovy	(revision 3555)
@@ -0,0 +1,186 @@
+// Copyright © 2019 ENS de Lyon, CNRS, University of Franche-Comté
+// @author mdecorde
+// @author sheiden
+
+package org.txm.macro.office
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import java.nio.charset.Charset
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.utils.*
+import javax.xml.stream.*
+import java.net.URL
+
+import org.apache.poi.ss.usermodel.*
+import org.apache.poi.hssf.usermodel.*
+import org.apache.poi.xssf.usermodel.*
+import org.apache.poi.ss.util.*
+
+@Field @Option(name="inputDirectory", usage="dossier des fichiers Excel à fusionner", widget="Folder", required=true, def="")
+def inputDirectory
+
+@Field @Option(name="outputFile", usage="output file", widget="FileSave", required=true, def="")
+def outputFile
+
+@Field @Option(name="sheetName", usage="sheet name (if no name is given the first sheet will be used)", widget="String", required=false, def="")
+def sheetName
+
+@Field @Option(name="columnList", usage="list of columns to extract, separated by comma", widget="String", required=false, def="")
+def columnList
+
+@Field @Option(name="multipleValues", usage="list of columns with multiple values, separated by comma", widget="String", required=false, def="")
+def multipleValues
+
+@Field @Option(name="normalizeIdentifiers", usage="normalize column names to simple lower case letters", widget="Boolean", required=true, def="true")
+def normalizeIdentifiers
+
+def stringToIdent = { str -> org.txm.utils.AsciiUtils.buildAttributeId(org.txm.utils.AsciiUtils.convertNonAscii(str)).toLowerCase() }
+
+if (!ParametersDialog.open(this)) return false
+
+if (!inputDirectory.exists()) {
+	println "** $scriptName: no '"+inputDirectory.name+"' directory found. Aborting."
+	return false
+}
+
+if (!inputDirectory.canRead()) {
+	println "** $scriptName: '"+inputDirectory.name+"' directory not readable. Aborting."
+	return false
+}
+
+def aborted = false
+
+def scriptName = this.class.getSimpleName()
+
+columnList = columnList.split(",") as List
+
+println "columnList = "+columnList
+
+multipleValues = multipleValues.split(",") as List
+
+// create output file
+out = new FileOutputStream(outputFile)
+HSSFWorkbook wb = new HSSFWorkbook()
+finalSheet = wb.createSheet()
+
+// create header line
+nFinalRows = 1
+r = finalSheet.createRow(0)
+columnList.eachWithIndex { columnName, i ->
+	c = r.createCell(i)
+	c.setCellValue(normalizeIdentifiers?stringToIdent(columnName):columnName)
+}
+
+def f = []
+
+inputDirectory.eachFileMatch(~/.*\.xlsx/) { f << it }
+
+if (f.size() == 0) {
+	println "** $scriptName: no .xlsx file found. Aborting."
+	return false
+}
+
+debug = false
+//ConsoleProgressBar cpb = new ConsoleProgressBar(f.size())
+
+try {
+
+	// for each .xlsx input file (lexicographic order)
+	f.sort { it.name }.each { inputFile ->
+
+		if (aborted) return false
+
+		if (debug) println "Processing "+inputFile+"."
+		//cpb.tick()
+		rownum = 0
+
+		// open input sheet
+		wb2 = WorkbookFactory.create(inputFile)
+		ws = null
+		if (sheetName.length() == 0) {
+			ws = wb2.getSheetAt(0)
+		} else {
+			ws = wb2.getSheet(sheetName)
+			if (ws == null) {
+				println "** $scriptName: no '"+sheetName+" found. Aborting."
+				aborted = true
+				return false
+			}
+		}
+
+		if (ws == null) {
+			println "** $scriptName: no sheet found. Aborting."
+			aborted = true
+			return false
+		}
+
+		nRows = ws.getPhysicalNumberOfRows()
+		if (debug) println nRows+" rows."
+
+		// get columns positions
+		firstRow = ws.getRow(0)
+		nCols = firstRow.getPhysicalNumberOfCells()
+		def colNames = []
+		def cellIndexes = []
+		def multipleValuesCols = []
+		0.upto(nCols-1, { iCol ->
+			value = firstRow.getCell(iCol).getStringCellValue()
+			if (columnList.contains(value)) {
+				colNames << value
+				cellIndexes << iCol
+			}
+			if (multipleValues.contains(value)) {
+				multipleValuesCols << iCol
+			}
+		})
+
+		if (cellIndexes.size() != columnList.size()) {
+			columnList.removeAll(colNames)
+			println "** $scriptName: some columns missing in file $inputFile: "+columnList.join(", ")+". Aborting."
+
+			aborted = true
+			return false
+		}
+
+		// sort columns indexes by columnList parameter order
+		cellIndexes.sort { columnList.indexOf(colNames[cellIndexes.indexOf(it)]) }
+
+		// copy column values
+		1.upto(nRows-1, { iRow ->
+			row = ws.getRow(iRow)
+			r = finalSheet.createRow(nFinalRows)
+			
+			nCellCreated = 0
+			cellIndexes.each { iCol ->
+				value = row.getCell(iCol).getStringCellValue()
+				c = r.createCell(nCellCreated)
+				if (iCol in multipleValuesCols && value.size() > 0) {
+					(lstr = value.split(";")*.trim() as List).removeAll { it.isEmpty() }
+					c.setCellValue("|"+lstr.join("|")+"|")
+				} else {
+					c.setCellValue(value)
+				}
+				nCellCreated++
+			}
+			
+			nFinalRows++
+		})
+	}
+} catch(Exception e) {
+	aborted = true
+	return false
+}
+//cpb.done()
+
+/* write sheet */
+
+wb.write(out)
+out.close()
+
+if (aborted) return false
+
+println nFinalRows+" rows written."
+
+return true
+
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/export/office/SetOfficeMacro.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/export/office/SetOfficeMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/export/office/SetOfficeMacro.groovy	(revision 3555)
@@ -0,0 +1,43 @@
+// STANDARD DECLARATIONS
+package org.txm.macro.office
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+
+// BEGINNING OF PARAMETERS
+
+@Field @Option(name="office_path", usage="Path to LibreOffice or OpenOffice installation directory", widget="Folder", required=false, def="libreoffice or openoffice install directory")
+def office_path
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return;
+
+// END OF PARAMETERS
+
+if (office_path == null) {
+	println "No path to office directory given."
+	return
+}
+
+if (!office_path.exists()) {
+	println "'$office_path' directory not found."
+	return
+}
+
+if (!office_path.isDirectory()) {
+	println "'$office_path' exists but is not a directory."
+	return
+}
+
+if (!office_path.canExecute()) {
+	println "'$office_path' exists but has not sufficent rights to be used."
+	return
+}
+
+def old = System.getProperty("office.home")
+System.setProperty("office.home", office_path.getAbsolutePath())
+println "Office path set to '"+System.getProperty("office.home")+"'."
+if (old != null) {
+	println "	Previous path was '${old}'."
+}
\ No newline at end of file
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/CAStyleMacro.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/CAStyleMacro.groovy	(revision 3554)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/CAStyleMacro.groovy	(revision 3555)
@@ -1,463 +0,0 @@
-// STANDARD DECLARATIONS
-// @author mdecorde sjacquot sheiden
-package org.txm.macro
-
-import org.kohsuke.args4j.*
-import groovy.transform.Field
-import org.txm.rcpapplication.swt.widget.parameters.*
-import org.txm.searchengine.cqp.clientExceptions.*
-import org.txm.searchengine.cqp.corpus.*
-import org.txm.searchengine.cqp.corpus.query.*
-import org.apache.commons.lang.time.StopWatch
-import java.util.Arrays
-import org.jfree.chart.renderer.xy.*
-import org.jfree.chart.renderer.*
-import org.jfree.chart.plot.*
-import org.jfree.data.xy.*
-import org.jfree.chart.axis.*
-import java.awt.*;
-import java.awt.geom.*;
-import org.jfree.chart.labels.*
-
-import org.txm.ca.core.functions.CA
-import org.txm.ca.core.chartsengine.jfreechart.themes.highcharts.renderers.*
-import org.txm.ca.rcp.editors.*
-import org.txm.libs.office.ReadODS
-import org.txm.ca.core.chartsengine.jfreechart.datasets.*
-import org.jfree.chart.renderer.AbstractRenderer
-import java.awt.geom.Ellipse2D
-import org.jfree.chart.util.ShapeUtils
-
-
-println "editor: "+editor
-
-if (!(editor instanceof CAEditor)) {
-	println "editor is not a CA editor: $editor, Run the macro with F12 when the editor is selected :-)"
-	return
-}
-
-@Field @Option(name="patternsODSFile", usage="The starting word", widget="FileOpen", required=true, def='patterns.ods')
-def patternsODSFile
-@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
-debug
-
-// 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
-
-if (!patternsODSFile.exists()) {
-	println "Pattern file not found: $patternsODSFile"
-	return false;
-}
-if (!patternsODSFile.isFile() || !patternsODSFile.getName().toLowerCase().endsWith(".ods")) {
-	println "Wrong pattern file: $patternsODSFile"
-	return false;
-}
-
-def data = ReadODS.toTable(patternsODSFile, "rows")
-def keys = data[0]
-def row_styles = [:] // reformat data
-	for (int i = 1 ; i < data.size() ; i++) {
-		def h = data[i]
-		def style = [:] // create style entry
-		String s = h[0];
-		row_styles[/$s/] = style // with a regexp pattern as key
-				
-		// fill the style
-		for (int j = 1 ; j < h.size() ; j++) {
-			style[keys[j]] = h[j]
-		}
-	}
-if (debug > 0) {
-	println "ROW STYLES=$row_styles"
-}
-
-data = ReadODS.toTable(patternsODSFile, "cols")
-keys = data[0]
-def col_styles = [:] // reformat data
-
-for (int i = 1 ; i < data.size() ; i++) {
-	def h = data[i]
-	def style = [:] // create style entry
-	String s = h[0];
-	col_styles[/$s/] = style // with a regexp pattern as key
-					
-	// fill the style
-	for (int j = 1 ; j < h.size() ; j++) {
-		style[keys[j]] = h[j]
-	}
-}
-if (debug > 0) {
-	println "COL STYLES=$col_styles"
-}
-
-ica = editor.getCA()
-ca = ica.getCA()
-
-// http://txm.sourceforge.net/javadoc/TXM/TBX/org/txm/stat/engine/r/function/CA.html
-
-// SOME DATA
-rows = ica.getRowNames()
-rowsinfo = ica.getRowInfos()
-rowscos2 = ca.getRowCos2()
-cols = ica.getColNames()
-colssinfo = ica.getColInfos()
-colscos2 = ca.getColCos2()
-D1 = ica.getFirstDimension() -1;
-D2 = ica.getSecondDimension() -1;
-
-// create some AWT shapes for replacement
-shapes = new HashMap<String, Shape>();
-// dimensions scaling factor (the same used in default theme for the replaced shapes have same dimension than non-replaced)
-float itemShapesScalingFactor = 1.2f
-shapes["diamond"] = ShapeUtils.createDiamond((float)(itemShapesScalingFactor * 3.4f));
-shapes["square"] = AbstractRenderer.DEFAULT_SHAPE;
-
-float circleSize = 6.4f * itemShapesScalingFactor;
-shapes["disk"] = new Ellipse2D.Float((float)(-circleSize / 2), (float)(-circleSize / 2), circleSize, circleSize);
-
-shapes["triangle"] = ShapeUtils.createUpTriangle((float)(itemShapesScalingFactor * 3.2f));
-
-//shapes["star"] = AbstractRenderer.DEFAULT_SHAPE;
-//shapes["circle"] = AbstractRenderer.DEFAULT_SHAPE;
-
-
-println "SHAPES=$shapes"
-
-
-// styles per col index in dataset
-// set col label
-colLabelStyle = new HashMap<Integer, String>();
-// set col visibility
-colHiddenStyle = new HashSet<Integer>(); // true false
-// set col font size
-colFontSizeStyle = new HashMap<Integer, Float>();
-// set col font color
-colFontColorStyle = new HashMap<Integer, Color>();
-// set col font family
-colFontFamilyStyle = new HashMap<Integer, String>();
-// set col points size
-colPointSizeStyle = new HashMap<Integer, Double>();
-// set col points RGBA color
-colPointColorStyle = new HashMap<Integer, Color>();
-// set col points shape (circle, square, triangle, ... + color ? + size ?) -> expert
-colPointShapeStyle = new HashMap<Integer, Shape>(); // circle, square, triangle, etc.
-// set col font style (1 = bold, 2 = italic, 3 = bold + italic)
-colFontStyleStyle = new HashMap<Integer, Integer>();
-
-
-// set row label
-rowLabelStyle = new HashMap<Integer, String>();
-// set row visibility
-rowHiddenStyle = new HashSet<Integer>(); // true false
-// set row font size
-rowFontSizeStyle = new HashMap<Integer, Float>();
-// set row font size
-rowFontColorStyle = new HashMap<Integer, Color>();
-// set row font size
-rowFontFamilyStyle = new HashMap<Integer, String>();
-// set row points size
-rowPointSizeStyle = new HashMap<Integer, Double>();
-// set row points RGBA color
-rowPointColorStyle = new HashMap<Integer, Color>();
-// set row points shape (circle, square, triangle, ... + color ? + size ?) -> expert
-rowPointShapeStyle = new HashMap<Integer, Shape>(); // circle, square, triangle, etc.
-// set row font style (1 = bold, 2 = italic, 3 = bold + italic)
-rowFontStyleStyle = new HashMap<Integer, Integer>();
-
-// prepare col style data for the dataset
-for (int i = 0 ; i < cols.length ; i++) {
-	for (def p : col_styles.keySet()) {
-		if (cols[i] ==~ p) {
-			def style = col_styles[p]
-			if (style["label-replacement"] != null && style["label-replacement"].length() > 0) {
-				colLabelStyle[i] = style["label-replacement"]
-			}
-			if (style["hidden"] != null && style["hidden"].toUpperCase() == "T") {
-				colHiddenStyle << i
-			}
-			if (style["shape-size"] != null && style["shape-size"].length() > 0) {
-				colPointSizeStyle[i] = Double.parseDouble(style["shape-size"])
-			}
-			if (style["shape-color"] != null && style["shape-color"].length() > 0 ) {
-				colPointColorStyle[i] = rgbaStringToColor(style["shape-color"])
-			}
-			if (style["shape-replacement"] != null && shapes.containsKey(style["shape-replacement"])) {
-				colPointShapeStyle[i] = shapes[style["shape-replacement"]]
-			}
-			if (style["label-size"] != null && style["label-size"].length() > 0) {
-				colFontSizeStyle[i] = Float.parseFloat(style["label-size"])
-			}
-			if (style["label-color"] != null && style["label-color"].length() > 0) {
-				colFontColorStyle[i] = rgbaStringToColor(style["label-color"])
-			}
-			if (style["label-font-family"] != null && style["label-font-family"].length() > 0) {
-				colFontFamilyStyle[i] = style["label-font-family"]
-			}
-			if (style["label-style"] != null && style["label-style"].length() > 0) {
-				colFontStyleStyle[i] = Integer.parseInt(style["label-style"])
-			}
-			
-		}
-	}
-}
-if (debug > 0) {
-	println "COL COL=$colPointColorStyle"
-	println "COL SHP=$colPointShapeStyle"
-	println "COL LAB=$colLabelStyle"
-	println "COL FONT-SIZ=$colFontSizeStyle"
-	println "COL SIZ=$colPointSizeStyle"
-	println "COL VIZ=$colHiddenStyle"
-	println "COL STYLE=$colFontStyleStyle"
-}
-
-// prepare row style data for the dataset
-for (int i = 0 ; i < rows.length ; i++) {
-	for (def p : row_styles.keySet()) {
-		if (rows[i] ==~ p) {
-			def style = row_styles[p]
-			if (style["hidden"] != null && style["hidden"].toUpperCase() == "T") {
-				rowHiddenStyle << i
-			}
-			if (style["label-replacement"] != null && style["label-replacement"].length() > 0) {
-				rowLabelStyle[i] = style["label-replacement"]
-			}
-			if (style["shape-size"] != null && style["shape-size"].length() > 0) {
-				rowPointSizeStyle[i] = Double.parseDouble(style["shape-size"])
-			}
-			if (style["shape-color"] != null && style["shape-color"].length() > 0 ) {
-				rowPointColorStyle[i] = rgbaStringToColor(style["shape-color"])
-			}
-			if (style["shape-replacement"] != null && shapes.containsKey(style["shape-replacement"])) {
-				rowPointShapeStyle[i] = shapes[style["shape-replacement"]]
-			}
-			if (style["label-size"] != null && style["label-size"].length() > 0) {
-				rowFontSizeStyle[i] = Float.parseFloat(style["label-size"])
-			}
-			if (style["label-color"] != null && style["label-color"].length() > 0) {
-				rowFontColorStyle[i] = rgbaStringToColor(style["label-color"])
-			}
-			if (style["label-font-family"] != null && style["label-font-family"].length() > 0) {
-				rowFontFamilyStyle[i] = style["label-font-family"]
-			}
-			if (style["label-style"] != null && style["label-style"].length() > 0) {
-				rowFontStyleStyle[i] = Integer.parseInt(style["label-style"])
-			}
-		}
-	}
-}
-if (debug > 0) {
-	println "ROW COL=$rowPointColorStyle"
-	println "ROW SHP=$rowPointShapeStyle"
-	println "ROW LAB=$rowLabelStyle"
-	println "ROW FONT-SIZ=$rowFontSizeStyle"
-	println "ROW SIZ=$rowPointSizeStyle"
-	println "ROW VIZ=$rowHiddenStyle"
-	println "ROW STYLE=$rowFontStyleStyle"
-}
-
-
-
-// Redefine the chart renderer and update the chart
-def chartEditor = editor.getEditors()[0]
-def chartComposite = chartEditor.getComposite()
-
-ddebug = debug
-monitor.syncExec( new Runnable() {
-
-	public void run() {
-		println chartComposite
-		def chart = chartEditor.getChart()
-		
-		/*
-		println "chart: "+chart
-		println "Plot: "+chart.getPlot()
-		println "Dataset: "+chart.getPlot().getDataset()
-		println "Renderer 1: "+chart.getPlot().getRenderer()
-		 */
-		
-		def renderer = new CAItemSelectionRenderer(ica, chart) {
-			Area EMPTYAREA = new Area()
-					
-					@Override
-					public void initItemLabelGenerator() {
-					XYItemLabelGenerator generator = new XYItemLabelGenerator() {
-					
-					@Override
-					public String generateLabel(XYDataset dataset, int series, int item) {
-						if (series == 0 && rowHiddenStyle.contains(item)) {
-							if (ddebug > 1) println "HIDDING ROW LABEL '$item' '${rows[item]}'"
-							return ""
-						} else if (series == 1 && colHiddenStyle.contains(item)) {
-							if (ddebug > 1) println "HIDDING COL LABEL '$item' '${cols[item]}'"
-							return ""
-						} else if (series == 0 && rowLabelStyle.containsKey(item)) {
-							if (ddebug > 1) println "RENAME ROW LABEL '$item' '${rows[item]}' -> '${rowLabelStyle[item]}'"
-							return rowLabelStyle[item]
-						} else if (series == 1 && colLabelStyle.containsKey(item)) {
-							if (ddebug > 1) println "RENAME COL LABEL '$item' '${cols[item]}' -> '${colLabelStyle[item]}'"
-							return colLabelStyle[item]
-						} else {
-							CAXYDataset caDataset = (CAXYDataset) dataset;
-							return caDataset.getLabel(series, item);
-						}
-					}
-				};
-				
-				// don't use setBaseItemLabelGenerator BUT setDefaultItemLabelGenerator
-				this.setDefaultItemLabelGenerator(generator);
-				this.setDefaultItemLabelsVisible(true);
-			}
-			
-			
-			
-			@Override
-			public Font getItemLabelFont(int series, int item) {
-				Font d = super.getItemLabelFont(series, item);
-				Integer style = d.getStyle();
-				Integer size = d.getSize();
-				String family = d.getFontName();
-				
-				// size
-				if (series == 0 && rowFontSizeStyle.containsKey(item)) {
-					if (ddebug > 1) println "FIX ROW FONT-SIZE $item ${rows[item]} -> ${rowFontSizeStyle[item]}"
-					size *= rowFontSizeStyle[item];
-				} else if (series == 1 && colFontSizeStyle.containsKey(item)) {
-					if (ddebug > 1) println "FIX COL FONT-SIZE $item ${cols[item]} -> ${colFontSizeStyle[item]}"
-					size *= colFontSizeStyle[item];
-				}
-				
-				// family
-				if (series == 0 && rowFontFamilyStyle.containsKey(item)) {
-					if (ddebug > 1) println "FIX ROW FONT-Family $item ${rows[item]} -> ${rowFontFamilyStyle[item]}"
-					family = rowFontFamilyStyle[item];
-				} else if (series == 1 && colFontFamilyStyle.containsKey(item)) {
-					if (ddebug > 1) println "FIX COL FONT-Family $item ${cols[item]} -> ${colFontFamilyStyle[item]}"
-					family = colFontFamilyStyle[item];
-				}
-				
-				// style
-				if (series == 0 && rowFontStyleStyle.containsKey(item)) {
-					if (ddebug > 1) println "FIX ROW FONT-Style $item ${rows[item]} -> ${rowFontStyleStyle[item]}"
-					style = rowFontStyleStyle[item];
-				} else if (series == 1 && colFontFamilyStyle.containsKey(item)) {
-					if (ddebug > 1) println "FIX COL FONT-Style $item ${cols[item]} -> ${colFontStyleStyle[item]}"
-					style = colFontStyleStyle[item];
-				}
-				
-				
-				return new Font(family, style, size);
-			}
-			
-			
-			@Override
-			public Shape getItemShape(int series, int item) {
-				// Rows (series == 0), Cols (series == 1)
-				if (series == 0 && rowHiddenStyle.contains(item)) {
-					return EMPTYAREA;
-				} else if (series == 1 && colHiddenStyle.contains(item)) {
-					return EMPTYAREA;
-				} else {
-					
-					Shape shape =  super.getItemShape(series, item);
-					
-					// not-visible shapes mode
-					if(!((CA) this.multipleItemsSelector.getResult()).isShowPointShapes())        {
-						return shape;
-					}
-					
-					// shape replacement
-					if (series == 0 && rowPointShapeStyle.containsKey(item)) {
-						if (ddebug > 1) println "FIX ROW SHAPE $item ${rows[item]} -> ${rowPointShapeStyle[item]}"
-						shape = rowPointShapeStyle.get(item);
-					} else if (series == 1 && colPointShapeStyle.containsKey(item)) {
-						if (ddebug > 1) println "FIX COL SHAPE $item ${cols[item]} -> ${colPointShapeStyle[item]}"
-						shape = colPointShapeStyle.get(item);
-					}
-					
-					
-					// shape scaling
-					AffineTransform t = new AffineTransform();
-					if (series == 0 && rowPointSizeStyle.containsKey(item)) {
-						if (ddebug > 1) println "FIX ROW POINT SIZE $item ${rows[item]} -> ${rowPointSizeStyle[item]}"
-						t.setToScale(rowPointSizeStyle.get(item), rowPointSizeStyle.get(item));
-						shape = t.createTransformedShape(shape);
-					} else if (series == 1 && colPointSizeStyle.containsKey(item)) {
-						if (ddebug > 1) println "FIX COL POINT SIZE $item ${cols[item]} -> ${colPointSizeStyle[item]}"
-						t.setToScale(colPointSizeStyle.get(item), colPointSizeStyle.get(item));
-						shape = t.createTransformedShape(shape);
-					}
-					
-					return shape;
-				}
-			}
-			
-			
-			@Override
-			public Paint getItemPaint(int series, int item) {
-				
-				// visible shapes mode
-				if (!((CA) this.multipleItemsSelector.getResult()).isShowPointShapes()) {
-					return super.getItemPaint(series, item);
-				}
-				
-				if (series == 0 && rowPointColorStyle.containsKey(item)) {
-					if (ddebug > 1) println "FIX ROW POINT COLOR $item ${rows[item]} -> ${rowPointColorStyle[item]}"
-					return rowPointColorStyle.get(item);
-				} else if (series == 1 && colPointColorStyle.containsKey(item)) {
-					if (ddebug > 1) println "FIX COL POINT COLOR $item ${cols[item]} -> ${colPointColorStyle[item]}"
-					return colPointColorStyle.get(item);
-				}
-				else {
-					return super.getItemPaint(series, item);
-				}
-			}
-			
-			
-			@Override
-			public Paint getItemLabelPaint(int series, int item) {
-				if (series == 0 && rowFontColorStyle.containsKey(item)) {
-					if (ddebug > 1) println "FIX ROW LABEL COLOR $item ${rows[item]} -> ${rowFontColorStyle[item]}"
-					return rowFontColorStyle.get(item);
-				} else if (series == 1 && colFontColorStyle.containsKey(item)) {
-					if (ddebug > 1) println "FIX COL LABEL COLOR $item ${cols[item]} -> ${colFontColorStyle[item]}"
-					return colFontColorStyle.get(item);
-				} else {
-					return super.getItemLabelPaint(series, item);
-				}
-			}
-			
-		};
-		
-		
-		def cp = editor.editors[0].getChart();
-		renderer.chart = cp // SJ: seems useless
-		renderer.setSeriesVisible(0, ica.isShowVariables()); // Rows  // SJ: seems useless
-		renderer.setSeriesVisible(1, ica.isShowIndividuals()); // Columns  // SJ: seems useless
-		chart.getXYPlot().setRenderer(renderer)
-		
-		ica.getChartCreator().updateChart(chartEditor.getResult())
-		
-	}
-});
-
-
-
-
-// creates a Color object from the specified RGB or RGBA string representation separated by spaces ("R G B" or "R G B A") from 0 to 255 for each channel
-def rgbaStringToColor(String color) {
-	String[] rgbColor = color.split(" ");
-	String alpha = "255";
-	if(rgbColor.length > 2) {
-		if(rgbColor.length > 3) {
-			alpha = rgbColor[3];
-		}
-		return new Color(Integer.parseInt(rgbColor[0]), Integer.parseInt(rgbColor[1]), Integer.parseInt(rgbColor[2]), Integer.parseInt(alpha))
-	}
-	else {
-		println "Error in color format for RGB or RGBA string: $color"
-	}
-}
-
-
-
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/CAFilter.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/CAFilter.groovy	(revision 3554)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/CAFilter.groovy	(revision 3555)
@@ -1,301 +0,0 @@
-// STANDARD DECLARATIONS
-package org.txm.macro
-
-import org.kohsuke.args4j.*
-import groovy.transform.Field
-import org.txm.rcpapplication.swt.widget.parameters.*
-import org.txm.searchengine.cqp.clientExceptions.*
-import org.txm.searchengine.cqp.corpus.*
-import org.txm.searchengine.cqp.corpus.query.*
-import org.apache.commons.lang.time.StopWatch
-import java.util.Arrays
-import org.jfree.chart.renderer.xy.*
-import org.jfree.chart.renderer.*
-import org.jfree.chart.plot.*
-import org.jfree.data.xy.*
-import org.jfree.chart.axis.*
-import java.awt.*;
-import java.awt.geom.*;
-import org.jfree.chart.labels.*
-
-import org.txm.ca.core.chartsengine.jfreechart.themes.highcharts.renderers.*
-import org.txm.ca.rcp.editors.*
-import org.txm.libs.office.ReadODS
-import org.txm.ca.core.chartsengine.jfreechart.datasets.*
-import org.jfree.chart.renderer.AbstractRenderer
-
-import org.apache.commons.math3.stat.descriptive.*
-
-println "editor: "+editor
-
-if (!(editor instanceof CAEditor)) {
-	println "editor is not a CA editor: $editor, Run the macro with F12 when the editor is selected :-)"
-	return
-}
-
-def chartEditor = editor.getEditors()[0]
-def chartComposite = chartEditor.getComposite()
-
-// BEGINNING OF PARAMETERS
-
-// Declare each parameter here
-// (available widget types: Query, File, Folder, String, Text, Boolean, Integer, Float and Date)
-
-//@Field @Option(name="query", usage="an example query", widget="Query", required=true, def='[pos="V.*"]')
-//def query
-
-//@Field @Option(name="file", usage="an example file", widget="File", required=true, def="C:/Temp/foo.txt")
-//def file
-
-//@Field @Option(name="folder", usage="an example folder", widget="Folder", required=false, def="C:/Temp")
-//def folder
-
-//@Field @Option(name="date", usage="an example date", widget="Date", required=false, def="1984-09-01")
-//def date
-
-//@Field @Option(name="integer", usage="an example integer", widget="Integer", required=false, def="42")
-//def integer
-
-@Field @Option(name="QMin", usage="min Q", widget="Float", required=true, def="0.01")
-def QMin
-
-@Field @Option(name="CTRXMin", usage="min CTR X", widget="Float", required=true, def="0.001")
-def CTRXMin
-
-@Field @Option(name="CTRYMin", usage="min CTR Y", widget="Float", required=true, def="0.001")
-def CTRYMin
-
-@Field @Option(name="stackX", usage="stack X", widget="Float", required=true, def="0.0")
-def stackX
-
-@Field @Option(name="stackY", usage="stack Y", widget="Float", required=true, def="0.0")
-def stackY
-
-//@Field @Option(name="string", usage="an example string", widget="String", required=false, def="hello world!")
-//def string
-
-@Field @Option(name="regexFilter", usage="row property form regex", widget="Text", required=false, def="")
-def regexFilter
-
-@Field @Option(name="debug", usage="debug (verbose) mode", widget="Boolean", required=true, def="true")
-def debug
-
-// La fenêtre de résultats
-CAresultWindow = editor
-
-// Le tableau de données d'aide à l'interprétation
-// Les données de l'AFC sont manipulables par les méthodes documentées ici http://txm.sourceforge.net/javadoc/TXM/TBX/org/txm/stat/engine/r/function/CA.html
-
-ica = CAresultWindow.getCA()
-ca = ica.getCA()
-
-rowNames = ica.getRowNames()
-rowCos2 = ca.getRowCos2()
-rowContrib = ca.getRowContrib()
-
-colNames = ica.getColNames()
-colCos2 = ca.getColCos2()
-colContrib = ca.getColContrib()
-
-F1 = ica.getFirstDimension()-1
-F2 = ica.getSecondDimension()-1
-
-println sprintf("F1 = %d, F2 = %d, %d initial rows, %d initial cols", F1+1, F2+1, rowNames.length, colNames.length)
-
-def stats = { vector, factor ->
-	s = new DescriptiveStatistics()
-	(vector.length).times {
-		s.addValue(vector[it][factor]);
-	}
-
-	println "min       quartile  median    third quartile  max"
-	println sprintf("%8f  %8f  %8f  %8f        %8f", s.getMin(), s.getPercentile(25), s.getPercentile(50), s.getPercentile(75), s.getMax())
-}
-
-// rows
-
-println "ROWS -----"
-println "CTR"+(F1+1)
-stats(rowContrib, F1)
-
-println "CTR"+(F2+1)
-stats(rowContrib, F2)
-
-println "Cos² "+(F1+1)
-stats(rowCos2, F1)
-
-println "Cos² "+(F2+1)
-stats(rowCos2, F2)
-
-// cols
-
-println "COLS -----"
-println "CTR"+(F1+1)
-stats(colContrib, F1)
-
-println "CTR"+(F2+1)
-stats(colContrib, F2)
-
-println "Cos² "+(F1+1)
-stats(colCos2, F1)
-
-println "Cos² "+(F2+1)
-stats(colCos2, F2)
-
-
-def stats2 = { vector, factor1, factor2 ->
-	s = new DescriptiveStatistics()
-	(vector.length).times {
-		s.addValue(vector[it][factor1]+vector[it][factor2]);
-	}
-
-	println "min       quartile  median    third quartile  max"
-	println sprintf("%8f  %8f  %8f  %8f        %8f", s.getMin(), s.getPercentile(25), s.getPercentile(50), s.getPercentile(75), s.getMax())
-}
-
-println "Q"+(F1+1)+(F2+1)
-stats2(rowCos2, F1, F2)
-
-println "Q"+(F1+1)+(F2+1)
-stats2(colCos2, F1, F2)
-
-// Open the parameters input dialog box
-if (!ParametersDialog.open(this)) return
-
-// END OF PARAMETERS
-
-
-filteredRows = []
-
-println ""
-
-if (debug) println "\nROWS -----"
-
-if (regexFilter.length() > 0) {
-	nmatched = 0
-	rowNames.each { it ->
-		if (it ==~ regexFilter) {
-			if (debug && !filteredRows.contains(it)) {
-				if (nmatched > 0) print ", "
-				print it
-			}
-			filteredRows << it
-			nmatched++
-		}
-	}
-
-	if (debug && nmatched > 0) println ""
-
-	if (debug) {
-		println sprintf("\n%d rows filtered by regex", nmatched)
-	}
-
-}
-
-nQCTR = 0
-rowNames.eachWithIndex { it, i ->
-	def cos2 = rowCos2[i]
-	if ((rowContrib[i][F1] < CTRXMin) && (rowContrib[i][F2] < CTRYMin) && (cos2[F1] + cos2[F2] < QMin)) {
-		if (debug && !filteredRows.contains(rowNames[i])) {
-			if (nQCTR > 0) print ", "
-			print rowNames[i]
-		}
-		filteredRows << rowNames[i]
-		nQCTR++
-	}
-}
-
-if (debug) {
-	println sprintf("\n%d rows filtered by CTR or Q"+(F1+1)+(F2+1), nQCTR)
-}
-
-// cols
-
-filteredCols = []
-
-println ""
-
-if (debug) println "\nCOLS -----"
-
-if (regexFilter.length() > 0) {
-	nmatched = 0
-	colNames.each { it ->
-		if (it ==~ regexFilter) {
-			if (debug && !filteredCols.contains(it)) {
-				if (nmatched > 0) print ", "
-				print it
-			}
-			filteredCols << it
-			nmatched++
-		}
-	}
-
-	if (debug && nmatched > 0) println ""
-
-	if (debug) {
-		println sprintf("\n%d cols filtered by regex", nmatched)
-	}
-
-}
-
-nQCTR = 0
-colNames.eachWithIndex { it, i ->
-	def cos2 = colCos2[i]
-	if (!((colContrib[i][F1] > CTRXMin) || (colContrib[i][F2] > CTRYMin) || (cos2[F1] + cos2[F2] > QMin))) {
-		if (debug && !filteredCols.contains(colNames[i])) {
-			if (nQCTR > 0) print ", "
-			print colNames[i]
-		}
-		filteredCols << colNames[i]
-		nQCTR++
-	}
-}
-
-if (debug) {
-	println sprintf("\n%d cols filtered by CTR or Q"+(F1+1)+(F2+1), nQCTR)
-}
-
-double stackXv = stackX
-double stackYv = stackY
-
-
-// Visualisation graphique
-
-chartCAresultWindow = CAresultWindow.getEditors()[0]
-chartComposite = chartCAresultWindow.getComposite()
-
-monitor.syncExec( new Runnable() {
-	public void run() {
-
-				println chartComposite
-				def chart = chartEditor.getChart();
-
-				dataset2 = new CAXYDataset(ica)
-				
-				labels = dataset2.rowLabels
-				coords = dataset2.rowCoordinates
-				(labels.length).times {
-					if (filteredRows.contains(labels[it])) {
-						println "Moving "+labels[it]+" row to origin."
-						labels[it] = ""
-						coords[it][F1] = stackXv
-						coords[it][F2] = stackYv
-					}
-				}
-				labels = dataset2.columnLabels
-				coords = dataset2.columnCoordinates
-				(labels.length).times {
-					if (filteredCols.contains(labels[it])) {
-						println "Moving "+labels[it]+" col to origin."
-						labels[it] = ""
-						coords[it][F1] = stackXv
-						coords[it][F2] = stackYv
-					}
-				}
-
-				chart.getXYPlot().setDataset(dataset2)
-
-				ica.getChartCreator().getChartsEngine().getJFCTheme().apply(chart); // need to be call AFTER setRenderer() cause this method changes some renderering parameters
-				chartComposite.loadChart()
-			}
-})
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/InvertCAXAxisMacro.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/InvertCAXAxisMacro.groovy	(revision 3554)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/InvertCAXAxisMacro.groovy	(revision 3555)
@@ -1,125 +0,0 @@
-// @author Sebastien Jacquot
-// STANDARD DECLARATIONS
-package org.txm.macro
-
-
-import org.kohsuke.args4j.*
-import groovy.transform.Field
-import org.txm.rcpapplication.swt.widget.parameters.*
-import org.txm.searchengine.cqp.clientExceptions.*
-import org.txm.searchengine.cqp.corpus.*
-import org.txm.searchengine.cqp.corpus.query.*
-import org.apache.commons.lang.time.StopWatch
-import java.util.Arrays
-import org.jfree.chart.renderer.xy.*
-import org.jfree.chart.renderer.*
-import org.jfree.chart.plot.*
-import org.jfree.data.xy.*
-import org.jfree.chart.axis.*
-import java.awt.*;
-import java.awt.geom.*;
-import org.jfree.chart.labels.*
-
-import org.txm.ca.core.chartsengine.jfreechart.themes.highcharts.renderers.*
-import org.txm.ca.rcp.editors.*
-import org.txm.libs.office.ReadODS
-import org.txm.ca.core.chartsengine.jfreechart.datasets.*
-import org.jfree.chart.renderer.AbstractRenderer
-
-println "editor: "+editor
-
-if (!(editor instanceof CAEditor)) {
-	println "editor is not a CA editor: $editor, Run the macro with F12 when the editor is selected :-)"
-	return
-}
-
-ica = editor.getCA();
-chart = ica.getChart();
-plot = chart.getXYPlot();
-dataset = plot.getDataset(); 
-
-// overrides some dataset methods to return inverted X coordinates for columns and rows
-plot.setDataset(new CAXYDataset(ica) {
-
-        public Number getX(int series, int item) {
-                if(item == -1)        {
-                        System.out.println("CAXYDataset.getX()");
-                }
-                // Rows
-                if(series == 0) {
-                        return -this.rowCoordinates[item][this.axis1];
-                }
-                // Cols
-                else {
-                        return -this.columnCoordinates[item][this.axis1];
-                }
-        }
-        
-        
-         
-        /**
-         * Gets the minimum value in the specified series according to the specified axis.
-         * @param series
-         * @param axis
-         * @return
-         */
-        public double getMinValue(int series, int axis)        {
-                double minValue = 0;
-                double tmpMinValue;
-                double[][] coordinates = this.rowCoordinates;
-                if(series != 0)        {
-                        coordinates = this.columnCoordinates;
-                }
-                
-                for(int i = 0; i < coordinates.length; i++) {
-                        tmpMinValue = coordinates[i][axis];
-                        
-						// invert X coordinate
-                		if(axis == 0)        {
-                			tmpMinValue = -tmpMinValue;
-                		}
-                        
-                        if(tmpMinValue < minValue)        {
-                                minValue = tmpMinValue;
-                        }
-                }
-                
-                return minValue;
-        }
-        
-        /**
-         * Gets the maximum value in the specified series according to the specified axis.
-         * @param series
-         * @param axis
-         * @return
-         */
-        public double getMaxValue(int series, int axis)        {
-                double maxValue = 0;
-                double tmpMaxValue;
-                double[][] coordinates = this.rowCoordinates;
-                if(series != 0)        {
-                        coordinates = this.columnCoordinates;
-                }
-                
-                for(int i = 0; i < coordinates.length; i++) {
-                        tmpMaxValue = coordinates[i][axis];
-                        
-						// invert X coordinate
-                		if(axis == 0)        {
-                			tmpMaxValue = -tmpMaxValue;
-                		}
-                        
-                        if(tmpMaxValue > maxValue)        {
-                                maxValue = tmpMaxValue;
-                        }
-                }
-                
-                return maxValue;
-        }
-}
-);
-
-// update the limits dotted borders
-ica.getChartCreator().createCAFactorialMapChartLimitsBorder(chart);
-
-
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/PlotEllipsesMacro.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/PlotEllipsesMacro.groovy	(revision 3554)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/PlotEllipsesMacro.groovy	(revision 3555)
@@ -1,36 +0,0 @@
-// STANDARD DECLARATIONS
-package org.txm.macro
-
-import org.txm.ca.core.functions.CA
-import org.txm.statsengine.r.core.RWorkspace
-import groovy.transform.Field
-// BEGINNING OF PARAMETERS
-
-if (!(corpusViewSelection instanceof CA)) {
-	println "Selection is not a CA. Please select a CA result in the Corpus view"
-	return;
-}
-
-def ca = corpusViewSelection
-
-@Field @Option(name="outputFile", usage="an example file", widget="FileSave", required=true, def="file.svg")
-def outputFile
-
-@Field @Option(name="draw", usage="'row' or 'col'", widget="String", required=true, def="row")
-def draw
-// Open the parameters input dialog box
-if (!ParametersDialog.open(this)) return;
-
-// END OF PARAMETERS
-
-def s = ca.getRSymbol()
-def RW = RWorkspace.getRWorkspaceInstance()
-
-def script = """
-plot($s);
-ellipseCA($s, ellipse=c("$draw"));
-"""
-
-RW.plot(outputFile, script);
-
-println "Done: "+outputFile.getAbsolutePath()
\ No newline at end of file
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/.~lock.clearPattern.ods#
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/.~lock.clearPattern.ods#	(revision 0)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/.~lock.clearPattern.ods#	(revision 3555)
@@ -0,0 +1 @@
+,mdecorde,L107533,14.10.2022 11:02,file:///home/mdecorde/.config/libreoffice/4;
\ No newline at end of file
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/resultPattern.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/resultPattern.ods
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/.~lock.resultPattern.ods#
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/.~lock.resultPattern.ods#	(revision 0)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/.~lock.resultPattern.ods#	(revision 3555)
@@ -0,0 +1 @@
+,mdecorde,L107533,14.10.2022 11:05,file:///home/mdecorde/.config/libreoffice/4;
\ No newline at end of file
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/clearPattern.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/prototypes/stats/clearPattern.ods
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/CAStyleMacro.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/CAStyleMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/CAStyleMacro.groovy	(revision 3555)
@@ -0,0 +1,463 @@
+// STANDARD DECLARATIONS
+// @author mdecorde sjacquot sheiden
+package org.txm.macro.stats
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.searchengine.cqp.clientExceptions.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.*
+import org.apache.commons.lang.time.StopWatch
+import java.util.Arrays
+import org.jfree.chart.renderer.xy.*
+import org.jfree.chart.renderer.*
+import org.jfree.chart.plot.*
+import org.jfree.data.xy.*
+import org.jfree.chart.axis.*
+import java.awt.*;
+import java.awt.geom.*;
+import org.jfree.chart.labels.*
+
+import org.txm.ca.core.functions.CA
+import org.txm.ca.core.chartsengine.jfreechart.themes.highcharts.renderers.*
+import org.txm.ca.rcp.editors.*
+import org.txm.libs.office.ReadODS
+import org.txm.ca.core.chartsengine.jfreechart.datasets.*
+import org.jfree.chart.renderer.AbstractRenderer
+import java.awt.geom.Ellipse2D
+import org.jfree.chart.util.ShapeUtils
+
+
+println "editor: "+editor
+
+if (!(editor instanceof CAEditor)) {
+	println "editor is not a CA editor: $editor, Run the macro with F12 when the editor is selected :-)"
+	return
+}
+
+@Field @Option(name="patternsODSFile", usage="The starting word", widget="FileOpen", required=true, def='patterns.ods')
+def patternsODSFile
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+debug
+
+// 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
+
+if (!patternsODSFile.exists()) {
+	println "Pattern file not found: $patternsODSFile"
+	return false;
+}
+if (!patternsODSFile.isFile() || !patternsODSFile.getName().toLowerCase().endsWith(".ods")) {
+	println "Wrong pattern file: $patternsODSFile"
+	return false;
+}
+
+def data = ReadODS.toTable(patternsODSFile, "rows")  // read from the "rows" sheet
+def keys = data[0]
+def row_styles = [:] // reformat data
+	for (int i = 1 ; i < data.size() ; i++) {
+		def h = data[i]
+		def style = [:] // create style entry
+		String s = h[0];
+		row_styles[/$s/] = style // with a regexp pattern as key
+				
+		// fill the style
+		for (int j = 1 ; j < h.size() ; j++) {
+			style[keys[j]] = h[j]
+		}
+	}
+if (debug > 0) {
+	println "ROW STYLES=$row_styles"
+}
+
+data = ReadODS.toTable(patternsODSFile, "cols") // read from the "cols" sheet
+keys = data[0]
+def col_styles = [:] // reformat data
+
+for (int i = 1 ; i < data.size() ; i++) {
+	def h = data[i]
+	def style = [:] // create style entry
+	String s = h[0];
+	col_styles[/$s/] = style // with a regexp pattern as key
+					
+	// fill the style
+	for (int j = 1 ; j < h.size() ; j++) {
+		style[keys[j]] = h[j]
+	}
+}
+if (debug > 0) {
+	println "COL STYLES=$col_styles"
+}
+
+ica = editor.getCA()
+ca = ica.getCA()
+
+// http://txm.sourceforge.net/javadoc/TXM/TBX/org/txm/stat/engine/r/function/CA.html
+
+// SOME DATA
+rows = ica.getRowNames()
+rowsinfo = ica.getRowInfos()
+rowscos2 = ca.getRowCos2()
+cols = ica.getColNames()
+colssinfo = ica.getColInfos()
+colscos2 = ca.getColCos2()
+D1 = ica.getFirstDimension() -1;
+D2 = ica.getSecondDimension() -1;
+
+// create some AWT shapes for replacement
+shapes = new HashMap<String, Shape>();
+// dimensions scaling factor (the same used in default theme for the replaced shapes have same dimension than non-replaced)
+float itemShapesScalingFactor = 1.2f
+shapes["diamond"] = ShapeUtils.createDiamond((float)(itemShapesScalingFactor * 3.4f));
+shapes["square"] = AbstractRenderer.DEFAULT_SHAPE;
+
+float circleSize = 6.4f * itemShapesScalingFactor;
+shapes["disk"] = new Ellipse2D.Float((float)(-circleSize / 2), (float)(-circleSize / 2), circleSize, circleSize);
+
+shapes["triangle"] = ShapeUtils.createUpTriangle((float)(itemShapesScalingFactor * 3.2f));
+
+//shapes["star"] = AbstractRenderer.DEFAULT_SHAPE;
+//shapes["circle"] = AbstractRenderer.DEFAULT_SHAPE;
+
+
+println "SHAPES=$shapes"
+
+
+// styles per col index in dataset
+// set col label
+colLabelStyle = new HashMap<Integer, String>();
+// set col visibility
+colHiddenStyle = new HashSet<Integer>(); // true false
+// set col font size
+colFontSizeStyle = new HashMap<Integer, Float>();
+// set col font color
+colFontColorStyle = new HashMap<Integer, Color>();
+// set col font family
+colFontFamilyStyle = new HashMap<Integer, String>();
+// set col points size
+colPointSizeStyle = new HashMap<Integer, Double>();
+// set col points RGBA color
+colPointColorStyle = new HashMap<Integer, Color>();
+// set col points shape (circle, square, triangle, ... + color ? + size ?) -> expert
+colPointShapeStyle = new HashMap<Integer, Shape>(); // circle, square, triangle, etc.
+// set col font style (1 = bold, 2 = italic, 3 = bold + italic)
+colFontStyleStyle = new HashMap<Integer, Integer>();
+
+
+// set row label
+rowLabelStyle = new HashMap<Integer, String>();
+// set row visibility
+rowHiddenStyle = new HashSet<Integer>(); // true false
+// set row font size
+rowFontSizeStyle = new HashMap<Integer, Float>();
+// set row font size
+rowFontColorStyle = new HashMap<Integer, Color>();
+// set row font size
+rowFontFamilyStyle = new HashMap<Integer, String>();
+// set row points size
+rowPointSizeStyle = new HashMap<Integer, Double>();
+// set row points RGBA color
+rowPointColorStyle = new HashMap<Integer, Color>();
+// set row points shape (circle, square, triangle, ... + color ? + size ?) -> expert
+rowPointShapeStyle = new HashMap<Integer, Shape>(); // circle, square, triangle, etc.
+// set row font style (1 = bold, 2 = italic, 3 = bold + italic)
+rowFontStyleStyle = new HashMap<Integer, Integer>();
+
+// prepare col style data for the dataset
+for (int i = 0 ; i < cols.length ; i++) {
+	for (def p : col_styles.keySet()) {
+		if (cols[i] ==~ p) {
+			def style = col_styles[p]
+			if (style["label-replacement"] != null && style["label-replacement"].length() > 0) {
+				colLabelStyle[i] = style["label-replacement"]
+			}
+			if (style["hidden"] != null && style["hidden"].toUpperCase() == "T") {
+				colHiddenStyle << i
+			}
+			if (style["shape-size"] != null && style["shape-size"].length() > 0) {
+				colPointSizeStyle[i] = Double.parseDouble(style["shape-size"])
+			}
+			if (style["shape-color"] != null && style["shape-color"].length() > 0 ) {
+				colPointColorStyle[i] = rgbaStringToColor(style["shape-color"])
+			}
+			if (style["shape-replacement"] != null && shapes.containsKey(style["shape-replacement"])) {
+				colPointShapeStyle[i] = shapes[style["shape-replacement"]]
+			}
+			if (style["label-size"] != null && style["label-size"].length() > 0) {
+				colFontSizeStyle[i] = Float.parseFloat(style["label-size"])
+			}
+			if (style["label-color"] != null && style["label-color"].length() > 0) {
+				colFontColorStyle[i] = rgbaStringToColor(style["label-color"])
+			}
+			if (style["label-font-family"] != null && style["label-font-family"].length() > 0) {
+				colFontFamilyStyle[i] = style["label-font-family"]
+			}
+			if (style["label-style"] != null && style["label-style"].length() > 0) {
+				colFontStyleStyle[i] = Integer.parseInt(style["label-style"])
+			}
+			
+		}
+	}
+}
+if (debug > 0) {
+	println "COL COL=$colPointColorStyle"
+	println "COL SHP=$colPointShapeStyle"
+	println "COL LAB=$colLabelStyle"
+	println "COL FONT-SIZ=$colFontSizeStyle"
+	println "COL SIZ=$colPointSizeStyle"
+	println "COL VIZ=$colHiddenStyle"
+	println "COL STYLE=$colFontStyleStyle"
+}
+
+// prepare row style data for the dataset
+for (int i = 0 ; i < rows.length ; i++) {
+	for (def p : row_styles.keySet()) {
+		if (rows[i] ==~ p) {
+			def style = row_styles[p]
+			if (style["hidden"] != null && style["hidden"].toUpperCase() == "T") {
+				rowHiddenStyle << i
+			}
+			if (style["label-replacement"] != null && style["label-replacement"].length() > 0) {
+				rowLabelStyle[i] = style["label-replacement"]
+			}
+			if (style["shape-size"] != null && style["shape-size"].length() > 0) {
+				rowPointSizeStyle[i] = Double.parseDouble(style["shape-size"])
+			}
+			if (style["shape-color"] != null && style["shape-color"].length() > 0 ) {
+				rowPointColorStyle[i] = rgbaStringToColor(style["shape-color"])
+			}
+			if (style["shape-replacement"] != null && shapes.containsKey(style["shape-replacement"])) {
+				rowPointShapeStyle[i] = shapes[style["shape-replacement"]]
+			}
+			if (style["label-size"] != null && style["label-size"].length() > 0) {
+				rowFontSizeStyle[i] = Float.parseFloat(style["label-size"])
+			}
+			if (style["label-color"] != null && style["label-color"].length() > 0) {
+				rowFontColorStyle[i] = rgbaStringToColor(style["label-color"])
+			}
+			if (style["label-font-family"] != null && style["label-font-family"].length() > 0) {
+				rowFontFamilyStyle[i] = style["label-font-family"]
+			}
+			if (style["label-style"] != null && style["label-style"].length() > 0) {
+				rowFontStyleStyle[i] = Integer.parseInt(style["label-style"])
+			}
+		}
+	}
+}
+if (debug > 0) {
+	println "ROW COL=$rowPointColorStyle"
+	println "ROW SHP=$rowPointShapeStyle"
+	println "ROW LAB=$rowLabelStyle"
+	println "ROW FONT-SIZ=$rowFontSizeStyle"
+	println "ROW SIZ=$rowPointSizeStyle"
+	println "ROW VIZ=$rowHiddenStyle"
+	println "ROW STYLE=$rowFontStyleStyle"
+}
+
+
+
+// Redefine the chart renderer and update the chart
+def chartEditor = editor.getEditors()[0]
+def chartComposite = chartEditor.getComposite()
+
+ddebug = debug
+monitor.syncExec( new Runnable() {
+
+	public void run() {
+		println chartComposite
+		def chart = chartEditor.getChart()
+		
+		/*
+		println "chart: "+chart
+		println "Plot: "+chart.getPlot()
+		println "Dataset: "+chart.getPlot().getDataset()
+		println "Renderer 1: "+chart.getPlot().getRenderer()
+		 */
+		
+		def renderer = new CAItemSelectionRenderer(ica, chart) {
+			Area EMPTYAREA = new Area()
+					
+					@Override
+					public void initItemLabelGenerator() {
+					XYItemLabelGenerator generator = new XYItemLabelGenerator() {
+					
+					@Override
+					public String generateLabel(XYDataset dataset, int series, int item) {
+						if (series == 0 && rowHiddenStyle.contains(item)) {
+							if (ddebug > 1) println "HIDDING ROW LABEL '$item' '${rows[item]}'"
+							return ""
+						} else if (series == 1 && colHiddenStyle.contains(item)) {
+							if (ddebug > 1) println "HIDDING COL LABEL '$item' '${cols[item]}'"
+							return ""
+						} else if (series == 0 && rowLabelStyle.containsKey(item)) {
+							if (ddebug > 1) println "RENAME ROW LABEL '$item' '${rows[item]}' -> '${rowLabelStyle[item]}'"
+							return rowLabelStyle[item]
+						} else if (series == 1 && colLabelStyle.containsKey(item)) {
+							if (ddebug > 1) println "RENAME COL LABEL '$item' '${cols[item]}' -> '${colLabelStyle[item]}'"
+							return colLabelStyle[item]
+						} else {
+							CAXYDataset caDataset = (CAXYDataset) dataset;
+							return caDataset.getLabel(series, item);
+						}
+					}
+				};
+				
+				// don't use setBaseItemLabelGenerator BUT setDefaultItemLabelGenerator
+				this.setDefaultItemLabelGenerator(generator);
+				this.setDefaultItemLabelsVisible(true);
+			}
+			
+			
+			
+			@Override
+			public Font getItemLabelFont(int series, int item) {
+				Font d = super.getItemLabelFont(series, item);
+				Integer style = d.getStyle();
+				Integer size = d.getSize();
+				String family = d.getFontName();
+				
+				// size
+				if (series == 0 && rowFontSizeStyle.containsKey(item)) {
+					if (ddebug > 1) println "FIX ROW FONT-SIZE $item ${rows[item]} -> ${rowFontSizeStyle[item]}"
+					size *= rowFontSizeStyle[item];
+				} else if (series == 1 && colFontSizeStyle.containsKey(item)) {
+					if (ddebug > 1) println "FIX COL FONT-SIZE $item ${cols[item]} -> ${colFontSizeStyle[item]}"
+					size *= colFontSizeStyle[item];
+				}
+				
+				// family
+				if (series == 0 && rowFontFamilyStyle.containsKey(item)) {
+					if (ddebug > 1) println "FIX ROW FONT-Family $item ${rows[item]} -> ${rowFontFamilyStyle[item]}"
+					family = rowFontFamilyStyle[item];
+				} else if (series == 1 && colFontFamilyStyle.containsKey(item)) {
+					if (ddebug > 1) println "FIX COL FONT-Family $item ${cols[item]} -> ${colFontFamilyStyle[item]}"
+					family = colFontFamilyStyle[item];
+				}
+				
+				// style
+				if (series == 0 && rowFontStyleStyle.containsKey(item)) {
+					if (ddebug > 1) println "FIX ROW FONT-Style $item ${rows[item]} -> ${rowFontStyleStyle[item]}"
+					style = rowFontStyleStyle[item];
+				} else if (series == 1 && colFontFamilyStyle.containsKey(item)) {
+					if (ddebug > 1) println "FIX COL FONT-Style $item ${cols[item]} -> ${colFontStyleStyle[item]}"
+					style = colFontStyleStyle[item];
+				}
+				
+				
+				return new Font(family, style, size);
+			}
+			
+			
+			@Override
+			public Shape getItemShape(int series, int item) {
+				// Rows (series == 0), Cols (series == 1)
+				if (series == 0 && rowHiddenStyle.contains(item)) {
+					return EMPTYAREA;
+				} else if (series == 1 && colHiddenStyle.contains(item)) {
+					return EMPTYAREA;
+				} else {
+					
+					Shape shape =  super.getItemShape(series, item);
+					
+					// not-visible shapes mode
+					if(!((CA) this.multipleItemsSelector.getResult()).isShowPointShapes())        {
+						return shape;
+					}
+					
+					// shape replacement
+					if (series == 0 && rowPointShapeStyle.containsKey(item)) {
+						if (ddebug > 1) println "FIX ROW SHAPE $item ${rows[item]} -> ${rowPointShapeStyle[item]}"
+						shape = rowPointShapeStyle.get(item);
+					} else if (series == 1 && colPointShapeStyle.containsKey(item)) {
+						if (ddebug > 1) println "FIX COL SHAPE $item ${cols[item]} -> ${colPointShapeStyle[item]}"
+						shape = colPointShapeStyle.get(item);
+					}
+					
+					
+					// shape scaling
+					AffineTransform t = new AffineTransform();
+					if (series == 0 && rowPointSizeStyle.containsKey(item)) {
+						if (ddebug > 1) println "FIX ROW POINT SIZE $item ${rows[item]} -> ${rowPointSizeStyle[item]}"
+						t.setToScale(rowPointSizeStyle.get(item), rowPointSizeStyle.get(item));
+						shape = t.createTransformedShape(shape);
+					} else if (series == 1 && colPointSizeStyle.containsKey(item)) {
+						if (ddebug > 1) println "FIX COL POINT SIZE $item ${cols[item]} -> ${colPointSizeStyle[item]}"
+						t.setToScale(colPointSizeStyle.get(item), colPointSizeStyle.get(item));
+						shape = t.createTransformedShape(shape);
+					}
+					
+					return shape;
+				}
+			}
+			
+			
+			@Override
+			public Paint getItemPaint(int series, int item) {
+				
+				// visible shapes mode
+				if (!((CA) this.multipleItemsSelector.getResult()).isShowPointShapes()) {
+					return super.getItemPaint(series, item);
+				}
+				
+				if (series == 0 && rowPointColorStyle.containsKey(item)) {
+					if (ddebug > 1) println "FIX ROW POINT COLOR $item ${rows[item]} -> ${rowPointColorStyle[item]}"
+					return rowPointColorStyle.get(item);
+				} else if (series == 1 && colPointColorStyle.containsKey(item)) {
+					if (ddebug > 1) println "FIX COL POINT COLOR $item ${cols[item]} -> ${colPointColorStyle[item]}"
+					return colPointColorStyle.get(item);
+				}
+				else {
+					return super.getItemPaint(series, item);
+				}
+			}
+			
+			
+			@Override
+			public Paint getItemLabelPaint(int series, int item) {
+				if (series == 0 && rowFontColorStyle.containsKey(item)) {
+					if (ddebug > 1) println "FIX ROW LABEL COLOR $item ${rows[item]} -> ${rowFontColorStyle[item]}"
+					return rowFontColorStyle.get(item);
+				} else if (series == 1 && colFontColorStyle.containsKey(item)) {
+					if (ddebug > 1) println "FIX COL LABEL COLOR $item ${cols[item]} -> ${colFontColorStyle[item]}"
+					return colFontColorStyle.get(item);
+				} else {
+					return super.getItemLabelPaint(series, item);
+				}
+			}
+			
+		};
+		
+		
+		def cp = editor.editors[0].getChart();
+		renderer.chart = cp // SJ: seems useless
+		renderer.setSeriesVisible(0, ica.isShowVariables()); // Rows  // SJ: seems useless
+		renderer.setSeriesVisible(1, ica.isShowIndividuals()); // Columns  // SJ: seems useless
+		chart.getXYPlot().setRenderer(renderer)
+		
+		ica.getChartCreator().updateChart(chartEditor.getResult())
+		
+	}
+});
+
+
+
+
+// creates a Color object from the specified RGB or RGBA string representation separated by spaces ("R G B" or "R G B A") from 0 to 255 for each channel
+def rgbaStringToColor(String color) {
+	String[] rgbColor = color.split(" ");
+	String alpha = "255";
+	if(rgbColor.length > 2) {
+		if(rgbColor.length > 3) {
+			alpha = rgbColor[3];
+		}
+		return new Color(Integer.parseInt(rgbColor[0]), Integer.parseInt(rgbColor[1]), Integer.parseInt(rgbColor[2]), Integer.parseInt(alpha))
+	}
+	else {
+		println "Error in color format for RGB or RGBA string: $color"
+	}
+}
+
+
+
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/functions.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/functions.groovy	(revision 0)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/functions.groovy	(revision 3555)
@@ -0,0 +1 @@
+// 
\ No newline at end of file
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/CAFilter.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/CAFilter.groovy	(revision 0)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/CAFilter.groovy	(revision 3555)
@@ -0,0 +1,301 @@
+// STANDARD DECLARATIONS
+package org.txm.macro.stats
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.searchengine.cqp.clientExceptions.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.*
+import org.apache.commons.lang.time.StopWatch
+import java.util.Arrays
+import org.jfree.chart.renderer.xy.*
+import org.jfree.chart.renderer.*
+import org.jfree.chart.plot.*
+import org.jfree.data.xy.*
+import org.jfree.chart.axis.*
+import java.awt.*;
+import java.awt.geom.*;
+import org.jfree.chart.labels.*
+
+import org.txm.ca.core.chartsengine.jfreechart.themes.highcharts.renderers.*
+import org.txm.ca.rcp.editors.*
+import org.txm.libs.office.ReadODS
+import org.txm.ca.core.chartsengine.jfreechart.datasets.*
+import org.jfree.chart.renderer.AbstractRenderer
+
+import org.apache.commons.math3.stat.descriptive.*
+
+println "editor: "+editor
+
+if (!(editor instanceof CAEditor)) {
+	println "editor is not a CA editor: $editor, Run the macro with F12 when the editor is selected :-)"
+	return
+}
+
+def chartEditor = editor.getEditors()[0]
+def chartComposite = chartEditor.getComposite()
+
+// BEGINNING OF PARAMETERS
+
+// Declare each parameter here
+// (available widget types: Query, File, Folder, String, Text, Boolean, Integer, Float and Date)
+
+//@Field @Option(name="query", usage="an example query", widget="Query", required=true, def='[pos="V.*"]')
+//def query
+
+//@Field @Option(name="file", usage="an example file", widget="File", required=true, def="C:/Temp/foo.txt")
+//def file
+
+//@Field @Option(name="folder", usage="an example folder", widget="Folder", required=false, def="C:/Temp")
+//def folder
+
+//@Field @Option(name="date", usage="an example date", widget="Date", required=false, def="1984-09-01")
+//def date
+
+//@Field @Option(name="integer", usage="an example integer", widget="Integer", required=false, def="42")
+//def integer
+
+@Field @Option(name="QMin", usage="min Q", widget="Float", required=true, def="0.01")
+def QMin
+
+@Field @Option(name="CTRXMin", usage="min CTR X", widget="Float", required=true, def="0.001")
+def CTRXMin
+
+@Field @Option(name="CTRYMin", usage="min CTR Y", widget="Float", required=true, def="0.001")
+def CTRYMin
+
+@Field @Option(name="stackX", usage="stack X", widget="Float", required=true, def="0.0")
+def stackX
+
+@Field @Option(name="stackY", usage="stack Y", widget="Float", required=true, def="0.0")
+def stackY
+
+//@Field @Option(name="string", usage="an example string", widget="String", required=false, def="hello world!")
+//def string
+
+@Field @Option(name="regexFilter", usage="row property form regex", widget="Text", required=false, def="")
+def regexFilter
+
+@Field @Option(name="debug", usage="debug (verbose) mode", widget="Boolean", required=true, def="true")
+def debug
+
+// La fenêtre de résultats
+CAresultWindow = editor
+
+// Le tableau de données d'aide à l'interprétation
+// Les données de l'AFC sont manipulables par les méthodes documentées ici http://txm.sourceforge.net/javadoc/TXM/TBX/org/txm/stat/engine/r/function/CA.html
+
+ica = CAresultWindow.getCA()
+ca = ica.getCA()
+
+rowNames = ica.getRowNames()
+rowCos2 = ca.getRowCos2()
+rowContrib = ca.getRowContrib()
+
+colNames = ica.getColNames()
+colCos2 = ca.getColCos2()
+colContrib = ca.getColContrib()
+
+F1 = ica.getFirstDimension()-1
+F2 = ica.getSecondDimension()-1
+
+println sprintf("F1 = %d, F2 = %d, %d initial rows, %d initial cols", F1+1, F2+1, rowNames.length, colNames.length)
+
+def stats = { vector, factor ->
+	s = new DescriptiveStatistics()
+	(vector.length).times {
+		s.addValue(vector[it][factor]);
+	}
+
+	println "min       quartile  median    third quartile  max"
+	println sprintf("%8f  %8f  %8f  %8f        %8f", s.getMin(), s.getPercentile(25), s.getPercentile(50), s.getPercentile(75), s.getMax())
+}
+
+// rows
+
+println "ROWS -----"
+println "CTR"+(F1+1)
+stats(rowContrib, F1)
+
+println "CTR"+(F2+1)
+stats(rowContrib, F2)
+
+println "Cos² "+(F1+1)
+stats(rowCos2, F1)
+
+println "Cos² "+(F2+1)
+stats(rowCos2, F2)
+
+// cols
+
+println "COLS -----"
+println "CTR"+(F1+1)
+stats(colContrib, F1)
+
+println "CTR"+(F2+1)
+stats(colContrib, F2)
+
+println "Cos² "+(F1+1)
+stats(colCos2, F1)
+
+println "Cos² "+(F2+1)
+stats(colCos2, F2)
+
+
+def stats2 = { vector, factor1, factor2 ->
+	s = new DescriptiveStatistics()
+	(vector.length).times {
+		s.addValue(vector[it][factor1]+vector[it][factor2]);
+	}
+
+	println "min       quartile  median    third quartile  max"
+	println sprintf("%8f  %8f  %8f  %8f        %8f", s.getMin(), s.getPercentile(25), s.getPercentile(50), s.getPercentile(75), s.getMax())
+}
+
+println "Q"+(F1+1)+(F2+1)
+stats2(rowCos2, F1, F2)
+
+println "Q"+(F1+1)+(F2+1)
+stats2(colCos2, F1, F2)
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return
+
+// END OF PARAMETERS
+
+
+filteredRows = []
+
+println ""
+
+if (debug) println "\nROWS -----"
+
+if (regexFilter.length() > 0) {
+	nmatched = 0
+	rowNames.each { it ->
+		if (it ==~ regexFilter) {
+			if (debug && !filteredRows.contains(it)) {
+				if (nmatched > 0) print ", "
+				print it
+			}
+			filteredRows << it
+			nmatched++
+		}
+	}
+
+	if (debug && nmatched > 0) println ""
+
+	if (debug) {
+		println sprintf("\n%d rows filtered by regex", nmatched)
+	}
+
+}
+
+nQCTR = 0
+rowNames.eachWithIndex { it, i ->
+	def cos2 = rowCos2[i]
+	if ((rowContrib[i][F1] < CTRXMin) && (rowContrib[i][F2] < CTRYMin) && (cos2[F1] + cos2[F2] < QMin)) {
+		if (debug && !filteredRows.contains(rowNames[i])) {
+			if (nQCTR > 0) print ", "
+			print rowNames[i]
+		}
+		filteredRows << rowNames[i]
+		nQCTR++
+	}
+}
+
+if (debug) {
+	println sprintf("\n%d rows filtered by CTR or Q"+(F1+1)+(F2+1), nQCTR)
+}
+
+// cols
+
+filteredCols = []
+
+println ""
+
+if (debug) println "\nCOLS -----"
+
+if (regexFilter.length() > 0) {
+	nmatched = 0
+	colNames.each { it ->
+		if (it ==~ regexFilter) {
+			if (debug && !filteredCols.contains(it)) {
+				if (nmatched > 0) print ", "
+				print it
+			}
+			filteredCols << it
+			nmatched++
+		}
+	}
+
+	if (debug && nmatched > 0) println ""
+
+	if (debug) {
+		println sprintf("\n%d cols filtered by regex", nmatched)
+	}
+
+}
+
+nQCTR = 0
+colNames.eachWithIndex { it, i ->
+	def cos2 = colCos2[i]
+	if (!((colContrib[i][F1] > CTRXMin) || (colContrib[i][F2] > CTRYMin) || (cos2[F1] + cos2[F2] > QMin))) {
+		if (debug && !filteredCols.contains(colNames[i])) {
+			if (nQCTR > 0) print ", "
+			print colNames[i]
+		}
+		filteredCols << colNames[i]
+		nQCTR++
+	}
+}
+
+if (debug) {
+	println sprintf("\n%d cols filtered by CTR or Q"+(F1+1)+(F2+1), nQCTR)
+}
+
+double stackXv = stackX
+double stackYv = stackY
+
+
+// Visualisation graphique
+
+chartCAresultWindow = CAresultWindow.getEditors()[0]
+chartComposite = chartCAresultWindow.getComposite()
+
+monitor.syncExec( new Runnable() {
+	public void run() {
+
+				println chartComposite
+				def chart = chartEditor.getChart();
+
+				dataset2 = new CAXYDataset(ica)
+				
+				labels = dataset2.rowLabels
+				coords = dataset2.rowCoordinates
+				(labels.length).times {
+					if (filteredRows.contains(labels[it])) {
+						println "Moving "+labels[it]+" row to origin."
+						labels[it] = ""
+						coords[it][F1] = stackXv
+						coords[it][F2] = stackYv
+					}
+				}
+				labels = dataset2.columnLabels
+				coords = dataset2.columnCoordinates
+				(labels.length).times {
+					if (filteredCols.contains(labels[it])) {
+						println "Moving "+labels[it]+" col to origin."
+						labels[it] = ""
+						coords[it][F1] = stackXv
+						coords[it][F2] = stackYv
+					}
+				}
+
+				chart.getXYPlot().setDataset(dataset2)
+
+				ica.getChartCreator().getChartsEngine().getJFCTheme().apply(chart); // need to be call AFTER setRenderer() cause this method changes some renderering parameters
+				chartComposite.loadChart()
+			}
+})
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/InvertCAXAxisMacro.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/InvertCAXAxisMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/InvertCAXAxisMacro.groovy	(revision 3555)
@@ -0,0 +1,125 @@
+// @author Sebastien Jacquot
+// STANDARD DECLARATIONS
+package org.txm.macro.stats
+
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.searchengine.cqp.clientExceptions.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.*
+import org.apache.commons.lang.time.StopWatch
+import java.util.Arrays
+import org.jfree.chart.renderer.xy.*
+import org.jfree.chart.renderer.*
+import org.jfree.chart.plot.*
+import org.jfree.data.xy.*
+import org.jfree.chart.axis.*
+import java.awt.*;
+import java.awt.geom.*;
+import org.jfree.chart.labels.*
+
+import org.txm.ca.core.chartsengine.jfreechart.themes.highcharts.renderers.*
+import org.txm.ca.rcp.editors.*
+import org.txm.libs.office.ReadODS
+import org.txm.ca.core.chartsengine.jfreechart.datasets.*
+import org.jfree.chart.renderer.AbstractRenderer
+
+println "editor: "+editor
+
+if (!(editor instanceof CAEditor)) {
+	println "editor is not a CA editor: $editor, Run the macro with F12 when the editor is selected :-)"
+	return
+}
+
+ica = editor.getCA();
+chart = ica.getChart();
+plot = chart.getXYPlot();
+dataset = plot.getDataset(); 
+
+// overrides some dataset methods to return inverted X coordinates for columns and rows
+plot.setDataset(new CAXYDataset(ica) {
+
+        public Number getX(int series, int item) {
+                if(item == -1)        {
+                        System.out.println("CAXYDataset.getX()");
+                }
+                // Rows
+                if(series == 0) {
+                        return -this.rowCoordinates[item][this.axis1];
+                }
+                // Cols
+                else {
+                        return -this.columnCoordinates[item][this.axis1];
+                }
+        }
+        
+        
+         
+        /**
+         * Gets the minimum value in the specified series according to the specified axis.
+         * @param series
+         * @param axis
+         * @return
+         */
+        public double getMinValue(int series, int axis)        {
+                double minValue = 0;
+                double tmpMinValue;
+                double[][] coordinates = this.rowCoordinates;
+                if(series != 0)        {
+                        coordinates = this.columnCoordinates;
+                }
+                
+                for(int i = 0; i < coordinates.length; i++) {
+                        tmpMinValue = coordinates[i][axis];
+                        
+						// invert X coordinate
+                		if(axis == 0)        {
+                			tmpMinValue = -tmpMinValue;
+                		}
+                        
+                        if(tmpMinValue < minValue)        {
+                                minValue = tmpMinValue;
+                        }
+                }
+                
+                return minValue;
+        }
+        
+        /**
+         * Gets the maximum value in the specified series according to the specified axis.
+         * @param series
+         * @param axis
+         * @return
+         */
+        public double getMaxValue(int series, int axis)        {
+                double maxValue = 0;
+                double tmpMaxValue;
+                double[][] coordinates = this.rowCoordinates;
+                if(series != 0)        {
+                        coordinates = this.columnCoordinates;
+                }
+                
+                for(int i = 0; i < coordinates.length; i++) {
+                        tmpMaxValue = coordinates[i][axis];
+                        
+						// invert X coordinate
+                		if(axis == 0)        {
+                			tmpMaxValue = -tmpMaxValue;
+                		}
+                        
+                        if(tmpMaxValue > maxValue)        {
+                                maxValue = tmpMaxValue;
+                        }
+                }
+                
+                return maxValue;
+        }
+}
+);
+
+// update the limits dotted borders
+ica.getChartCreator().createCAFactorialMapChartLimitsBorder(chart);
+
+
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/rules.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/rules.groovy	(revision 0)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/rules.groovy	(revision 3555)
@@ -0,0 +1,228 @@
+// Functions
+
+def RedScale(n, min, max) {
+
+/* target for 4:
+40 40 255
+80 80 255
+120 120 255
+160 160 255
+
+RedScale(4, 40, 160)
+
+*/
+
+	delta = ((max-min)/(n-1)).round()
+		
+	colors = []
+
+	n.times {
+		v = min+delta*it
+		colors << "255 "+v+" "+v
+	}
+	
+	return colors
+}
+
+def GreenScale(n, min, max) {
+
+	delta = ((max-min)/(n-1)).round()
+		
+	colors = []
+
+	n.times {
+		v = min+delta*it
+		colors << v+" 255 "+v
+	}
+	
+	return colors
+}
+
+def BlueScale(n, min, max) {
+
+	delta = ((max-min)/(n-1)).round()
+		
+	colors = []
+
+	n.times {
+		v = min+delta*it
+		colors << v+" "+v+" 255"
+	}
+	
+	return colors
+}
+
+int_linear_min = { x, max_input, min_output, max_output ->
+
+	def y = x*(max_output-min_output)/max_input+min_output
+	
+	if (y < 1) {
+		return (int) min_output
+	} else {
+		return (int) y
+	}
+}
+
+def sex2Color(sexe) {
+	
+	switch(sexe) {
+		
+		case "F":
+			return "255 0 255"
+		case "M":
+			return "0 0 255"
+		default:
+			println "$sexe is not a sex value..."
+			return "0 0 0"
+	}
+}
+
+sex2Symbol = { sexe ->
+	
+	switch(sexe) {
+		
+		case "F":
+			return "⬤"
+		case "M":
+			return "✚"
+		default:
+			println "$sexe is not a sex value..."
+			return "?"
+	}
+}
+
+sex2Shape = { sexe ->
+	
+	switch(sexe) {
+		
+		case "F":
+			return "disk"
+		case "M":
+			return "triangle"
+		default:
+			println "$sexe is not a sex value..."
+			return "?"
+	}
+}
+
+sex2ColorScale = { sexe, scale ->
+	
+	switch(sexe) {
+		
+		case "F":
+			return blue_scale[scale]
+		case "M":
+			return red_scale[scale]
+		default:
+			println "$sexe is not a sex value..."
+			return "0 0 0"
+	}
+}
+
+colorScale = { color_scale, scale ->
+
+	try {
+    		value = color_scale[scale]
+    		if (value == null) {
+    			println "no scale $scale in $color_scale color_scale..."
+			return ""
+    		}
+	} catch ( IndexOutOfBoundsException e ) {
+    		println "no scale $scale in $color_scale color_scale..."
+		return ""
+	}
+	return value
+}
+
+parseInt = { str ->
+	if (str.isInteger()) {
+		return str.toInteger()
+	} else {
+		println "$str is not an Integer..."
+		return 0
+	}
+}
+
+parseFloat = { str ->
+
+	str = str.replaceAll(",", ".")
+	if (str.isFloat()) {
+		return str.toFloat()
+	} else {
+		println "$str is not a float number..."
+		return 0.0
+	}
+}
+
+// globals
+
+red_scale = RedScale(4, 40, 160)
+blue_scale = BlueScale(4, 40, 160)
+
+// https://www.schemecolor.com/solar-heat-color-scheme.php
+
+solarScale4 = [
+	"199 5 9",
+	"255 52 45",
+	"255 237 68",
+	"249 169 0"
+]
+
+mixedTxmPalette4 = [
+	"255 0 0",
+	"255 215 0",
+	"0 139 0",
+	"0 0 255"
+]
+
+rows_rules = // ajouter des [target, source]
+		[
+			// ["color",	"""c("autre")"""]
+			
+			// ...
+		]
+
+cols_rules = [
+
+/*
+
+Pattern :
+
+	[<column-name>, <groovy-code>]
+	
+	e.g. ["color", "1"]
+	
+	use " " for one space string
+
+- LABEL : cercle
+- TAILLE du label : fixe
+- COULEUR : fonction du sexe (couleur de base) et du quartile d'âge (dégradé)
+- POINT : pas de point
+
+LABEL : numéro du cercle
+TAILLE : fixe
+COULEUR : fonction du cercle. Prendre 4 couleurs qui suivent un ordre “naturel”, ex. Arc-en-ciel, ou chaud (cercle1) – froid (cercle 4), ex Rouge / Orange / Bleu / Violet. Ou bien un dégradé où l’on arrive bien à distinguer 4 valeurs (pas sûr que ce soit possible ?)
+TRANSPARENCE : filtrage éventuel sur cos2 
+
+c("cercle")
+c("age-quartile")
+sex2ColorScale(c("sexe"), c("age-quartile") as Integer)+" "+c(transparency)
+int_linear_min(c("q12") as Integer, 0.48, 80, 255)
+
+Examples:
+
+	["label-size", """1"""],
+	["label-replacement", """c("cercle")"""],
+	["transparency", """int_linear_min(parseFloat(c("cos2-1")), 0.43, 80, 255)"""],
+	["label-color", """sex2ColorScale(c("sexe"), parseInt(c("age-quartile")))+" "+c("transparency")"""],
+
+
+*/
+	["label-size", """1"""],
+	["label-replacement", """return(".")"""],
+	["shape-replacement", """sex2Shape(c("sexe"))"""],
+	["transparency", """int_linear_min(parseFloat(c("cos2-1")), 0.43, 80, 255)"""],
+	["shape-color", """colorScale(mixedTxmPalette4, parseInt(c("cercle"))-1)+" "+c("transparency")"""],
+	
+	// ajouter des [target, source] ici ...
+]
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/CaCompileStyleMacro.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/CaCompileStyleMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/CaCompileStyleMacro.groovy	(revision 3555)
@@ -0,0 +1,217 @@
+// STANDARD DECLARATIONS
+// @author mdecorde sjacquot sheiden
+package org.txm.macro
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.libs.office.ReadODS
+import org.txm.libs.office.WriteODS
+
+// ############################################
+
+
+c = { name ->
+	if (!style.containsKey(name)) {
+		println "No $name column..."
+		return false
+	}
+	return style[name]
+}
+
+def applyRules(def styles, def rules) {
+	for (def rule : rules) {
+		applyRule(styles, rule)
+	}
+}
+
+def applyRule(def styles, def rule) {
+	String pseudoCode = rule[1]
+//	if (pseudoCode.matches("[^(]+\\((.+)\\)")
+//	String method = 
+	//println "styles="+styles+" rule="+rule+ " "+styles[rule[0]]+" <- "+groovy.evaluate(rule[1])
+	styles[rule[0]] = groovy.evaluate(rule[1])	
+}
+
+// ############################################
+
+@Field @Option(name="rules_script", usage=".groovy file", widget="FileOpen", required=true, def='')
+def rules_script
+
+@Field @Option(name="functions_script", usage="functions used in rules, .groovy file", widget="FileOpen", required=true, def='')
+def functions_script
+
+@Field @Option(name="input_style_table", usage="must include 2 sheets named 'rows' and 'cols'", widget="FileOpen", required=true, def='')
+def input_style_table
+
+@Field @Option(name="output_style_table", usage="writes the 2 sheets rows and cols", widget="FileSave", required=true, def='')
+def output_style_table
+
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+debug
+
+// 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
+
+if (!rules_script.exists()) {
+	println "Rules file not found: $rules_script. Aborting..."
+	return false
+}
+
+if (!functions_script.exists()) {
+	println "Functions file not found: $functions_script. Aborting..."
+	return false
+}
+
+groovy = new GroovyShell(binding)
+groovy.evaluate(functions_script.getText("UTF-8"))
+
+
+if (!input_style_table.exists()) {
+	println "Pattern file not found: $input_style_table"
+	return false
+}
+if (!input_style_table.isFile() || !input_style_table.getName().toLowerCase().endsWith(".ods")) {
+	println "Wrong pattern file: $input_style_table"
+	return false
+}
+
+cols_rules = null
+rows_rules = null
+
+groovy.evaluate(rules_script.getText("UTF-8"))
+//def rows_rules = []
+//rules_script.getLines("UTF-8") { line ->
+//	line = lilne.split("\t", 3)
+//	if ("row".equals(line[0])) {
+//		rows_rules << [line[1], line[2]]
+//	}
+//}
+//
+//def cols_rules = []
+//rules_script.getLines("UTF-8") { line ->
+//	line = lilne.split("\t", 3)
+//	if ("col".equals(line[0])) {
+//		cols_rules << [line[1], line[2]]
+//	}
+//}
+
+if (cols_rules == null) {
+	println "Error: no 'cols_rules' defined. Aborting..."
+	return false
+}
+
+if (rows_rules == null) {
+	println "Error: no 'rows_rules' defined. Aborting..."
+	return false
+}
+
+print "Reading input_style_table rows..."
+def data = ReadODS.toTable(input_style_table, "rows")  // read from the "rows" sheet
+println "Done."
+
+print "Applying rows styles..."
+
+def keys = data[0]
+def row_styles = [] // reformat data
+	for (int i = 1 ; i < data.size() ; i++) {
+		def h = data[i]
+		style = [:] // create style entry
+		
+		// fill the style
+		for (int j = 0 ; j < h.size() ; j++) {
+			style[keys[j]] = h[j]
+		}
+		
+		applyRules(style, rows_rules)
+		row_styles << style
+	}
+if (debug > 0) {
+	println "ROW STYLES="+row_styles.join("\n")
+}
+println "Done."
+
+print "Reading input_style_table cols..."
+data = ReadODS.toTable(input_style_table, "cols") // read from the "cols" sheet
+println "Done."
+
+print "Applying cols styles..."
+
+keys = data[0]
+def col_styles = [] // reformat data
+
+for (int i = 1 ; i < data.size() ; i++) {
+	def h = data[i]
+	style = [:] // create style entry
+	
+	// fill the style
+	for (int j = 0 ; j < h.size() ; j++) {
+		style[keys[j]] = h[j]
+	}
+	
+	applyRules(style, cols_rules)
+	col_styles << style
+}
+if (debug > 0) {
+	println "COL STYLES="+col_styles.join("\n")
+}
+println "Done."
+
+print "Writing output_style_table..."
+WriteODS writer = new WriteODS(output_style_table)
+writer.table.setTableName("rows")
+if (row_styles.size() > 0) {
+
+	print "Writing rows styles..."
+	
+	writer.declareRowsAndColumns(row_styles.size(), row_styles[0].size())
+	keys = row_styles[0].keySet()
+	try {
+		writer.writeLine(keys as ArrayList, 0)
+	} catch(e) {
+		println "** Error in writer.writeLine(keys as ArrayList, 0)"
+		e.printStackTrace()
+	}
+	int iRow = 1
+	for (def style : row_styles) {
+		def line = []
+		for (def k : keys) line << style[k]
+			try {
+				writer.writeLine(line, iRow++)
+			} catch(e) {
+				println "** Error in writer.writeLine('$line', '${iRow+1}')"
+				e.printStackTrace()
+			}
+	}
+}
+
+table = writer.newTable("cols")
+if (col_styles.size() > 0) {
+
+	print "Writing cols styles..."
+	
+	writer.declareRowsAndColumns(col_styles.size(), col_styles[0].size())
+	
+	keys = col_styles[0].keySet()
+	try {
+		writer.writeLine(keys as ArrayList, 0)
+	} catch(e) {
+		println "** Error in writer.writeLine(keys as ArrayList, 0)"
+		e.printStackTrace()
+	}
+	int iRow = 1
+	for (def style : col_styles) {
+		def line = []
+		for (def k : keys) line << style[k]
+			try {
+				writer.writeLine(line, iRow++)
+			} catch(e) {
+				println "** Error in writer.writeLine('$line', '${iRow+1}')"
+				e.printStackTrace()
+			}
+	}
+}
+println "Done."
+
+writer.save()
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/PlotEllipsesMacro.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/PlotEllipsesMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/stats/PlotEllipsesMacro.groovy	(revision 3555)
@@ -0,0 +1,36 @@
+// STANDARD DECLARATIONS
+package org.txm.macro.stats
+
+import org.txm.ca.core.functions.CA
+import org.txm.statsengine.r.core.RWorkspace
+import groovy.transform.Field
+// BEGINNING OF PARAMETERS
+
+if (!(corpusViewSelection instanceof CA)) {
+	println "Selection is not a CA. Please select a CA result in the Corpus view"
+	return;
+}
+
+def ca = corpusViewSelection
+
+@Field @Option(name="outputFile", usage="an example file", widget="FileSave", required=true, def="file.svg")
+def outputFile
+
+@Field @Option(name="draw", usage="'row' or 'col'", widget="String", required=true, def="row")
+def draw
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return;
+
+// END OF PARAMETERS
+
+def s = ca.getRSymbol()
+def RW = RWorkspace.getRWorkspaceInstance()
+
+def script = """
+plot($s);
+ellipseCA($s, ellipse=c("$draw"));
+"""
+
+RW.plot(outputFile, script);
+
+println "Done: "+outputFile.getAbsolutePath()
\ No newline at end of file
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/utils/ListFontsMacro.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/utils/ListFontsMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/utils/ListFontsMacro.groovy	(revision 3555)
@@ -0,0 +1,16 @@
+// 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.utils
+
+def e = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment()
+def fonts = e.getAllFonts()
+
+println fonts.size()+" fonts on this computer:"
+println ""
+
+fonts.each { f ->
+	println f.getFontName()
+}
Index: TXM/trunk/org.txm.treesearch.rcp/src/org/txm/treesearch/command/ConcordanceLineToTreeSearch.java
===================================================================
--- TXM/trunk/org.txm.treesearch.rcp/src/org/txm/treesearch/command/ConcordanceLineToTreeSearch.java	(revision 3554)
+++ TXM/trunk/org.txm.treesearch.rcp/src/org/txm/treesearch/command/ConcordanceLineToTreeSearch.java	(revision 3555)
@@ -1,130 +0,0 @@
-// 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.treesearch.command;
-
-import java.util.HashMap;
-import java.util.List;
-
-import org.eclipse.core.commands.ExecutionEvent;
-import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.core.runtime.IConfigurationElement;
-import org.eclipse.core.runtime.RegistryFactory;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.StructuredSelection;
-import org.eclipse.ui.handlers.HandlerUtil;
-import org.txm.concordance.core.functions.Concordance;
-import org.txm.concordance.core.functions.Line;
-import org.txm.core.messages.TXMCoreMessages;
-import org.txm.core.preferences.TXMPreferences;
-import org.txm.core.results.TXMResult;
-import org.txm.objects.Match;
-import org.txm.rcp.editors.TXMEditor;
-import org.txm.rcp.handlers.BaseAbstractHandler;
-import org.txm.searchengine.core.QueryBasedTXMResult;
-import org.txm.searchengine.cqp.corpus.CQPCorpus;
-import org.txm.treesearch.editor.TreeSearchEditor;
-import org.txm.treesearch.function.TreeSearch;
-import org.txm.treesearch.function.TreeSearchSelector;
-import org.txm.treesearch.preferences.TreeSearchPreferences;
-import org.txm.treesearch.rcp.Messages;
-import org.txm.utils.logger.Log;
-
-
-/**
- * Open the TIGERSearch Editor using the current selection OR a preference node set in the RCP command parameter TXMPreferences.RESULT_PARAMETERS_NODE_PATH
- * 
- * @author mdecorde.
- */
-public class ConcordanceLineToTreeSearch extends BaseAbstractHandler {
-	
-	/** The ID. */
-	public static String ID = ConcordanceLineToTreeSearch.class.getName();
-	
-	/*
-	 * (non-Javadoc)
-	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
-	 */
-	@Override
-	public Object execute(final ExecutionEvent event) throws ExecutionException {
-		
-		TXMResult r = BaseAbstractHandler.getActiveEditorResult(event);
-		
-		if (!(r instanceof Concordance)) {
-			Log.warning(Messages.bind(Messages.ResultIsNotAConcordanceP0, r));
-			return null;
-		}
-		
-		ISelection s = HandlerUtil.getCurrentSelection(event);
-		if (!(s instanceof StructuredSelection)) {
-			Log.warning(Messages.bind(Messages.SelectionIsNotALineP0, s));
-			return null;
-		}
-		
-		StructuredSelection selection = (StructuredSelection) s;
-		List list = selection.toList();
-		
-		if (list.size() == 0) {
-			Log.warning(Messages.bind(Messages.NoEditorSelectionP0, r));
-			return null;
-		}
-		
-		Concordance concordance = (Concordance)r;
-		Object o = list.get(0);
-		if (!(o instanceof Line)) {
-			Log.warning(Messages.bind(Messages.SelectionIsNotALineP0, o));
-			return null;
-		}
-		Line l = (Line)o;
-		//TreeSearchSelector selector = ComputeTreeSearch.getSelectorForCorpus(concordance.getCorpus(), "UD");
-		
-		TreeSearch ts = ComputeTreeSearch.getTreeSearchFor(concordance.getCorpus());
-		
-		ts.setQuery(concordance.getQuery());
-		
-		try {
-			if (ts.compute() &&  ts.getSelection() != null) {
-				int i = 0;
-				
-				for (Match m : ts.getSelection().getMatches()) {
-					if (m.getStart() <= l.getKeywordPosition() && l.getKeywordPosition() <= m.getEnd()) {
-						ts.setIndexAndSubIndex(i, 1);
-						break;
-					}
-					i++;
-				}
-			}
-		}
-		catch (Exception e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		}
-		
-		return ComputeTreeSearch.openEditor(ts);
-	}
-}
Index: TXM/trunk/org.txm.treesearch.rcp/src/org/txm/treesearch/command/SendToTreeSearch.java
===================================================================
--- TXM/trunk/org.txm.treesearch.rcp/src/org/txm/treesearch/command/SendToTreeSearch.java	(revision 0)
+++ TXM/trunk/org.txm.treesearch.rcp/src/org/txm/treesearch/command/SendToTreeSearch.java	(revision 3555)
@@ -0,0 +1,170 @@
+// 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.treesearch.command;
+
+import java.util.List;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.txm.concordance.core.functions.Concordance;
+import org.txm.concordance.core.functions.Line;
+import org.txm.concordance.rcp.editors.ConcordanceEditor;
+import org.txm.core.results.TXMResult;
+import org.txm.edition.rcp.editors.SynopticEditionEditor;
+import org.txm.objects.Match;
+import org.txm.rcp.editors.ITXMResultEditor;
+import org.txm.rcp.handlers.BaseAbstractHandler;
+import org.txm.rcp.utils.SWTEditorsUtils;
+import org.txm.searchengine.core.Selection;
+import org.txm.treesearch.editor.TreeSearchEditor;
+import org.txm.treesearch.function.TreeSearch;
+import org.txm.treesearch.rcp.Messages;
+import org.txm.utils.logger.Log;
+
+
+/**
+ * Open the TIGERSearch Editor using the current selection OR a preference node set in the RCP command parameter TXMPreferences.RESULT_PARAMETERS_NODE_PATH
+ * 
+ * @author mdecorde
+ */
+public class SendToTreeSearch extends BaseAbstractHandler {
+	
+	/** The ID. */
+	public static String ID = SendToTreeSearch.class.getName();
+	
+	/*
+	 * (non-Javadoc)
+	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	@Override
+	public Object execute(final ExecutionEvent event) throws ExecutionException {
+		
+		ITXMResultEditor<? extends TXMResult> editor = SWTEditorsUtils.getActiveEditor(event);
+		
+		ISelection s = HandlerUtil.getCurrentSelection(event);
+		
+		if (editor instanceof ConcordanceEditor) {
+			return concordancetoTree(editor, s);
+		} else if (editor instanceof SynopticEditionEditor) {
+			return editiontoTree(editor, s);
+		} else {
+			return null;
+		}
+	}
+	
+	public Object editiontoTree(ITXMResultEditor<? extends TXMResult> editor, ISelection s) {
+		System.out.println("Send EDITION TO TREE");
+		return null;
+	}
+	
+	public Object concordancetoTree(ITXMResultEditor<? extends TXMResult> editor, ISelection s) {
+		TXMResult r = editor.getResult();
+		
+		if (!(r instanceof Concordance)) {
+			Log.warning(Messages.bind(Messages.ResultIsNotAConcordanceP0, r));
+			return null;
+		}
+		
+		if (!(s instanceof StructuredSelection)) {
+			Log.warning(Messages.bind(Messages.SelectionIsNotALineP0, s));
+			return null;
+		}
+		
+		StructuredSelection selection = (StructuredSelection) s;
+		List list = selection.toList();
+		
+		if (list.size() == 0) {
+			Log.warning(Messages.bind(Messages.NoEditorSelectionP0, r));
+			return null;
+		}
+		
+		Concordance concordance = (Concordance)r;
+		Object o = list.get(0);
+		if (!(o instanceof Line)) {
+			Log.warning(Messages.bind(Messages.SelectionIsNotALineP0, o));
+			return null;
+		}
+		Line l = (Line)o;
+		//TreeSearchSelector selector = ComputeTreeSearch.getSelectorForCorpus(concordance.getCorpus(), "UD");
+		
+		TreeSearchEditor leditor = editor.getLinkedEditor(TreeSearchEditor.class);
+		TreeSearch ts = null;
+		if (leditor != null) {
+			ts = leditor.getResult();
+			ts.setQuery(null);
+		} else {
+			ts = ComputeTreeSearch.getTreeSearchFor(concordance.getCorpus());
+			ts.setQuery(null);
+		}
+		//ts.setQuery(concordance.getQuery());
+		
+		try {
+			boolean c = ts.compute();
+			Selection sel = ts.getSelection();
+			int kp = l.getKeywordPosition();
+//			System.out.println("KP="+kp);
+			if (c &&  sel != null) {
+				int i = 0;
+				List<? extends Match> matches = ts.getSelection().getMatches();
+				
+				for (Match m : matches) {
+					if (m.getStart() <= kp && kp <= m.getEnd()) {
+//						System.out.println("set index "+(i+1));
+						ts.setIndexAndSubIndex(i+1, 1);
+						break;
+					}
+					i++;
+				}
+			}
+		}
+		catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+		if (leditor == null) {
+			ITXMResultEditor<TXMResult> openedEditor = ComputeTreeSearch.openEditor(ts);
+			if (openedEditor != null) {
+				editor.addLinkedEditor(openedEditor);
+			}
+			return openedEditor;
+		} else {
+			try {
+				leditor.refresh(true);
+			}
+			catch (Exception e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+		return leditor;
+	}
+}

Property changes on: TXM/trunk/org.txm.treesearch.rcp/src/org/txm/treesearch/command/SendToTreeSearch.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/org.txm.treesearch.rcp/src/org/txm/treesearch/editor/TreeSearchEditor.java
===================================================================
--- TXM/trunk/org.txm.treesearch.rcp/src/org/txm/treesearch/editor/TreeSearchEditor.java	(revision 3554)
+++ TXM/trunk/org.txm.treesearch.rcp/src/org/txm/treesearch/editor/TreeSearchEditor.java	(revision 3555)
@@ -2,8 +2,10 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.browser.Browser;
@@ -30,6 +32,7 @@
 import org.txm.core.results.Parameter;
 import org.txm.edition.rcp.handlers.OpenEdition;
 import org.txm.rcp.IImageKeys;
+import org.txm.rcp.editors.ITXMResultEditor;
 import org.txm.rcp.editors.TXMBrowserEditor;
 import org.txm.rcp.editors.TXMEditor;
 import org.txm.rcp.editors.TXMResultEditorInput;
@@ -219,7 +222,7 @@
 		l1.setText("T "); //$NON-NLS-1$
 		l1.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
 		
-		TCombo = new Combo(line2, SWT.READ_ONLY);
+		TCombo = new Combo(line2, SWT.READ_ONLY|SWT.MULTI);
 		GridData gdata = new GridData(SWT.FILL, SWT.CENTER, true, true);
 		TCombo.setLayoutData(gdata);
 		TCombo.addSelectionListener(selChangedListener);
@@ -383,7 +386,7 @@
 		String[] tFeatures = ts.getAvailableTProperties();
 		if (tFeatures.length > 0) {
 			TCombo.setItems(tFeatures);
-			TCombo.setText(ts.getT());
+			//TCombo.setText(ts.getT());
 		}
 		
 		String[] ntFeatures = ts.getAvailableNTProperties();
@@ -441,7 +444,7 @@
 		}
 		
 		if (ts.isDrawn()) {
-			sentSpinner.setSelection(1);
+			sentSpinner.setSelection(ts.getCurrentMatchIndex() + 1);
 			sentSpinner.setMaximum(ts.getNSentences());
 			// if (ts.hasSubMatchesStrategy()) {
 			subSpinner.setSelection(ts.getSub(0));
@@ -515,6 +518,7 @@
 		try {
 			TreeSearch ts = tsPerRepresentation.get(currentSelector.getEngine());
 			if (ts.getNSentences() > 0) {
+				
 				sentCounterLabel.setText("/" + ts.getNSentences()); //$NON-NLS-1$
 				if (ts.hasSubMatchesStrategy()) subCounterLabel.setText("/" + ts.getNSubGraph(0)); //$NON-NLS-1$
 				sentSpinner.setSelection(ts.getCurrentMatchIndex());
@@ -546,7 +550,12 @@
 	 */
 	private boolean reloadGraph() {
 		
-		String T = TCombo.getText();
+		List<String> T = null;
+		if (TCombo.getText().isEmpty()) {
+			T = new ArrayList<String>();
+		} else {
+			T = Arrays.asList(TCombo.getText().split(", "));
+		}
 		String NT = NTCombo.getText();
 		int sent = sentSpinner.getSelection() - 1;
 		int sub = 0;
Index: TXM/trunk/org.txm.treesearch.rcp/plugin.xml
===================================================================
--- TXM/trunk/org.txm.treesearch.rcp/plugin.xml	(revision 3554)
+++ TXM/trunk/org.txm.treesearch.rcp/plugin.xml	(revision 3555)
@@ -50,7 +50,7 @@
       </command>
       <command
             categoryId="TreeSearch4TXM.commands.category"
-            defaultHandler="org.txm.treesearch.command.ConcordanceLineToTreeSearch"
+            defaultHandler="org.txm.treesearch.command.SendToTreeSearch"
             id="org.txm.treesearch.command.ConcordanceLineToTreeSearch"
             name="%command.name.0">
       </command>
@@ -114,6 +114,22 @@
             </visibleWhen>
          </command>
       </menuContribution>
+      <menuContribution
+            locationURI="popup:org.txm.concordance.rcp.editors.ConcordanceEditor">
+         <command
+               commandId="org.txm.treesearch.command.ConcordanceLineToTreeSearch"
+               icon="icons/functions/Tree.png"
+               style="push">
+         </command>
+      </menuContribution>
+      <menuContribution
+            locationURI="popup:org.txm.edition.rcp.editors.SynopticEditionEditor">
+         <command
+               commandId="org.txm.treesearch.command.ConcordanceLineToTreeSearch"
+               icon="icons/functions/Tree.png"
+               style="push">
+         </command>
+      </menuContribution>
       
    </extension>
    <extension
Index: TXM/trunk/org.txm.translate.rcp/messages_fr.properties
===================================================================
--- TXM/trunk/org.txm.translate.rcp/messages_fr.properties	(revision 3554)
+++ TXM/trunk/org.txm.translate.rcp/messages_fr.properties	(revision 3555)
@@ -1582,7 +1582,7 @@
 statsengine.r.core.messages.RCore.error_failedToInitializeFileTransfert=** Échec de l''initialisation du transfert \: {0}.
 statsengine.r.core.messages.RCore.error_failedToLoadLibrary=** La librairie {0} n''a pas pu être chargée \: {1}.
 statsengine.r.core.messages.RCore.error_failedToRunREG=** Échec du lancement de REG pour localiser le programme R.
-statsengine.r.core.messages.RCore.error_failedToStartRServe=** Impossible de démarrer le moteur statistique (RServe).
+statsengine.r.core.messages.RCore.error_failedToStartRServe=** Impossible de démarrer le moteur statistique (Rserve).
 statsengine.r.core.messages.RCore.error_failedToStartRServeWithCommand=** Échec du lancement de Rserve avec la commande \: 
 statsengine.r.core.messages.RCore.error_matrixIsEmpty=La matrice est vide.
 statsengine.r.core.messages.RCore.error_requestedObjectNotFoundInR=L''objet demandé ({0}) n''a pas été trouvé dans l''espace de travail R.
Index: TXM/trunk/org.txm.translate.rcp/messages.properties
===================================================================
--- TXM/trunk/org.txm.translate.rcp/messages.properties	(revision 3554)
+++ TXM/trunk/org.txm.translate.rcp/messages.properties	(revision 3555)
@@ -1581,7 +1581,7 @@
 statsengine.r.core.messages.RCore.error_failedToInitializeFileTransfert=** Failed to initialize file transfer\: {0}.
 statsengine.r.core.messages.RCore.error_failedToLoadLibrary=** Failed to load the {0} library\: {1}.
 statsengine.r.core.messages.RCore.error_failedToRunREG=** Failed to run REG to locate the R program.
-statsengine.r.core.messages.RCore.error_failedToStartRServe=** Failed to start the statistics engine (RServe).
+statsengine.r.core.messages.RCore.error_failedToStartRServe=** Failed to start the statistics engine (Rserve).
 statsengine.r.core.messages.RCore.error_failedToStartRServeWithCommand=** Failed to start Rserve with command\: 
 statsengine.r.core.messages.RCore.error_matrixIsEmpty=Matrix is empty.
 statsengine.r.core.messages.RCore.error_requestedObjectNotFoundInR=The requested object ({0}) was not found in the R workspace.
@@ -1624,12 +1624,12 @@
 statsengine.r.rcp.messages.RUI.remoteConnection=Remote connection
 statsengine.r.rcp.messages.RUI.rPackageDiagnostic=R package diagnostic
 statsengine.r.rcp.messages.RUI.rserveArgs=Rserve arguments
-statsengine.r.rcp.messages.RUI.runRServeInDebugMode=Run RServe in debug mode
+statsengine.r.rcp.messages.RUI.runRServeInDebugMode=Run Rserve in debug mode
 statsengine.r.rcp.messages.RUI.sendingToRWorkspaceColon=Sending to R Workspace\: 
 statsengine.r.rcp.messages.RUI.serverAddress=Server address
 statsengine.r.rcp.messages.RUI.showEvalLogs=Showing R evaluation logs
 statsengine.r.rcp.messages.RUI.somePackagesAreMissingSeeConsoleForDetails=Some packages are missing. See the console for details.
-statsengine.r.rcp.messages.RUI.theRStatEngineIsNotRunningTryingToReinstallThePackagesRServeFactoMineRTextometry=The R statistical engine is not accessible. Try to reinstall R packets needed for TXM (RServe, FactoMineR, textometry...)
+statsengine.r.rcp.messages.RUI.theRStatEngineIsNotRunningTryingToReinstallThePackagesRServeFactoMineRTextometry=The R statistical engine is not accessible. Try to reinstall R packets needed for TXM (Rserve, FactoMineR, textometry...)
 statsengine.r.rcp.messages.RUI.tXMCouldNotLoadTheFactoMineRRPackageTheCorrespondanceAnalysisClassificationCommandsWontBeAvailable=TXM could not load the 'FactoMineR' R package. The Correspondance analysis, Classification commands won't be available
 statsengine.r.rcp.messages.RUI.tXMCouldNotLoadTheTextometryRPackageTheCooccurenceSpecificityAndProgressionCommandsWontBeAvailable=TXM could not load the 'textometry' R package. The Cooccurence, Specificity and Progression commands will not be available
 statsengine.r.rcp.messages.RUI.tXMCouldNotReinstallRPackagesPleaseDoItManuallySeeManual=TXM could not re-install R packages. Please do it manually (see manual).
Index: TXM/trunk/org.txm.translate.rcp/messages2.properties
===================================================================
--- TXM/trunk/org.txm.translate.rcp/messages2.properties	(revision 3554)
+++ TXM/trunk/org.txm.translate.rcp/messages2.properties	(revision 3555)
@@ -290,7 +290,7 @@
 core.messages.TXMCore.failedToExecTskillCqpserverexeColon=** Failed to execute ''tskill cqpserver.exe''\: {0}.
 rcp.messages.TXMUI.chooseTheLanguage=Choose the language
 specificities.rcp.messages.SpecificitiesUI.t=\ T
-statsengine.r.rcp.messages.RUI.runRServeInDebugMode=Run RServe in debug mode
+statsengine.r.rcp.messages.RUI.runRServeInDebugMode=Run Rserve in debug mode
 searchengine.cqp.core.messages.CQPSearchEngineCore.sourceRegistryDoesNotExistsColon=No registry file in {0}.
 core.messages.TXMCore.errorRegDirColon=** Error in the registry directory\: 
 searchengine.cqp.rcp.messages.CQPUI.additionalAmpoptionsForTheCWBServerColon=Additional &options for the CQP server\: 
@@ -308,7 +308,7 @@
 statsengine.core.messages.StatsEngineCore.theIndexArrayCanNotBeNullOrEmpty=** The index table can not be null or empty.
 ahc.rcp.messages.AHCUI.numberOfClustersColon=Number of clusters\:
 lexicaltable.rcp.messages.LexicalTableUI.mergingLines=Merging lines
-statsengine.r.rcp.messages.RUI.theRStatEngineIsNotRunningTryingToReinstallThePackagesRServeFactoMineRTextometry=The R statistical engine is not accessible. Try to reinstall R packets needed for TXM (RServe, FactoMineR, textometry...)
+statsengine.r.rcp.messages.RUI.theRStatEngineIsNotRunningTryingToReinstallThePackagesRServeFactoMineRTextometry=The R statistical engine is not accessible. Try to reinstall R packets needed for TXM (Rserve, FactoMineR, textometry...)
 core.messages.TXMCore.failedToExecTaskkillIMCqpserverexeFColon=** Failed to execute ''taskkill /IM cqpserver.exe /F''\: {0}.
 rcp.messages.TXMUI.loadingBinaryCorpus=Loading binary corpus
 core.messages.TXMCore.noValuesGiven=No values given
@@ -648,7 +648,7 @@
 rcp.messages.TXMUI.errorWhileLoadingTXMColon=** TXM startup error\: {0}.
 searchengine.cqp.core.messages.CQPSearchEngineCore.noError=No error to notify.
 rcp.messages.TXMUI.saveScriptBeforeExecution=Save script before execution
-statsengine.r.core.messages.RCore.error_failedToStartRServe=** Failed to start the statistics engine (RServe).
+statsengine.r.core.messages.RCore.error_failedToStartRServe=** Failed to start the statistics engine (Rserve).
 rcp.messages.TXMUI.editTheNameOfTheNewLineCreatedByTheMergedLines=Enter the name of the new line resulting from the merge
 core.messages.TXMCore.error_errorWhileSortingResult=** Error while sorting result.
 rcp.messages.TXMUI.newCorpusColonP0=New corpus\: {0}.
Index: TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/swt/widget/parameters/ParametersDialog.java
===================================================================
--- TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/swt/widget/parameters/ParametersDialog.java	(revision 3554)
+++ TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/swt/widget/parameters/ParametersDialog.java	(revision 3555)
@@ -87,7 +87,7 @@
 	 * @param args pre-filled fields
 	 */
 	public ParametersDialog(Shell parentShell, Object bean, List<OptionHandler> allParameters, Map args, Map defaultArgs) {
-
+		
 		super(parentShell);
 		if (bean != null) {
 			this.script = bean.getClass().getName();
@@ -564,135 +564,145 @@
 	 * @return true if the user has clicked on the "OK" button
 	 */
 	public static boolean open(final Object bean) {
-		errorOpen = true;
-		retOpen = false;
 		
-		// if (!(bean instanceof groovy.lang.Script)) {
-		// System.out.println(Messages.ParametersDialog_15);
-		// return false;
-		// }
-		
-		Object oArgs = null;
-		if (bean instanceof groovy.lang.Script) {
-			groovy.lang.Script script = (groovy.lang.Script) bean;
+		try {
 			
-			// if the "args" variable exists then use its values. Can be used to set a default value by another Macro
-			if (script.getBinding().hasVariable("args")) {
-				oArgs = script.getBinding().getVariable("args"); //$NON-NLS-1$
+			errorOpen = true;
+			retOpen = false;
+			
+			// if (!(bean instanceof groovy.lang.Script)) {
+			// System.out.println(Messages.ParametersDialog_15);
+			// return false;
+			// }
+			
+			Object oArgs = null;
+			if (bean instanceof groovy.lang.Script) {
+				groovy.lang.Script script = (groovy.lang.Script) bean;
+				
+				// if the "args" variable exists then use its values. Can be used to set a default value by another Macro
+				if (script.getBinding().hasVariable("args")) {
+					oArgs = script.getBinding().getVariable("args"); //$NON-NLS-1$
+				}
 			}
-		}
-		
-		Object oDefaultArgs = null;
-		if (bean instanceof groovy.lang.Script) {
-			groovy.lang.Script script = (groovy.lang.Script) bean;
 			
-			// if the "defaultArgs" variable exists then use its values. Can be used to set a default value by another Macro
-			if (script.getBinding().hasVariable("defaultArgs")) {
-				oDefaultArgs = script.getBinding().getVariable("defaultArgs"); //$NON-NLS-1$
+			Object oDefaultArgs = null;
+			if (bean instanceof groovy.lang.Script) {
+				groovy.lang.Script script = (groovy.lang.Script) bean;
+				
+				// if the "defaultArgs" variable exists then use its values. Can be used to set a default value by another Macro
+				if (script.getBinding().hasVariable("defaultArgs")) {
+					oDefaultArgs = script.getBinding().getVariable("defaultArgs"); //$NON-NLS-1$
+				}
 			}
-		}
-		
-		final Map args;
-		if (oArgs == null || !(oArgs instanceof Map)) {
-			args = new HashMap<String, Object>();
-		}
-		else {
-			args = (Map) oArgs;
-		}
-		
-		if (bean instanceof groovy.lang.Script) { // create the args binding if not already existing
-			groovy.lang.Script script = (groovy.lang.Script) bean;
-			if (!script.getBinding().hasVariable("args")) {
-				script.getBinding().setVariable("args", args);
+			
+			final Map args;
+			if (oArgs == null || !(oArgs instanceof Map)) {
+				args = new HashMap<String, Object>();
 			}
-		}
-		
-		final Map defaultArgs;
-		if (oDefaultArgs == null || !(oDefaultArgs instanceof Map)) {
-			defaultArgs = new HashMap<String, Object>();
-		}
-		else {
-			defaultArgs = (Map) oDefaultArgs;
-		}
-		
-		if (bean instanceof groovy.lang.Script) { // create the args binding if not already existing
-			groovy.lang.Script script = (groovy.lang.Script) bean;
-			if (!script.getBinding().hasVariable("defaultArgs")) {
-				script.getBinding().setVariable("defaultArgs", defaultArgs);
+			else {
+				args = (Map) oArgs;
 			}
-		}
-		
-		Log.finest("Calling syncExec on display: " + Display.getDefault());
-		Display.getDefault().syncExec(new Runnable() {
 			
-			@Override
-			public void run() {
-				try {
-					boolean okNames = true;
-					CmdLineParser parser = new CmdLineParser(bean);
-					
-					Display display = Display.getCurrent();
-					Shell shell = display.getActiveShell();
-					Log.finest("Display=" + display + " Shell=" + shell);
-					// check names
-					Class c = bean.getClass();
-					Log.finest("Parsing options: " + parser.getOptions());
-					for (OptionHandler opt : parser.getOptions()) { // pre set variable using the defaultArgs binding
-						try {
-							if (opt.option instanceof NamedOptionDef) {
-								NamedOptionDef option = (NamedOptionDef) opt.option;
-								c.getDeclaredField(option.name());
-								if (defaultArgs.containsKey(option.name())) {
-									option.def = ""+defaultArgs.get(option.name());
+			if (bean instanceof groovy.lang.Script) { // create the args binding if not already existing
+				groovy.lang.Script script = (groovy.lang.Script) bean;
+				if (!script.getBinding().hasVariable("args")) {
+					script.getBinding().setVariable("args", args);
+				}
+			}
+			
+			final Map defaultArgs;
+			if (oDefaultArgs == null || !(oDefaultArgs instanceof Map)) {
+				defaultArgs = new HashMap<String, Object>();
+			}
+			else {
+				defaultArgs = (Map) oDefaultArgs;
+			}
+			
+			if (bean instanceof groovy.lang.Script) { // create the args binding if not already existing
+				groovy.lang.Script script = (groovy.lang.Script) bean;
+				if (!script.getBinding().hasVariable("defaultArgs")) {
+					script.getBinding().setVariable("defaultArgs", defaultArgs);
+				}
+			}
+			
+			Log.finest("Calling syncExec on display: " + Display.getDefault());
+			Display.getDefault().syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					try {
+						boolean okNames = true;
+						CmdLineParser parser = new CmdLineParser(bean);
+						
+						Display display = Display.getCurrent();
+						Shell shell = display.getActiveShell();
+						Log.finest("Display=" + display + " Shell=" + shell);
+						// check names
+						Class c = bean.getClass();
+						Log.finest("Parsing options: " + parser.getOptions());
+						for (OptionHandler opt : parser.getOptions()) { // pre set variable using the defaultArgs binding
+							try {
+								if (opt.option instanceof NamedOptionDef) {
+									NamedOptionDef option = (NamedOptionDef) opt.option;
+									c.getDeclaredField(option.name());
+									if (defaultArgs.containsKey(option.name())) {
+										option.def = ""+defaultArgs.get(option.name());
+									}
 								}
 							}
+							catch (NoSuchFieldException e) {
+								Log.warning(TXMUIMessages.errorInAtOptionNameDeclarationColon + e.getMessage());
+								okNames = false;
+							}
 						}
-						catch (NoSuchFieldException e) {
-							Log.warning(TXMUIMessages.errorInAtOptionNameDeclarationColon + e.getMessage());
-							okNames = false;
-						}
-					}
-					if (okNames) {
-						ParametersDialog dialog = new ParametersDialog(shell, bean, parser.getOptions(), args, defaultArgs);
-						if (dialog.getShell() != null) {
-							Log.finest("Activating shell:" + shell);
-							shell.setActive();
-						}
-						
-						ArrayList missingParameters = dialog.getParametersToSet();
-						ArrayList missingMandatoryParameters = dialog.getMandatoryParametersToSet();
-						
-						dialog.initializeMacroVariables(); // with args
-						if (missingParameters.size() > 0) {
-							Log.finer("The parameters dialog must be opened to fill parameters " + missingParameters + " and all mandatory fields: " + missingMandatoryParameters);
-							retOpen = dialog.open() == ParametersDialog.OK;
-							errorOpen = dialog.isError();
-						}
-						else { // fields initialized by 'args'
-							Log.finest("The parameters dialog dont need to be opened all mandatory fields are set: " + args);
-							if (dialog.getNumberOfFields() > 0) dialog.saveParameters();
-							retOpen = true;
-							errorOpen = false;
-						}
-						
-						if (bean instanceof groovy.lang.Script) { // reset the timer binding if already existing
+						if (okNames) {
+							ParametersDialog dialog = new ParametersDialog(shell, bean, parser.getOptions(), args, defaultArgs);
+							if (dialog.getShell() != null) {
+								Log.finest("Activating shell:" + shell);
+								shell.setActive();
+							}
 							
-							groovy.lang.Script script = (groovy.lang.Script) bean;
-							if (script.getBinding().hasVariable("timer")) {
-								Log.finest("Reset groovy execution timer: " + args);
-								Timer timer = (Timer) script.getBinding().getVariable("timer");
-								timer.reset();
+							ArrayList missingParameters = dialog.getParametersToSet();
+							ArrayList missingMandatoryParameters = dialog.getMandatoryParametersToSet();
+							
+							dialog.initializeMacroVariables(); // with args
+							if (missingParameters.size() > 0) {
+								Log.finer("The parameters dialog must be opened to fill parameters " + missingParameters + " and all mandatory fields: " + missingMandatoryParameters);
+								retOpen = dialog.open() == ParametersDialog.OK;
+								errorOpen = dialog.isError();
 							}
+							else { // fields initialized by 'args'
+								Log.finest("The parameters dialog dont need to be opened all mandatory fields are set: " + args);
+								if (dialog.getNumberOfFields() > 0) dialog.saveParameters();
+								retOpen = true;
+								errorOpen = false;
+							}
+							
+							if (bean instanceof groovy.lang.Script) { // reset the timer binding if already existing
+								
+								groovy.lang.Script script = (groovy.lang.Script) bean;
+								if (script.getBinding().hasVariable("timer")) {
+									Log.finest("Reset groovy execution timer: " + args);
+									Timer timer = (Timer) script.getBinding().getVariable("timer");
+									timer.reset();
+								}
+							}
 						}
 					}
+					catch (Throwable e) {
+						Log.severe("Could not open the parameter dialog: " + e);
+						Log.printStackTrace(e);
+						errorOpen = true;
+					}
 				}
-				catch (Throwable e) {
-					Log.severe("Could not open the parameter dialog: " + e);
-					Log.printStackTrace(e);
-					errorOpen = true;
-				}
-			}
-		});
+			});
+			
+		} catch (Throwable e) {
+			Log.severe("Could not open the parameter dialog: " + e);
+			Log.printStackTrace(e);
+			errorOpen = true;
+		}
+		
 		return retOpen && !errorOpen;
 	}
 	
Index: TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/handlers/scripts/ExecuteGroovyScript.java
===================================================================
--- TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/handlers/scripts/ExecuteGroovyScript.java	(revision 3554)
+++ TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/handlers/scripts/ExecuteGroovyScript.java	(revision 3555)
@@ -282,7 +282,7 @@
 					}
 				} catch (Exception e) {
 					Log.severe(TXMUIMessages.errorDuringScriptExecutionColon+e);
-					org.txm.utils.logger.Log.printStackTrace(e);
+					e.printStackTrace();
 				} finally {
 					monitor.done();			
 				}
Index: TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/preferences/DebugPreferencePage.java
===================================================================
--- TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/preferences/DebugPreferencePage.java	(revision 3554)
+++ TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/preferences/DebugPreferencePage.java	(revision 3555)
@@ -14,27 +14,34 @@
  *
  */
 public class DebugPreferencePage extends TXMPreferencePage {
-
-
+	
+	
 	@Override
 	public void createFieldEditors() {
+		
 		// Show all result nodes in Corpora view
 		addField(new BooleanFieldEditor(TBXPreferences.SHOW_ALL_RESULT_NODES, TXMUIMessages.showAllResultNodesInCorporaView, getFieldEditorParent()));
+		// change TXM update site base URL
 		addField(new StringFieldEditor(TBXPreferences.UPDATESITE, TXMUIMessages.UpdateSiteAddress, getFieldEditorParent()));
+		// enable some Eclipse features deactivated for TXM
+		addField(new BooleanFieldEditor(TBXPreferences.EXPERT_USER, "Expert mode", getFieldEditorParent()));
 	}
 	
 	
 	@Override
 	public void init(IWorkbench workbench) {
+		
 		this.setPreferenceStore(new TXMPreferenceStore(TBXPreferences.getInstance().getPreferencesNodeQualifier()));
 	}
 	
 	@Override
 	public boolean performOk() {
-		if(super.performOk())	{
+		
+		if (super.performOk()) {
 			CorporaView.refresh();
 			return true;
-		};
+		}
+		;
 		return false;
 	}
-}
\ No newline at end of file
+}
Index: TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/preferences/RCPPreferences.java
===================================================================
--- TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/preferences/RCPPreferences.java	(revision 3554)
+++ TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/preferences/RCPPreferences.java	(revision 3555)
@@ -102,7 +102,7 @@
 		preferences.putBoolean(CGU, false);
 		
 		preferences.putInt(NO_SESSION, 1);
-		preferences.putInt(MAX_NUMBER_OF_COLUMNS, 100);
+		preferences.putInt(MAX_NUMBER_OF_COLUMNS, 50);
 	}
 	
 	/**
Index: TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/editors/TXMEditor.java
===================================================================
--- TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/editors/TXMEditor.java	(revision 3554)
+++ TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/editors/TXMEditor.java	(revision 3555)
@@ -5,6 +5,7 @@
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -1518,6 +1519,17 @@
 				continue;
 			}
 			
+			Field targetField = BeanParameters.getField(getResult(), key);
+			
+//			Field targetField = null;
+//			for (Field f2 : this.getResult().getClass().getFields()) {
+//				Parameter a = f2.getAnnotation(Parameter.class);
+//				if (a != null && a.key().equals(parameter.key())) {
+//					targetField = f2;
+//					break;
+//				}
+//			}
+			
 			try {
 				f.setAccessible(true);
 				Object object = f.get(this);
@@ -1600,7 +1612,23 @@
 					value = ((NewNavigationWidget) object).getCurrentPosition();
 				}
 				else if (object instanceof Combo) {
-					value = ((Combo) object).getText();
+					String s = ((Combo) object).getText();
+					Class<?> clazz = targetField.getType();
+					if (clazz.equals(String.class)) {
+						value = s;
+					} else if (clazz.equals(List.class)) {
+						if (!s.isEmpty()) {
+							value = new ArrayList<>(Arrays.asList(s.split(",")));
+						} else {
+							value = new ArrayList<>();
+						}
+					}
+					
+//					else if (value instanceof List) {
+//						if (!s.isEmpty()) {
+//							value = new ArrayList<>(Arrays.asList(s.split(",")));
+//						}
+//					}
 				}
 				else {
 					value = object;
Index: TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/editors/ITXMResultEditor.java
===================================================================
--- TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/editors/ITXMResultEditor.java	(revision 3554)
+++ TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/editors/ITXMResultEditor.java	(revision 3555)
@@ -47,7 +47,7 @@
 	
 	public void removeLinkedEditor(ITXMResultEditor<TXMResult> editor);
 	
-	public void addLinkedEditor(ITXMResultEditor<T> editor);
+	public void addLinkedEditor(ITXMResultEditor<TXMResult> editor);
 	
 	public <E extends ITXMResultEditor<TXMResult>> E getLinkedEditor(Class<E> editorClass);
 	
