Index: tmp/org.txm.specificities.rcp/src/org/txm/specificities/rcp/editors/SpecificitiesEditor.java
===================================================================
--- tmp/org.txm.specificities.rcp/src/org/txm/specificities/rcp/editors/SpecificitiesEditor.java	(revision 2947)
+++ tmp/org.txm.specificities.rcp/src/org/txm/specificities/rcp/editors/SpecificitiesEditor.java	(revision 2948)
@@ -27,6 +27,8 @@
 //
 package org.txm.specificities.rcp.editors;
 
+import java.util.ArrayList;
+
 import org.eclipse.jface.viewers.ArrayContentProvider;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.TableViewer;
@@ -55,6 +57,7 @@
 import org.txm.searchengine.cqp.corpus.CQPCorpus;
 import org.txm.searchengine.cqp.corpus.MainCorpus;
 import org.txm.searchengine.cqp.corpus.Subcorpus;
+import org.txm.searchengine.cqp.corpus.WordProperty;
 import org.txm.specificities.core.functions.Specificities;
 import org.txm.specificities.core.preferences.SpecificitiesPreferences;
 import org.txm.specificities.rcp.messages.SpecificitiesUIMessages;
@@ -131,8 +134,12 @@
 			if (!this.getResult().getParent().isVisible()) {
 				// unit property
 				new Label(mainParametersArea, SWT.NONE).setText(TXMCoreMessages.common_property);
+				
+				ArrayList<WordProperty> availableProperties = new ArrayList<>();
+				availableProperties.addAll(CQPCorpus.getFirstParentCorpus(this.getResult()).getOrderedProperties());
+				availableProperties.addAll(CQPCorpus.getFirstParentCorpus(this.getResult()).getVirtualProperties());
 				this.unitPropertyComboViewer = new PropertiesComboViewer(mainParametersArea, this, false,
-						CQPCorpus.getFirstParentCorpus(this.getResult()).getOrderedProperties(),
+						availableProperties,
 						this.getResult().getUnitProperty(), false);
 			}
 			
Index: tmp/org.txm.core.tests/src/org/txm/core/tests/manual/ToolBoxTesterRCPApplication.java
===================================================================
--- tmp/org.txm.core.tests/src/org/txm/core/tests/manual/ToolBoxTesterRCPApplication.java	(revision 2947)
+++ tmp/org.txm.core.tests/src/org/txm/core/tests/manual/ToolBoxTesterRCPApplication.java	(revision 2948)
@@ -12,6 +12,7 @@
 import org.txm.searchengine.cqp.corpus.Property;
 import org.txm.searchengine.cqp.corpus.StructuralUnit;
 import org.txm.searchengine.cqp.corpus.StructuralUnitProperty;
+import org.txm.searchengine.cqp.corpus.WordProperty;
 
 /**
  * 
@@ -68,9 +69,9 @@
 			StructuralUnitProperty text_type = textUnit.getProperty("type");
 			StructuralUnitProperty text_id = textUnit.getProperty("id");
 			StructuralUnit sUnit = corpus.getStructuralUnit("s");
-			Property word = corpus.getProperty("word");
-			Property enpos = corpus.getProperty("enpos");
-			Property enlemma = corpus.getProperty("enlemma");
+			WordProperty word = corpus.getProperty("word");
+			WordProperty enpos = corpus.getProperty("enpos");
+			WordProperty enlemma = corpus.getProperty("enlemma");
 
 			// CQP Lexicon
 			System.out.println("**************************************************");
Index: tmp/org.txm.cooccurrence.core/src/org/txm/cooccurrence/core/functions/Cooccurrence.java
===================================================================
--- tmp/org.txm.cooccurrence.core/src/org/txm/cooccurrence/core/functions/Cooccurrence.java	(revision 2947)
+++ tmp/org.txm.cooccurrence.core/src/org/txm/cooccurrence/core/functions/Cooccurrence.java	(revision 2948)
@@ -62,6 +62,7 @@
 import org.txm.searchengine.cqp.corpus.QueryResult;
 import org.txm.searchengine.cqp.corpus.StructuralUnit;
 import org.txm.searchengine.cqp.corpus.StructuralUnitProperty;
+import org.txm.searchengine.cqp.corpus.VirtualProperty;
 import org.txm.searchengine.cqp.corpus.WordProperty;
 import org.txm.searchengine.cqp.corpus.query.Match;
 import org.txm.searchengine.cqp.corpus.query.CQLQuery;
@@ -81,149 +82,149 @@
  * 
  */
 public class Cooccurrence extends TXMResult {
-	
+
 	/** The nocooc. */
 	protected static int nocooc = 1;
-	
+
 	/** The prefix r. */
 	protected static String prefixR = "Cooccurrences"; //$NON-NLS-1$
-	
+
 	/** The allsignaturesstr. */
 	private HashMap<Integer, String> allsignaturesstr;
-	
+
 	/** The anticontextquery. */
 	private CQLQuery anticontextquery;
-	
+
 	private boolean buildLexicalTableWithCooccurrents;
-	
+
 	/** The conclines. */
 	List<org.txm.concordance.core.functions.Line> conclines;
-	
+
 	/** The conc. */
 	Concordance concordance;
-	
+
 	/** The contextquery. */
 	private CQLQuery contextQuery;
-	
+
 	/** The count. */
 	HashMap<String, Integer> count;
-	
+
 	// contains the sum of distances
 	/** The counts. */
 	HashMap<String, Integer> counts = new HashMap<>();
-	
+
 	/** The dist. */
 	HashMap<String, Float> dist;
-	
+
 	// System.out.println("Matches: focus: "+m1.size()+" full: "+m2.size()+" anti: "+m3.size());
 	// System.out.println("T matches : "+(System.currentTimeMillis()- time)); //$NON-NLS-1$
 	/** The distances. */
 	HashMap<String, Double> distances = new HashMap<>();
-	
+
 	/** The FA. */
 	int FA = -1;
-	
+
 	/** The freq. */
 	HashMap<String, Integer> freq;
-	
+
 	/** The index. */
 	Index index;
-	
+
 	/** The indexfreqs. */
 	HashMap<String, Integer> indexfreqs = new HashMap<>();
-	
+
 	/** The keys to string. */
 	private HashMap<String, String> keysToString;
-	
+
 	/** The lines. */
 	List<CLine> lines = new ArrayList<>();
-	
+
 	/** The lt. */
 	private LexicalTableImpl lt;
-	
+
 	/** The m1. */
 	private List<Match> m1;
-	
+
 	/** The m2. */
 	private List<Match> m2;
-	
+
 	/** The m3. */
 	private List<Match> m3;
-	
+
 	int numberOfCooccurrents = -1;
-	
+
 	/** The number of keyword. */
 	int numberOfKeyword = 0;
-	
+
 	/** The occproperties. */
 	HashMap<String, List<String>> occproperties;
-	
+
 	/** The P. */
 	int P = -1;
-	
+
 	/** The reference corpus to use = the R symbol that point to a matrix WordxFreqs. */
 	String referenceCorpus;
-	
+
 	/** The scores. */
 	HashMap<String, Double> scores;
-	
+
 	/** The symbol. */
 	private String symbol;
-	
+
 	/** The writer. */
 	private BufferedWriter writer;
-	
+
 	@Parameter(key = CooccurrencePreferences.QUERY_FILTER)
 	protected String pCooccurentQueryFilter = "[]"; //$NON-NLS-1$
-	
+
 	/** The mincof. */
 	@Parameter(key = CooccurrencePreferences.MIN_COUNT)
 	protected Integer pFCoocFilter;
-	
+
 	/** The minf. */
 	@Parameter(key = TXMPreferences.F_MIN)
 	protected Integer pFminFilter;
-	
+
 	/** The include xpivot. */
 	@Parameter(key = CooccurrencePreferences.INCLUDE_X_PIVOT)
 	protected Boolean pIncludeXpivot;
-	
+
 	/** The maxleft. */
 	@Parameter(key = CooccurrencePreferences.MAX_LEFT)
 	protected Integer pMaxLeftContextSize;
-	
+
 	/** The maxright. */
 	@Parameter(key = CooccurrencePreferences.MAX_RIGHT)
 	protected Integer pMaxRightContextSize;
-	
+
 	/** The minleft. */
 	@Parameter(key = CooccurrencePreferences.MIN_LEFT)
 	protected Integer pMinLeftContextSize;
-	
+
 	/** The minright. */
 	@Parameter(key = CooccurrencePreferences.MIN_RIGHT)
 	protected Integer pMinRightContextSize;
-	
+
 	/** The cooccurrents properties to display. */
 	@Parameter(key = CooccurrencePreferences.UNIT_PROPERTIES)
 	protected List<WordProperty> pProperties;
-	
+
 	/** The keyword query. */
 	@Parameter(key = CooccurrencePreferences.QUERY)
 	protected CQLQuery pQuery;
-	
+
 	/** The minscore. */
 	@Parameter(key = CooccurrencePreferences.MIN_SCORE)
 	protected Float pScoreMinFilter;
-	
+
 	/**
 	 * The structural unit context limit.
 	 * In null then the unit property is used.
 	 */
 	@Parameter(key = CooccurrencePreferences.STRUCTURAL_UNIT_LIMIT, electric = false)
 	protected StructuralUnit pStructuralUnitLimit;
-	
-	
+
+
 	/**
 	 * Creates a not computed cooccurrence from the specified corpus.
 	 * 
@@ -232,7 +233,7 @@
 	public Cooccurrence(CQPCorpus parent) {
 		super(parent);
 	}
-	
+
 	/**
 	 * Creates a not computed cooccurrence from a parameters node.
 	 * 
@@ -241,15 +242,15 @@
 	public Cooccurrence(String parametersNodePath) {
 		super(parametersNodePath);
 	}
-	
-	
-	
+
+
+
 	@Override
 	protected boolean _compute(TXMProgressMonitor monitor) throws CqiClientException, IOException, CqiServerError, StatException {
 		// System.out.println("cooc: "+corpus+" "+query+" "+properties+" "+limit+" "+maxLeft+" "+minLeft+" "+minRight+" "+maxRight+" "+minFreq+" "+minCof+" "+minScore+" "+includeXpivot);
-		
+
 		monitor.setTask(CooccurrenceCoreMessages.info_buildingQueries);
-		
+
 		// clear data
 		try {
 			this.numberOfCooccurrents = -1;
@@ -266,46 +267,46 @@
 		}
 		catch (Exception e) {
 		}
-		
+
 		if (!this.stepQueryLimits()) {
 			return false;
 		}
-		
+
 		monitor.setTask(CooccurrenceCoreMessages.info_retreivingMatches);
 		if (!this.stepGetMatches()) {
 			return false;
 		}
 		monitor.worked(20);
-		
+
 		monitor.setTask(CooccurrenceCoreMessages.info_buildingLineSignatures);
 		if (!this.stepBuildSignatures()) {
 			return false;
 		}
 		monitor.worked(20);
-		
+
 		monitor.setTask(CooccurrenceCoreMessages.info_counting);
 		if (!this.stepCount()) {
 			return false;
 		}
 		monitor.worked(20);
-		
+
 		monitor.setTask(CooccurrenceCoreMessages.info_buildingLexicalTable);
 		if (!this.stepBuildLexicalTable(monitor)) {
 			return false;
 		}
 		monitor.worked(10);
-		
+
 		monitor.setTask(CooccurrenceCoreMessages.info_computingSpecificitiesScores);
 		if (!this.stepGetScores()) {
 			return false;
 		}
-		
+
 		this.clearMemory();
 		monitor.done();
-		
+
 		return true;
 	}
-	
+
 	@Override
 	public boolean loadParameters() throws CqiClientException {
 		pProperties = (List<WordProperty>) Property.stringToProperties(getCorpus(), this.getStringParameterValue(TXMPreferences.UNIT_PROPERTIES));
@@ -313,23 +314,23 @@
 		pStructuralUnitLimit = this.getCorpus().getStructuralUnit(this.getStringParameterValue(CooccurrencePreferences.STRUCTURAL_UNIT_LIMIT));
 		return true;
 	}
-	
+
 	@Override
 	public boolean saveParameters() {
 		this.saveParameter(TXMPreferences.UNIT_PROPERTIES, Property.propertiesToString(this.pProperties));
-		
+
 		if (pQuery != null) {
 			this.saveParameter(TXMPreferences.QUERY, pQuery.getQueryString());
 		}
-		
+
 		if (pStructuralUnitLimit != null) {
 			this.saveParameter(CooccurrencePreferences.STRUCTURAL_UNIT_LIMIT, this.pStructuralUnitLimit.getName());
 		}
-		
+
 		return true;
 	}
-	
-	
+
+
 	/**
 	 * As r matrix.
 	 *
@@ -338,13 +339,13 @@
 	 */
 	public String asRMatrix() throws RWorkspaceException {
 		symbol = prefixR + nocooc;
-		
+
 		String[] occ = new String[this.lines.size()];
 		int[] freq = new int[this.lines.size()];
 		int[] cofreq = new int[this.lines.size()];
 		double[] score = new double[this.lines.size()];
 		double[] dist = new double[this.lines.size()];
-		
+
 		int i = 0;
 		for (CLine line : this.lines) {
 			occ[i] = line.occ;
@@ -354,53 +355,53 @@
 			dist[i] = line.distmoyenne;
 			i++;
 		}
-		
+
 		RWorkspace rw = RWorkspace.getRWorkspaceInstance();
 		rw.addVectorToWorkspace("coococc", occ); //$NON-NLS-1$
 		rw.addVectorToWorkspace("coocfreq", freq); //$NON-NLS-1$
 		rw.addVectorToWorkspace("cooccofreq", cofreq); //$NON-NLS-1$
 		rw.addVectorToWorkspace("coocscore", score); //$NON-NLS-1$
 		rw.addVectorToWorkspace("coocmeandist", dist); //$NON-NLS-1$
-		
+
 		rw.eval(symbol + "<- matrix(data = c(coocfreq, cooccofreq, coocscore, coocmeandist), nrow = " + this.lines.size() + ", ncol = 4)"); //$NON-NLS-1$ //$NON-NLS-2$
 		rw.eval("rownames(" + symbol + " ) <- coococc"); //$NON-NLS-1$ //$NON-NLS-2$
 		rw.eval("colnames(" + symbol + " ) <- c('freq', 'cofreq', 'score', 'dist')"); //$NON-NLS-1$ //$NON-NLS-2$
 		rw.eval(symbol + "<- list(data=" + symbol //$NON-NLS-1$
-		// + ", leftcontext="+this.leftContextSize
-		// + ", rightcontext="+this.rightContextSize
-		// + ", query=\""+this.query.getQueryString()+"\""
+				// + ", leftcontext="+this.leftContextSize
+				// + ", rightcontext="+this.rightContextSize
+				// + ", query=\""+this.query.getQueryString()+"\""
 				+ ")"); //$NON-NLS-1$
-		
+
 		nocooc++;
 		return symbol;
 	}
-	
+
 	@Override
 	public boolean canCompute() {
-		
+
 		if (pQuery == null || pQuery.isEmpty()) {
 			Log.fine("No query set.");
 			return false;
 		}
-		
+
 		if (pProperties == null) {
 			Log.fine("No properties set.");
 			return false;
 		}
-		
+
 		if (getCorpus() == null) {
 			Log.fine("No corpus set.");
 			return false;
 		}
-		
+
 		if (pProperties.size() == 0) {
 			Log.fine("No properties filled.");
 			return false;
 		}
-		
+
 		return true;
 	}
-	
+
 	@Override
 	public void clean() {
 		try {
@@ -413,7 +414,7 @@
 			org.txm.utils.logger.Log.printStackTrace(e);
 		}
 	}
-	
+
 	// FIXME: useless?
 	public void clearMemory() {
 		if (distances != null) distances.clear();
@@ -429,10 +430,10 @@
 		if (dist != null) dist.clear();
 		if (freq != null) freq.clear();
 		if (scores != null) scores.clear();
-		
+
 		lt = null;
 	}
-	
+
 	// /**
 	// * Count occ.
 	// *
@@ -490,7 +491,7 @@
 	// }
 	// }
 	// }
-	
+
 	/**
 	 * Gets the corpus.
 	 *
@@ -499,7 +500,7 @@
 	public CQPCorpus getCorpus() {
 		return (CQPCorpus) this.getParent();
 	}
-	
+
 	@Override
 	public String getDetails() {
 		Object[] params = new Object[] { this.getParent(), this.pQuery, this.pProperties, this.pStructuralUnitLimit, (this.pMinLeftContextSize - 1), (this.pMaxLeftContextSize - 1),
@@ -507,7 +508,7 @@
 				(this.pMaxRightContextSize - 1), this.pFminFilter, this.pFCoocFilter, this.pScoreMinFilter };
 		return NLS.bind(CooccurrenceCoreMessages.info_details, params);
 	}
-	
+
 	@Override
 	public String getName() {
 		try {
@@ -517,43 +518,43 @@
 			return this.getSimpleName();
 		}
 	}
-	
-	
+
+
 	@Override
 	public String getSimpleName() {
 		if (this.pQuery != null && !this.pQuery.isEmpty()) {
 			StringBuffer output = new StringBuffer();
 			output.append(this.pQuery.asString());
 			output.append(WordProperty.asString(this.pProperties));
-			
+
 			if (this.pMaxLeftContextSize > 0 && this.pMaxRightContextSize > 0) {
 				output.append(" " + (this.pMaxLeftContextSize - 1) + " " + (this.pMaxRightContextSize - 1)); //$NON-NLS-1$ //$NON-NLS-2$
 			}
 			output.append(TXMCoreMessages.formatMinFilter(this.pFminFilter));
 			output.append(TXMCoreMessages.formatMinFilter(this.pFCoocFilter));
 			output.append(TXMCoreMessages.formatMinFilter(this.pScoreMinFilter));
-			
+
 			// TODO: SJ: improve the hiding or display of value according to the default preferences values
 			// output.append(TXMCoreMessages.formatMinFilter(this.pFminFilter, CooccurrencePreferences.getInstance().getInt(CooccurrencePreferences.F_MIN) + 1));
 			// output.append(TXMCoreMessages.formatMinFilter(this.pFCoocFilter, CooccurrencePreferences.getInstance().getInt(CooccurrencePreferences.MIN_COUNT) + 1));
 			// output.append(TXMCoreMessages.formatMinFilter(this.pScoreMinFilter, CooccurrencePreferences.getInstance().getDouble(CooccurrencePreferences.MIN_SCORE) + 1));
-			
-			
+
+
 			return output.toString();
 		}
 		else {
 			return this.getEmptyName();
 		}
 	}
-	
-	
+
+
 	@Override
 	public String getComputingStartMessage() {
-		return TXMCoreMessages.bind(CooccurrenceCoreMessages.cooccurrentsOfP0PropertieP1InTheP2Corpus, this.pQuery.asString(), WordProperty.asString(this.pProperties),
+		return TXMCoreMessages.bind(CooccurrenceCoreMessages.cooccurrentsOfP0PropertieP1InTheP2Corpus, (this.pQuery != null?this.pQuery.asString():"<no query>"), WordProperty.asString(this.pProperties),
 				(this.pMaxLeftContextSize - 1), (this.pMaxRightContextSize - 1), this.pFminFilter, this.pFCoocFilter, this.pScoreMinFilter, this.getCorpus().getName());
 	}
-	
-	
+
+
 	@Override
 	public String getComputingDoneMessage() {
 		if (this.lines.isEmpty()) {
@@ -563,9 +564,9 @@
 			return TXMCoreMessages.bind(CooccurrenceCoreMessages.P0CooccurentsForP1Occurrences, TXMCoreMessages.formatNumber(this.lines.size()), TXMCoreMessages.formatNumber(this.numberOfKeyword));
 		}
 	}
-	
-	
-	
+
+
+
 	/**
 	 * Gets the fA.
 	 *
@@ -574,11 +575,11 @@
 	public int getFA() {
 		return this.FA;
 	}
-	
+
 	public boolean getIncludeXPivot() {
 		return pIncludeXpivot;
 	}
-	
+
 	/**
 	 * Gets the lines.
 	 *
@@ -587,7 +588,7 @@
 	public List<CLine> getLines() {
 		return lines;
 	}
-	
+
 	/**
 	 * Gets the max left.
 	 *
@@ -596,7 +597,7 @@
 	public int getMaxLeft() {
 		return pMaxLeftContextSize;
 	}
-	
+
 	/**
 	 * Gets the max right.
 	 *
@@ -605,7 +606,7 @@
 	public int getMaxRight() {
 		return pMaxRightContextSize;
 	}
-	
+
 	/**
 	 * Gets the min left.
 	 *
@@ -614,7 +615,7 @@
 	public int getMinLeft() {
 		return pMinLeftContextSize;
 	}
-	
+
 	/**
 	 * Gets the min right.
 	 *
@@ -623,7 +624,7 @@
 	public int getMinRight() {
 		return pMinRightContextSize;
 	}
-	
+
 	/**
 	 * Gets the lines.
 	 *
@@ -638,7 +639,7 @@
 		}
 		return numberOfCooccurrents;
 	}
-	
+
 	/**
 	 * Gets the lines.
 	 *
@@ -650,7 +651,7 @@
 		}
 		return 0;
 	}
-	
+
 	/**
 	 * Gets the number of keyword.
 	 *
@@ -659,7 +660,7 @@
 	public int getNumberOfKeyword() {
 		return numberOfKeyword;
 	}
-	
+
 	/**
 	 * Gets the p.
 	 *
@@ -668,7 +669,7 @@
 	public int getP() {
 		return P;
 	}
-	
+
 	/**
 	 * Gets the properties.
 	 *
@@ -677,7 +678,7 @@
 	public List<WordProperty> getProperties() {
 		return pProperties;
 	}
-	
+
 	/**
 	 * Gets the query.
 	 *
@@ -686,8 +687,8 @@
 	public CQLQuery getQuery() {
 		return pQuery;
 	}
-	
-	
+
+
 	/**
 	 * Gets the structural unit limit.
 	 *
@@ -696,7 +697,7 @@
 	public StructuralUnit getStructuralUnitLimit() {
 		return this.pStructuralUnitLimit;
 	}
-	
+
 	/**
 	 * Gets the symbol.
 	 *
@@ -705,7 +706,7 @@
 	public String getSymbol() {
 		return this.symbol;
 	}
-	
+
 	/**
 	 * Inits the conc infos.
 	 *
@@ -713,12 +714,12 @@
 	 * @return true, if successful
 	 */
 	private boolean initConcInfos(Concordance conc) {
-		
+
 		int from = 0;
 		int to = conc.getNLines() - 1;
 		return initConcInfos(conc, from, to);
 	}
-	
+
 	/**
 	 * Inits the conc infos.
 	 *
@@ -728,7 +729,7 @@
 	 * @return true, if successful
 	 */
 	private boolean initConcInfos(Concordance conc, int from, int to) {
-		
+
 		try {
 			this.concordance = conc;
 			conclines = conc.getLines(from, to);
@@ -739,7 +740,7 @@
 		}
 		return false;
 	}
-	
+
 	/**
 	 * Inits the conc infos.
 	 *
@@ -748,7 +749,7 @@
 	 * @return true, if successful
 	 */
 	private boolean initConcInfos(Concordance conc, List<Line> conclines) {
-		
+
 		try {
 			CQPCorpus corpus = this.getCorpus();
 			this.concordance = conc;
@@ -770,7 +771,7 @@
 		}
 		return false;
 	}
-	
+
 	/**
 	 * Prints the.
 	 */
@@ -782,11 +783,11 @@
 		for (CLine line : lines)
 			System.out.println(line.resume("\t", "")); //$NON-NLS-1$ //$NON-NLS-2$
 	}
-	
+
 	public void setCoocQuery(String q) {
 		pCooccurentQueryFilter = q;
 	}
-	
+
 	/**
 	 * Sets the max left.
 	 *
@@ -795,7 +796,7 @@
 	public void setMaxLeft(int maxleft) {
 		this.pMaxLeftContextSize = maxleft;
 	}
-	
+
 	/**
 	 * Sets the max right.
 	 *
@@ -804,7 +805,7 @@
 	public void setMaxRight(int maxright) {
 		this.pMaxRightContextSize = maxright;
 	}
-	
+
 	/**
 	 * Sets the min left.
 	 *
@@ -813,7 +814,7 @@
 	public void setMinLeft(int minleft) {
 		this.pMinLeftContextSize = minleft;
 	}
-	
+
 	/**
 	 * Sets the min right.
 	 *
@@ -822,10 +823,10 @@
 	public void setMinRight(int minright) {
 		this.pMinRightContextSize = minright;
 	}
-	
+
 	public void setParameters(CQLQuery query, List<WordProperty> properties, StructuralUnit limit, int maxLeft, int minLeft, int minRight,
 			int maxRight, int minFreq, float minScore, int minCof, boolean includeXpivot, boolean buildLexicalTableWithCooccurrents) {
-		
+
 		this.pQuery = query;
 		this.pProperties = properties;
 		this.pStructuralUnitLimit = limit;
@@ -839,25 +840,25 @@
 		this.pIncludeXpivot = includeXpivot;
 		this.buildLexicalTableWithCooccurrents = buildLexicalTableWithCooccurrents;
 	}
-	
+
 	public void setIncludeXpivot(boolean b) {
 		pIncludeXpivot = b;
 	}
-	
+
 	@Override
 	public boolean setParameters(TXMParameters parameters) {
 		try {
 			CQPCorpus corpus = this.getCorpus();
 			boolean includeXpivot = parameters.getBoolean(CooccurrencePreferences.INCLUDE_X_PIVOT);
-			
+
 			String queryString = ""; //$NON-NLS-1$
 			if (parameters.get(TXMPreferences.QUERY) != null) {
 				queryString = parameters.get(TXMPreferences.QUERY).toString();
 			}
 			CQLQuery query = new CQLQuery(queryString);
-			
+
 			StructuralUnit limit = (StructuralUnit) parameters.get(CooccurrencePreferences.STRUCTURAL_UNIT_LIMIT);
-			
+
 			Object propsParam = parameters.get(CooccurrencePreferences.UNIT_PROPERTIES);
 			List<WordProperty> properties = null;
 			if (propsParam instanceof List<?>) {
@@ -866,7 +867,7 @@
 			else if (propsParam instanceof String) {
 				properties = (List<WordProperty>) Property.stringToProperties(corpus, propsParam.toString());
 			}
-			
+
 			int maxLeft = parameters.getInteger(CooccurrencePreferences.MAX_LEFT);
 			int minLeft = parameters.getInteger(CooccurrencePreferences.MIN_LEFT);
 			int maxRight = parameters.getInteger(CooccurrencePreferences.MAX_RIGHT);
@@ -875,9 +876,9 @@
 			int minCof = parameters.getInteger(CooccurrencePreferences.MIN_COUNT);
 			int minFreq = parameters.getInteger(TXMPreferences.F_MIN);
 			boolean buildLexicalTableWithCooccurrents = parameters.getBoolean(CooccurrencePreferences.PARTIAL_LEXICAL_TABLE);
-			
+
 			this.setParameters(query, properties, limit, maxLeft, minLeft, minRight, maxRight, minFreq, minScore, minCof, includeXpivot, buildLexicalTableWithCooccurrents);
-			
+
 		}
 		catch (Exception e) {
 			System.out.println("Error while setting cooccurrence parameters: " + e.getLocalizedMessage());
@@ -886,11 +887,11 @@
 		}
 		return true;
 	}
-	
+
 	public void setReferenceCorpus(String symbol) {
 		referenceCorpus = symbol;
 	}
-	
+
 	/**
 	 * Sets the structural unit limit.
 	 *
@@ -899,7 +900,7 @@
 	public void setStructuralUnitLimt(StructuralUnit su) {
 		pStructuralUnitLimit = su;
 	}
-	
+
 	/**
 	 * Sets the thresfold.
 	 *
@@ -908,12 +909,12 @@
 	 * @param score the score
 	 */
 	public void setThresfold(int freq, int count, float score) {
-		
+
 		pFminFilter = freq;
 		pFCoocFilter = count;
 		pScoreMinFilter = score;
 	}
-	
+
 	/**
 	 * Sort.
 	 *
@@ -927,7 +928,7 @@
 			Collections.sort(lines, comparator);
 		}
 	}
-	
+
 	/**
 	 * Step build lexical table.
 	 *
@@ -935,15 +936,15 @@
 	 * @throws RWorkspaceException the r workspace exception
 	 */
 	public boolean stepBuildLexicalTable(TXMProgressMonitor monitor) throws RWorkspaceException {
-		
+
 		CQPCorpus corpus = this.getCorpus();
 		String[] colnames = { corpus.getName() + "-" + pQuery.getQueryString(), pQuery.getQueryString() }; //$NON-NLS-1$
 		keysToString = new HashMap<>();
-		
+
 		// time = System.currentTimeMillis();
 		for (TXMResult rez : corpus.getChildren(Index.class)) { // TODO: fix usages of index for cooc
 			Index rezvoc = (Index) rez;
-			
+
 			if (rezvoc.getProperties().equals(pProperties)) {
 				if (rezvoc.getQuery().equals(new CQLQuery(pCooccurentQueryFilter))) {
 					if (rezvoc.getFilterFmax() == null) {
@@ -953,7 +954,7 @@
 				}
 			}
 		}
-		
+
 		// TODO: MD: implement a sibling dependency system
 		if (index == null) {
 			try {
@@ -970,7 +971,7 @@
 				return false;
 			}
 		}
-		
+
 		// ALTER THE INDEX IF A REFERENCE CORPUS IS SET -> this change the base frequencies
 		if (referenceCorpus != null && referenceCorpus.length() > 0) {
 			// voc.toTxt(new File("/home/mdecorde/TEMP/before.tsv"), "UTF-8", "\t", "");
@@ -982,7 +983,7 @@
 				return false;
 			}
 		}
-		
+
 		List<org.txm.index.core.functions.Line> vocLines = index.getAllLines();
 		int[][] freqs;
 		String[] rownames;
@@ -994,7 +995,7 @@
 			freqs = new int[vocLines.size()][2];
 			rownames = new String[vocLines.size()];
 		}
-		
+
 		int i = 0;
 		// System.out.println("T voc : "+(System.currentTimeMillis()- time)); //$NON-NLS-1$
 		// System.out.println("nb lines voc "+voclines.size());
@@ -1009,7 +1010,7 @@
 				int count = counts.get(l.getSignature());
 				int tot = l.getFrequency();
 				indexfreqs.put(l.toString(), tot);
-				
+
 				freqs[i][0] = tot - count;
 				freqs[i][1] = count;
 				i++;
@@ -1019,10 +1020,10 @@
 				rownames[i] = l.toString();
 				// System.out.println("set rowname: "+l.toString());
 				// System.out.println("("+l.getSignature()+", "+l.toString()+") : "+l.getFrequency()+" - "+counts.get(l.getSignature()));
-				
+
 				int tot = l.getFrequency();
 				indexfreqs.put(l.toString(), tot);
-				
+
 				freqs[i][0] = tot;
 				freqs[i][1] = 0;
 				i++;
@@ -1030,7 +1031,7 @@
 		}
 		index.delete(); // no more needed
 		index = null;
-		
+
 		// time = System.currentTimeMillis();
 		if (freqs.length == 0) {
 			System.out.println(CooccurrenceCoreMessages.errorColonNoCooccurrents);
@@ -1053,10 +1054,10 @@
 		// writer.close();
 		// //writer.println("Cols: "+Arrays.toString(colnames));
 		// } catch(Exception e) {e.printStackTrace();}
-		
+
 		lt = new LexicalTableImpl(freqs, rownames, colnames);
-		
-		
+
+
 		// if(referenceCorpus != null && referenceCorpus.length() > 0) {
 		// //lt.removeCol(0, false);
 		// lt.setReference(referenceCorpus);
@@ -1064,7 +1065,7 @@
 		// }
 		return true;
 	}
-	
+
 	/**
 	 * Step build signatures.
 	 *
@@ -1082,27 +1083,26 @@
 			}
 		}
 		// System.out.println("Position set: "+allpositions.size());
-		
+
 		int[] allpositionsarray = new int[allpositions.size()];
 		int pcount = 0;
 		for (int p : allpositions) {
 			allpositionsarray[pcount++] = p;
 		}
-		
+
 		HashMap<Property, int[]> propsId = new HashMap<>();
 		// HashMap<Property, String[]> propsValues = new HashMap<Property, String[]>();
-		for (Property property : pProperties) {
-			int[] indices = CorpusManager.getCorpusManager().getCqiClient()
-					.cpos2Id(property.getQualifiedName(), allpositionsarray);
+		for (WordProperty property : pProperties) {
+			int[] indices = property.cpos2Id(allpositionsarray);
 			// String[] values =
 			// CorpusManager.getCorpusManager().getCqiClient().cpos2Str(property.getQualifiedName(),allpositionsarray);
 			propsId.put(property, indices);
 			// propsValues.put(property, values);
 			// System.out.println("all "+property+" indices: "+propsId.get(property).length);
 		}
-		
+
 		// System.out.println("T values + ids: "+(System.currentTimeMillis()- time)); //$NON-NLS-1$
-		
+
 		pcount = 0;
 		for (int position : allpositionsarray) {
 			// String sign = ""; //$NON-NLS-1$
@@ -1114,11 +1114,11 @@
 			// allsignatures.put(position, sign);
 			allsignaturesstr.put(position, signstr);
 			pcount++;
-			
+
 		}
 		return true;
 	}
-	
+
 	/**
 	 * Step count.
 	 *
@@ -1126,15 +1126,15 @@
 	 */
 	public boolean stepCount() {
 		// ArrayList<Integer> keepedPosition = new ArrayList<>();
-		
+
 		int startsearchM2 = 0; // optimisation: m2 is ordered
 		int startsearchM3 = 0; // optimisation: m3 is ordered
 		// time = System.currentTimeMillis();
-		
+
 		HashMap<Integer, Integer> positionsDistances = new HashMap<>();
-		
+
 		for (Match m : m1) { // for each match = for each focus
-			
+
 			if (m.getTarget() >= 0) { // if target is set focus on target position
 				m.setStart(m.getTarget());
 				m.setEnd(m.getTarget());
@@ -1153,9 +1153,9 @@
 			}
 			if (Thread.interrupted()) return false; // stop if interrupted by user
 			// System.out.println("found n: "+n);
-			
+
 			for (int i = startsearchM3; i < m3.size(); i++) { // find next match m3 contained by m2
-				
+
 				o = m3.get(i);
 				if (o.getStart() <= m.getStart() && m.getEnd() <= o.getEnd()) {
 					startsearchM3 = i;
@@ -1164,11 +1164,11 @@
 				}
 			}
 			// System.out.println("found o: "+o);
-			
+
 			if (!matchFound) {
 				continue;
 			}
-			
+
 			int start = n.getStart();
 			int size = n.getEnd() - start + 1;
 			// if (size > 0)
@@ -1177,16 +1177,16 @@
 			// System.out.println("NbOccs "+(size));
 			int[] positions = new int[size];
 			int noOcc = 0;
-			
+
 			// System.out.println("positions");
 			// System.out.println("start: "+(start)+" end:"+n.getEnd());
 			for (int position = start; position <= n.getEnd(); position++) {
-				
+
 				if (o.getStart() <= position && position <= o.getEnd()) {
 					// ignore positions in the anticontext positions
 					continue;
 				}
-				
+
 				int dist;
 				if (position < m.getStart()) {
 					dist = m.getStart() - position - 1;
@@ -1202,17 +1202,17 @@
 					positionsDistances.put(position, dist);
 				}
 			}
-			
+
 			// System.out.println("nb Occ ignored: "+ignore);
 			// System.out.println("nb Occ chevauche: "+chevauche);
 		}
-		
+
 		// store and count distances for each position signature
 		int noOcc = 0;
 		for (int position : positionsDistances.keySet()) { // cooccurrent words positions
 			// String signature = allsignatures.get(position);
 			String signaturestr = allsignaturesstr.get(position);
-			
+
 			int dist = positionsDistances.get(position);
 			if (distances.containsKey(signaturestr)) {
 				distances.put(signaturestr, (distances.get(signaturestr)) + dist);
@@ -1220,28 +1220,28 @@
 			else {
 				distances.put(signaturestr, 0.0);
 			}
-			
+
 			if (counts.containsKey(signaturestr)) {
 				counts.put(signaturestr, (counts.get(signaturestr)) + 1);
 			}
 			else {
 				counts.put(signaturestr, 1);
 			}
-			
+
 			// if ("[1599]".equals(signaturestr)) {
 			// System.out.println("p=" + position + " d=" + dist + " total(d)=" + distances.get(signaturestr) + " c=" + counts.get(signaturestr));
 			// }
 			// }
-			
+
 			noOcc++;
 		}
 		// System.out.println("T counts : "+(System.currentTimeMillis()- time)); //$NON-NLS-1$
-		
+
 		allsignaturesstr = null; // no more need
 		// counted = null;
 		return true;
 	}
-	
+
 	/**
 	 * Step get matches.
 	 *
@@ -1268,22 +1268,22 @@
 		else {
 			r3 = corpus.query(anticontextquery, "CoocAntiContextFocusQuery", false); // no context //$NON-NLS-1$
 		}
-		
-		
+
+
 		m1 = r1.getMatches();
 		numberOfKeyword = m1.size();
 		m2 = r2.getMatches();
 		m3 = r3.getMatches();
-		
+
 		Log.finest("R1 size=" + m1.size());
 		Log.finest("R2 size=" + m2.size());
 		Log.finest("R3 size=" + m3.size());
-		
+
 		// System.out.println(query+" M1 size: "+m1.size());
 		// System.out.println(contextquery+" M2 size: "+m2.size());
 		// System.out.println(anticontextquery+" M3 size: "+m3.size());
 		r1.drop();
-		
+
 		if (r2 != r1) {
 			r2.drop();
 		}
@@ -1292,7 +1292,7 @@
 		}
 		return true;
 	}
-	
+
 	/**
 	 * Step get scores.
 	 *
@@ -1301,7 +1301,7 @@
 	 * @throws StatException the stat exception
 	 */
 	public boolean stepGetScores() throws CqiClientException, StatException {
-		
+
 		SpecificitiesR specif = new SpecificitiesR(lt);
 		// System.out.println("Specif N part: "+specif.getNbrPart()); //$NON-NLS-1$
 		// System.out.println("Specif N lines number: "+specif.getSpecificitesIndex().length); //$NON-NLS-1$
@@ -1310,15 +1310,15 @@
 		String[] specifrownames = specif.getRowNames().asStringsArray();
 		double[][] scores = specif.getScores();
 		// System.out.println("Nb specif result: "+specif.getSpecificitesIndex().length);
-		
+
 		int iimax = Math.min(specifrownames.length, scores.length);
 		for (int ii = 0; ii < iimax; ii++) { // counts.keySet())
 			String signaturestr = keysToString.get(specifrownames[ii]);
-			
+
 			ArrayList<String> props = new ArrayList<>();
 			if (pProperties.size() > 1) {
 				String[] splited = specifrownames[ii].split("_", pProperties.size()); //$NON-NLS-1$
-				
+
 				for (int p = 0; p < pProperties.size(); p++) {
 					props.add(splited[p]);
 				}
@@ -1342,7 +1342,7 @@
 						indexfreqs.get(specifrownames[ii]), scores[ii][1], // freq
 						((float) (distances.get(signaturestr) / counts.get(signaturestr))), // mean distance
 						-1);
-				
+
 				// select the line
 				if (cline.freq >= this.pFminFilter && cline.nbocc >= this.pFCoocFilter && cline.score >= 0 && cline.score >= this.pScoreMinFilter) {
 					if (cline.score >= Integer.MAX_VALUE - 5) {
@@ -1356,7 +1356,7 @@
 		}
 		return true;
 	}
-	
+
 	/**
 	 * Step query limits build the context, anticontext and keyword queries using the context size and xincludepivot and structuralLimit parameters
 	 *
@@ -1364,26 +1364,26 @@
 	 */
 	public boolean stepQueryLimits() {
 		// structural context
-		
+
 		String fixedQuery = CQLQuery.fixQuery(pQuery.getQueryString());
-		
+
 		if (pStructuralUnitLimit != null) {
 			String tempquery = ""; //$NON-NLS-1$
 			String lname = pStructuralUnitLimit.getName();
-			
+
 			// test if there is a left context
 			if (pMinLeftContextSize > 0) {
 				tempquery += "(<" + lname + ">[]* </" + lname + ">){" + (pMaxLeftContextSize) + "," + (pMaxLeftContextSize) + "}"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
 			}
 			// (<p>[]*</p>){0, 50} "je" (<p>[]*</p>){0, 50}
 			tempquery += " <" + lname + ">[]* " + fixedQuery + " []* </" + lname + "> "; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
-			
+
 			// test if there is a right context
 			if (pMinRightContextSize > 0) {
 				tempquery += "(<" + lname + ">[]* </" + lname + ">){" + (pMaxRightContextSize) + "," + (pMaxRightContextSize) + "}";  //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
 			}
 			this.contextQuery = new CQLQuery(tempquery);
-			
+
 			if (pIncludeXpivot) {
 				String anticontextquerystring = ""; //$NON-NLS-1$
 				// minleft = 2..N
@@ -1412,13 +1412,13 @@
 			}
 		}
 		else { // word context
-			
+
 			String tempquery = ""; //$NON-NLS-1$
 			if (pMinLeftContextSize > 0) { // test if there is a left context
 				tempquery += "[]{" + pMaxLeftContextSize + "," + pMaxLeftContextSize + "} "; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 			}
 			tempquery += fixedQuery;
-			
+
 			if (pMinRightContextSize > 0) { // test if there is a right context
 				tempquery += " []{" + pMaxRightContextSize + "," + pMaxRightContextSize + "} "; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 			}
@@ -1435,7 +1435,7 @@
 		}
 		return true;
 	}
-	
+
 	/**
 	 * To txt.
 	 *
@@ -1447,7 +1447,7 @@
 	public boolean toTxt(File outfile, String encoding) throws Exception {
 		return toTxt(outfile, encoding, "\t", ""); //$NON-NLS-1$ //$NON-NLS-2$
 	}
-	
+
 	/**
 	 * To txt.
 	 *
@@ -1472,7 +1472,7 @@
 		}
 		return true;
 	}
-	
+
 	/**
 	 * To txt.
 	 *
@@ -1497,11 +1497,11 @@
 			Log.severe(TXMCoreMessages.bind(TXMCoreMessages.error_error, e));
 			return false;
 		}
-		
+
 		return true;
 	}
-	
-	
+
+
 	/**
 	 * Sets the query.
 	 * 
@@ -1510,7 +1510,7 @@
 	public void setQuery(CQLQuery query) {
 		this.pQuery = query;
 	}
-	
+
 	/**
 	 * Creates a CQL query string from the specified lines.
 	 *
@@ -1518,37 +1518,43 @@
 	 * @return the query
 	 */
 	public String createQuery(List<CLine> lines) {
-		
+
 		if (this.getQuery().isEmpty()) {
 			return ""; //$NON-NLS-1$
 		}
-		
-		
+
+
 		int nbProps = this.getProperties().size();
 		List<WordProperty> props = this.getProperties();
-		
-		String query = "["; //$NON-NLS-1$
+
+		String query = "@["; //$NON-NLS-1$
 		for (int p = 0; p < nbProps; p++) {
-			query += props.get(p) + "=\""; //$NON-NLS-1$
-			for (int l = 0; l < lines.size(); l++) {
-				CLine line = lines.get(l);
-				String s = line.props.get(p);
-				s = CQLQuery.addBackSlash(s);
-				query += s + "|"; //$NON-NLS-1$
+
+			if (props.get(p) instanceof WordProperty) {
+				ArrayList<String> values = new ArrayList<String>();
+				for (int l = 0; l < lines.size(); l++) {
+					CLine line = lines.get(l);
+					String s = line.props.get(p);
+					values.add(s);
+				}
+				String test = ((WordProperty)props.get(p)).getCQLTest(values);
+				if (test != null) {
+					query += test;
+				}
 			}
-			query = query.substring(0, query.length() - 1);
-			query += "\" & "; //$NON-NLS-1$
+			if (p < nbProps-1) {
+				query += " & "; //$NON-NLS-1$
+			}
 		}
-		query = query.substring(0, query.length() - 3);
 		query += "] "; //$NON-NLS-1$
-		
+
 		int maxempan = Math.max(this.getMaxLeft(), this.getMaxRight());
 		if (this.getIncludeXPivot() && maxempan == 0) maxempan = 1;
-		
+
 		String maxempanstr = "within " + maxempan + " "; //$NON-NLS-1$ //$NON-NLS-2$
 		if (this.getStructuralUnitLimit() != null) maxempanstr += this.getStructuralUnitLimit().getName();
-		
-		
+
+
 		String pquery = CQLQuery.fixQuery(this.getQuery().getQueryString());
 		if (this.getMaxLeft() == 0) {
 			query = "" + pquery + " []* " + query + " " + maxempanstr; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
@@ -1559,43 +1565,43 @@
 		else {
 			query = "(" + pquery + " []* " + query + ") | (" + query + " []* " + pquery + ") " + maxempanstr; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
 		}
-		
+
 		return query;
 	}
-	
-	
+
+
 	/**
 	 * The Class CLine.
 	 */
 	public class CLine {
-		
+
 		/** The cooc. */
 		Cooccurrence cooc;
-		
+
 		/** The distmoyenne. */
 		public float distmoyenne;
-		
+
 		/** The freq. */
 		public int freq;
-		
+
 		/** The id. */
 		public int id;
-		
+
 		/** The mode. */
 		public long mode;
-		
+
 		/** The nbocc. */
 		public int nbocc;
-		
+
 		/** The occ. */
 		public String occ;
-		
+
 		/** The props. */
 		public List<String> props;
-		
+
 		/** The score. */
 		public double score;
-		
+
 		/**
 		 * Instantiates a new c line.
 		 *
@@ -1619,7 +1625,7 @@
 			this.mode = mode;
 			this.cooc = cooc;
 		}
-		
+
 		/**
 		 * Adds the txt sep.
 		 *
@@ -1630,7 +1636,7 @@
 		private String addTxtSep(String str, String sep) {
 			return sep + str.replace(sep, sep + sep) + sep;
 		}
-		
+
 		/**
 		 * Gets the cooc.
 		 *
@@ -1639,7 +1645,7 @@
 		public Cooccurrence getCooc() {
 			return cooc;
 		}
-		
+
 		/**
 		 * Resume.
 		 *
@@ -1651,7 +1657,7 @@
 			return addTxtSep("" + occ, txtseparator) //$NON-NLS-1$
 					+ colseparator + freq + colseparator + nbocc + colseparator + score + colseparator + distmoyenne;
 		}
-		
+
 		/**
 		 * Sets the count and dist.
 		 *
@@ -1662,7 +1668,7 @@
 			this.nbocc = count;
 			this.distmoyenne = dist;
 		}
-		
+
 		/**
 		 * Sets the freq.
 		 *
@@ -1671,26 +1677,26 @@
 		public void setFreq(int freq) {
 			this.freq = freq;
 		}
-		
+
 		/**
 		 * Sets the score.
 		 */
 		public void setScore() {// FB == freq, R = nbocc
 			this.score = (this.nbocc + this.freq + this.distmoyenne);
 		}
-		
+
 		@Override
 		public String toString() {
 			return occ + CooccurrenceCoreMessages.fColon + freq + CooccurrenceCoreMessages.occColon + nbocc + CooccurrenceCoreMessages.scoreColon + score + CooccurrenceCoreMessages.meanDistColon
 					+ distmoyenne + CooccurrenceCoreMessages.propertiesColon + props;
 		}
 	}
-	
-	
+
+
 	@Override
 	public String getResultType() {
 		return CooccurrenceCoreMessages.RESULT_TYPE;
 	}
-	
-	
+
+
 }
Index: tmp/org.txm.index.rcp/src/org/txm/index/rcp/editors/PartitionIndexEditor.java
===================================================================
--- tmp/org.txm.index.rcp/src/org/txm/index/rcp/editors/PartitionIndexEditor.java	(revision 2947)
+++ tmp/org.txm.index.rcp/src/org/txm/index/rcp/editors/PartitionIndexEditor.java	(revision 2948)
@@ -220,7 +220,8 @@
 		propertiesSelector.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
 		propertiesSelector.setLayout(new GridLayout(3, false));
 		try {
-			List<WordProperty> props = index.getCorpus().getOrderedProperties();
+			ArrayList<WordProperty> props = new ArrayList<>(index.getCorpus().getOrderedProperties());
+			props.addAll(index.getCorpus().getVirtualProperties());
 			propertiesSelector.setProperties(props);
 		}
 		catch (CqiClientException e) {
Index: tmp/org.txm.index.rcp/src/org/txm/index/rcp/editors/IndexEditor.java
===================================================================
--- tmp/org.txm.index.rcp/src/org/txm/index/rcp/editors/IndexEditor.java	(revision 2947)
+++ tmp/org.txm.index.rcp/src/org/txm/index/rcp/editors/IndexEditor.java	(revision 2948)
@@ -219,7 +219,8 @@
 		propertiesSelector.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
 		propertiesSelector.setLayout(new GridLayout(3, false));
 		try {
-			List<WordProperty> props = index.getCorpus().getOrderedProperties();
+			ArrayList<WordProperty> props = new ArrayList<>(index.getCorpus().getOrderedProperties());
+			props.addAll(index.getCorpus().getVirtualProperties());
 			propertiesSelector.setProperties(props);
 		}
 		catch (CqiClientException e) {
Index: tmp/org.txm.cooccurrence.rcp/src/org/txm/cooccurrence/rcp/editors/CooccurrencesEditor.java
===================================================================
--- tmp/org.txm.cooccurrence.rcp/src/org/txm/cooccurrence/rcp/editors/CooccurrencesEditor.java	(revision 2947)
+++ tmp/org.txm.cooccurrence.rcp/src/org/txm/cooccurrence/rcp/editors/CooccurrencesEditor.java	(revision 2948)
@@ -612,6 +612,7 @@
 			List<WordProperty> available;
 			try {
 				available = new ArrayList<>(this.cooc.getCorpus().getProperties());
+				available.addAll(this.cooc.getCorpus().getVirtualProperties());
 				available.removeAll(cooc.getProperties());
 				this.propertiesSelector.setProperties(available, cooc.getProperties());
 			}
Index: tmp/org.txm.referencer.core/src/org/txm/referencer/core/functions/Referencer.java
===================================================================
--- tmp/org.txm.referencer.core/src/org/txm/referencer/core/functions/Referencer.java	(revision 2947)
+++ tmp/org.txm.referencer.core/src/org/txm/referencer/core/functions/Referencer.java	(revision 2948)
@@ -86,63 +86,60 @@
  * @author sjacquot
  */
 public class Referencer extends TXMResult {
-	
+
 	/** The noref. */
 	protected static int noref = 1;
-	
+
 	/** The prefix r. */
 	protected static String prefixR = "Referencer"; //$NON-NLS-1$
-	
+
 	/** The indexes. */
 	int[] indexes;
-	
+
 	/** The lines. */
 	List<Line> lines;
-	
+
 	/** The matches. */
 	List<Match> matches;
-	
+
 	/** The positions. */
 	int[] positions;
-	
+
 	/** The nlines. */
 	int nlines;
-	
+
 	/** The processed idx. */
 	HashMap<Integer, Line> processedIdx;
-	
+
 	/** The result. */
 	QueryResult result;
-	
+
 	/** The symbol. */
 	private String symbol;
-	
+
 	/** The writer. */
 	private BufferedWriter writer;
-	
-	
-	
-	
-	
+
+
+
+
+
 	/** The hierarchic sort. */
 	@Parameter(key = ReferencerPreferences.SORT_BY_FREQUENCIES)
 	protected boolean pHierarchicSort;
-	
+
 	@Parameter(key = ReferencerPreferences.PATTERN)
 	protected List<StructuralUnitProperty> pPattern;
-	
+
 	/** The prop. */
 	@Parameter(key = ReferencerPreferences.UNIT_PROPERTY)
-	protected Property pProperty;
-	
+	protected WordProperty pProperty;
+
 	/** The query. */
 	@Parameter(key = ReferencerPreferences.QUERY)
 	protected CQLQuery pQuery;
-	
-	
-	
-	
-	
+
+
 	/**
 	 * Creates a not computed referencer.
 	 *
@@ -151,8 +148,8 @@
 	public Referencer(CQPCorpus parent) {
 		super(parent);
 	}
-	
-	
+
+
 	/**
 	 * Creates a not computed referencer.
 	 * 
@@ -161,8 +158,8 @@
 	public Referencer(String parametersNodePath) {
 		super(parametersNodePath);
 	}
-	
-	
+
+
 	/**
 	 * As r matrix.
 	 *
@@ -170,14 +167,14 @@
 	 * @throws RWorkspaceException the r workspace exception
 	 */
 	public String asRMatrix() throws RWorkspaceException {
-		
+
 		String keywords[] = new String[lines.size()];
 		for (int i = 0; i < lines.size(); i++)
 			keywords[i] = lines.get(i).getPropValue();
 		// System.out.println(Arrays.toString(keywords));
-		
+
 		String symbol = prefixR + noref;
-		
+
 		RWorkspace rw = RWorkspace.getRWorkspaceInstance();
 		rw.eval(symbol + " <- list()"); //$NON-NLS-1$
 		rw.addVectorToWorkspace("refkeywords", keywords); //$NON-NLS-1$
@@ -192,12 +189,12 @@
 			rw.eval(symbol + "$refs[[" + i + "]] <- reflinerefs"); //$NON-NLS-1$ //$NON-NLS-2$
 			i++;
 		}
-		
+
 		noref++;
 		this.symbol = symbol;
 		return symbol;
 	}
-	
+
 	@Override
 	public void clean() {
 		try {
@@ -211,7 +208,7 @@
 			org.txm.utils.logger.Log.printStackTrace(e);
 		}
 	}
-	
+
 	/**
 	 * Clears all lines.
 	 */
@@ -220,7 +217,7 @@
 			line.clear();
 		}
 	}
-	
+
 	/**
 	 * Calls in order all stages to compute the referencer.
 	 *
@@ -232,11 +229,11 @@
 			if (!getQueryMatches()) {
 				return false;
 			}
-			
+
 			if (!getQueryindexes()) {
 				return false;
 			}
-			
+
 			if (!groupPositionsbyId()) {
 				return false;
 			}
@@ -245,10 +242,10 @@
 			e.printStackTrace();
 			return false;
 		}
-		
+
 		return true;
 	}
-	
+
 	/**
 	 * Gets the parent corpus.
 	 *
@@ -257,12 +254,12 @@
 	public CQPCorpus getCorpus() {
 		return (CQPCorpus) this.parent;
 	}
-	
+
 	@Override
 	public String getDetails() {
 		return getCorpus().getName();
 	}
-	
+
 	/**
 	 * Gets the lines.
 	 *
@@ -274,7 +271,7 @@
 	public List<Line> getLines() throws CqiClientException, IOException, CqiServerError {
 		return getLines(0, lines.size());
 	}
-	
+
 	/**
 	 * Gets the lines.
 	 *
@@ -292,16 +289,16 @@
 		if (to > lines.size()) {
 			to = lines.size();
 		}
-		
+
 		HashMap<Integer, Line> lineswithoutpropvalue = new HashMap<>();
-		
+
 		AbstractCqiClient cqiClient = CorpusManager.getCorpusManager().getCqiClient();
 		// build Missing lines
 		for (int i = from; i < to; i++) { // for each position group
 			Line l = lines.get(i);
 			if (l.notcomputed) {
 				lineswithoutpropvalue.put(l.id, l);
-				
+
 				// get all reference values of all position of the line
 				Map<Property, List<List<String>>> refValues = new HashMap<>();
 				for (Property property : pPattern) {
@@ -314,7 +311,7 @@
 					for (Property property : pPattern) {
 						propvalue += refValues.get(property).get(j).get(0) + ", "; //$NON-NLS-1$
 					}
-					
+
 					l.addReference(propvalue.substring(0, propvalue.length() - 2));
 				}
 				if (pHierarchicSort) {
@@ -326,22 +323,22 @@
 				l.notcomputed = false;
 			}
 		}
-		
+
 		// get idx String value
 		int[] idxwithoutvalues = new int[lineswithoutpropvalue.keySet().size()];
 		int count = 0;
 		for (int i : lineswithoutpropvalue.keySet()) {
 			idxwithoutvalues[count++] = i;
 		}
-		
-		String[] values = CorpusManager.getCorpusManager().getCqiClient().id2Str(pProperty.getQualifiedName(), idxwithoutvalues);
+
+		String[] values = pProperty.id2Str(idxwithoutvalues);
 		for (int i = 0; i < values.length; i++) {
 			int id = idxwithoutvalues[i];
 			lineswithoutpropvalue.get(id).linepropvalue = values[i];
 		}
 		return lines.subList(from, to);
 	}
-	
+
 	/**
 	 * Gets the name.
 	 *
@@ -356,8 +353,8 @@
 			return this.getEmptyName();
 		}
 	}
-	
-	
+
+
 	@Override
 	public String getSimpleName() {
 		if (this.pQuery != null && !this.pQuery.isEmpty()) {
@@ -367,14 +364,14 @@
 			return this.getEmptyName();
 		}
 	}
-	
-	
+
+
 	@Override
 	public String getComputingStartMessage() {
 		return TXMCoreMessages.bind(ReferencerCoreMessages.referencesOfP0InTheP1Corpus, this.pQuery.asString(), this.getCorpus().getName());
 	}
-	
-	
+
+
 	@Override
 	public String getComputingDoneMessage() {
 		if (this.lines == null || this.lines.isEmpty()) {
@@ -384,8 +381,8 @@
 			return TXMCoreMessages.bind(TXMCoreMessages.common_P0ItemsForP1Occurrences, TXMCoreMessages.formatNumber(this.getNLines()), TXMCoreMessages.formatNumber(this.getV()));
 		}
 	}
-	
-	
+
+
 	/**
 	 * Gets the n lines.
 	 *
@@ -394,7 +391,7 @@
 	public int getNLines() {
 		return nlines;
 	}
-	
+
 	/**
 	 * Gets the pattern.
 	 *
@@ -403,7 +400,7 @@
 	public List<StructuralUnitProperty> getPattern() {
 		return pPattern;
 	}
-	
+
 	/**
 	 * Gets the property.
 	 *
@@ -412,7 +409,7 @@
 	public Property getProperty() {
 		return pProperty;
 	}
-	
+
 	/**
 	 * Gets the query.
 	 *
@@ -421,7 +418,7 @@
 	public CQLQuery getQuery() {
 		return pQuery;
 	}
-	
+
 	/**
 	 * 2nd step.
 	 *
@@ -434,8 +431,8 @@
 			for (Match m : matches) {
 				positions[i++] = m.getStart();
 			}
-			
-			indexes = CorpusManager.getCorpusManager().getCqiClient().cpos2Id(pProperty.getQualifiedName(), positions);
+
+			indexes = pProperty.cpos2Id(positions);
 		}
 		catch (Exception e) {
 			// TODO Auto-generated catch block
@@ -444,7 +441,7 @@
 		}
 		return true;
 	}
-	
+
 	/**
 	 * 1st step.
 	 *
@@ -460,7 +457,7 @@
 		result.drop();
 		return true;
 	}
-	
+
 	/**
 	 * Gets the symbol.
 	 *
@@ -469,14 +466,14 @@
 	public String getSymbol() {
 		return symbol;
 	}
-	
+
 	public int getV() {
 		if (matches == null) {
 			return 0;
 		}
 		return matches.size();
 	}
-	
+
 	/**
 	 * 3rd stage.
 	 *
@@ -484,7 +481,7 @@
 	 */
 	public boolean groupPositionsbyId() {
 		processedIdx = new HashMap<>();
-		
+
 		lines = new ArrayList<>();
 		// System.out.println("indexes ");
 		for (int i = 0; i < indexes.length; i++) {
@@ -494,34 +491,34 @@
 				// System.out.println("add idx "+id);
 				Line l = new Line(id);
 				processedIdx.put(id, l);
-				
+
 				lines.add(l);
 			}
 			processedIdx.get(id).addPosition(positions[i]);
 		}
-		
+
 		nlines = processedIdx.keySet().size();
 		return true;
 	}
-	
-	public void setParameters(CQLQuery query, Property prop, List<StructuralUnitProperty> pattern, Boolean hierarchicSort) {
+
+	public void setParameters(CQLQuery query, WordProperty prop, List<StructuralUnitProperty> pattern, Boolean hierarchicSort) {
 		if (query != null) this.pQuery = query;
 		if (pattern != null) this.pPattern = pattern;
 		if (prop != null) this.pProperty = prop;
 		if (hierarchicSort != null) this.pHierarchicSort = hierarchicSort;
 		this.setDirty();
 	}
-	
+
 	@Override
 	public boolean setParameters(TXMParameters parameters) {
 		return false;
 	}
-	
+
 	@Deprecated
 	public boolean toTxt(File outfile, String encoding) throws Exception {
 		return toTxt(outfile, encoding, "\t", ""); //$NON-NLS-1$ //$NON-NLS-2$
 	}
-	
+
 	@Override
 	@Deprecated
 	public boolean _toTxt(File outfile, String encoding, String colseparator, String txtseparator) {
@@ -537,7 +534,7 @@
 		}
 		return true;
 	}
-	
+
 	@Deprecated
 	public void toTxt(Writer writer, int from, int to, String colseparator, String txtseparator)
 			throws CqiClientException, IOException {
@@ -549,7 +546,7 @@
 						.replace(txtseparator, txtseparator + txtseparator) + txtseparator + "\n"); //$NON-NLS-1$
 				writer.flush();
 			}
-			
+
 			writer.close();
 		}
 		catch (CqiServerError e) {
@@ -557,10 +554,10 @@
 			org.txm.utils.logger.Log.printStackTrace(e);
 		}
 	}
-	
+
 	@Override
 	public boolean canCompute() {
-		
+
 		if (pQuery == null || pQuery.isEmpty()) {
 			Log.fine("No query set.");
 			return false;
@@ -573,10 +570,10 @@
 			Log.fine("No property set.");
 			return false;
 		}
-		
+
 		return true;
 	}
-	
+
 	@Override
 	public boolean loadParameters() throws CqiClientException {
 		this.pQuery = new CQLQuery(this.getStringParameterValue(ReferencerPreferences.QUERY));
@@ -584,49 +581,49 @@
 		this.pProperty = this.getCorpus().getProperty(this.getStringParameterValue(ReferencerPreferences.UNIT_PROPERTY));
 		return true;
 	}
-	
+
 	@Override
 	public boolean saveParameters() {
 		if (this.pQuery != null) {
 			this.saveParameter(ReferencerPreferences.QUERY, this.pQuery.getQueryString());
 		}
-		
+
 		if (this.pPattern != null) {
 			this.saveParameter(ReferencerPreferences.PATTERN, StructuralUnitProperty.propertiesToString(this.pPattern));
 		}
-		
+
 		if (this.pProperty != null) {
 			this.saveParameter(ReferencerPreferences.UNIT_PROPERTY, this.pProperty.getName());
 		}
 		return true;
 	}
-	
-	
-	
-	
+
+
+
+
 	/**
 	 * The Class Line.
 	 */
 	public class Line {
-		
+
 		/** The id. */
 		int id;
-		
+
 		/** The propvalue. */
 		String linepropvalue;
-		
+
 		/** The notcomputed. */
 		boolean notcomputed = true;
-		
+
 		/** The positions. */
 		ArrayList<Integer> positions;
-		
+
 		/** The references. */
 		ArrayList<String> references;
-		
+
 		/** The references counts. */
 		HashMap<String, Integer> referencesCounts = new HashMap<>();
-		
+
 		/**
 		 * Instantiates a new line.
 		 *
@@ -637,7 +634,7 @@
 			positions = new ArrayList<>();
 			references = new ArrayList<>();
 		}
-		
+
 		/**
 		 * Adds the position.
 		 *
@@ -646,7 +643,7 @@
 		public void addPosition(int i) {
 			positions.add(i);
 		}
-		
+
 		/**
 		 * Adds the reference.
 		 *
@@ -661,7 +658,7 @@
 				referencesCounts.put(string, referencesCounts.get(string) + 1);
 			}
 		}
-		
+
 		/**
 		 * Clear.
 		 */
@@ -669,7 +666,7 @@
 			notcomputed = false;
 			references = new ArrayList<>();
 		}
-		
+
 		/**
 		 * Gets the count.
 		 *
@@ -679,11 +676,11 @@
 		public int getCount(String ref) {
 			return referencesCounts.get(ref);
 		}
-		
+
 		public HashMap<String, Integer> getCounts() {
 			return referencesCounts;
 		}
-		
+
 		/**
 		 * Gets the prop value.
 		 *
@@ -692,7 +689,7 @@
 		public String getPropValue() {
 			return linepropvalue;
 		}
-		
+
 		/**
 		 * Gets the references.
 		 *
@@ -701,14 +698,14 @@
 		public List<String> getReferences() {
 			return references;
 		}
-		
+
 		/**
 		 * Sort alpha.
 		 */
 		public void sortAlpha() {
 			Collections.sort(references);
 		}
-		
+
 		/**
 		 * Sort ref.
 		 *
@@ -716,7 +713,7 @@
 		 */
 		public void sortRef(final boolean reverse) {
 			Collections.sort(references, new Comparator<String>() {
-				
+
 				@Override
 				public int compare(String arg0, String arg1) {
 					if (reverse)
@@ -726,7 +723,7 @@
 				}
 			});
 		}
-		
+
 		/*
 		 * (non-Javadoc)
 		 * @see java.lang.Object#toString()
@@ -736,20 +733,20 @@
 			return linepropvalue + " : <" + id + "," + pProperty + "> : " + references.toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 		}
 	}
-	
+
 	public void setQuery(CQLQuery query) {
 		this.pQuery = query;
 	}
-	
-	public void setProperty(Property property) {
+
+	public void setProperty(WordProperty property) {
 		this.pProperty = property;
 	}
-	
+
 	public void setPattern(List<StructuralUnitProperty> properties) {
 		this.pPattern = properties;
 	}
-	
-	
+
+
 	/**
 	 * Creates a CQL query string from the specified Referencer lines.
 	 *
@@ -757,32 +754,30 @@
 	 * @return the query
 	 */
 	public String createQuery(List<Line> lines) {
-		String query = ""; //$NON-NLS-1$
-		
-		int nbToken = 1;
-		
-		
+
 		Property prop = this.getProperty();
-		for (int t = 0; t < nbToken; t++) {
-			query += "[" + prop + "=\""; //$NON-NLS-1$ //$NON-NLS-2$
-			
-			for (Line line : lines) {
-				String s = line.getPropValue();
-				s = CQLQuery.addBackSlash(s);
-				query += s + "|"; //$NON-NLS-1$
-			}
-			query = query.substring(0, query.length() - 1);
-			query += "\"] "; //$NON-NLS-1$
+		String query = "["; //$NON-NLS-1$
+
+		ArrayList<String> values = new ArrayList<>();
+		for (Line line : lines) {
+			String s = line.getPropValue();
+			values.add(s);
 		}
-		query = query.substring(0, query.length() - 1);
-		return query;
+		String test = ((WordProperty) prop).getCQLTest(values);
+		if (test != null) {
+			query += test;
+		}
 		
+		query += "]"; //$NON-NLS-1$
+				
+		return query;
+
 	}
-	
+
 	@Override
 	public String getResultType() {
 		return ReferencerCoreMessages.RESULT_TYPE;
 	}
-	
-	
+
+
 }
Index: tmp/org.txm.concordance.rcp/src/org/txm/concordance/rcp/editors/ConcordanceEditor.java
===================================================================
--- tmp/org.txm.concordance.rcp/src/org/txm/concordance/rcp/editors/ConcordanceEditor.java	(revision 2947)
+++ tmp/org.txm.concordance.rcp/src/org/txm/concordance/rcp/editors/ConcordanceEditor.java	(revision 2948)
@@ -1072,6 +1072,8 @@
 		propertiesPanel.getLayout().numColumns = 5;
 		propertiesPanel.getLayout().makeColumnsEqualWidth = false;
 		
+		ArrayList<WordProperty> tmp; // tmp to store properties
+		
 		try {
 			Label l = new Label(propertiesPanel, SWT.NONE);
 			l.setText(ConcordanceUIMessages.editor_21);
@@ -1109,7 +1111,9 @@
 			leftViewProperties = new PropertiesSelector<>(propertiesPanel, SWT.NONE);
 			leftViewProperties.setLayoutData(new GridData(GridData.CENTER, GridData.CENTER, false, false));
 			leftViewProperties.setTitle(ConcordanceUIMessages.editor_21);
-			leftViewProperties.setProperties(getCorpus().getOrderedProperties());
+			tmp = new ArrayList<>(getCorpus().getOrderedProperties());
+			tmp.addAll(getCorpus().getVirtualProperties());
+			leftViewProperties.setProperties(tmp);
 			leftViewProperties.setButtonText(ConcordanceUIMessages.editor_19);
 			leftViewProperties.addSelectionListener(new ComputeSelectionListener(this) {
 				
@@ -1123,7 +1127,9 @@
 			keywordViewProperties = new PropertiesSelector<>(propertiesPanel, SWT.NONE);
 			keywordViewProperties.setLayoutData(new GridData(GridData.CENTER, GridData.CENTER, false, false));
 			keywordViewProperties.setTitle(ConcordanceUIMessages.editor_21);
-			keywordViewProperties.setProperties(getCorpus().getOrderedProperties());
+			tmp = new ArrayList<>(getCorpus().getOrderedProperties());
+			tmp.addAll(getCorpus().getVirtualProperties());
+			keywordViewProperties.setProperties(tmp);
 			keywordViewProperties.setButtonText(ConcordanceUIMessages.editor_19);
 			keywordViewProperties.addSelectionListener(new ComputeSelectionListener(this) {
 				
@@ -1137,7 +1143,9 @@
 			rightViewProperties = new PropertiesSelector<>(propertiesPanel, SWT.NONE);
 			rightViewProperties.setLayoutData(new GridData(GridData.CENTER, GridData.CENTER, false, false));
 			rightViewProperties.setTitle(ConcordanceUIMessages.editor_21);
-			rightViewProperties.setProperties(getCorpus().getOrderedProperties());
+			tmp = new ArrayList<>(getCorpus().getOrderedProperties());
+			tmp.addAll(getCorpus().getVirtualProperties());
+			rightViewProperties.setProperties(tmp);
 			rightViewProperties.setButtonText(ConcordanceUIMessages.editor_19);
 			rightViewProperties.addSelectionListener(new ComputeSelectionListener(this) {
 				
@@ -1170,7 +1178,9 @@
 			leftSortProperties.setLayoutData(new GridData(GridData.CENTER, GridData.CENTER, false, false));
 			leftSortProperties.setTitle(ConcordanceUIMessages.editor_21);
 			leftSortProperties.setButtonText(ConcordanceUIMessages.editor_19);
-			leftSortProperties.setProperties(getCorpus().getOrderedProperties());
+			tmp = new ArrayList<>(getCorpus().getOrderedProperties());
+			tmp.addAll(getCorpus().getVirtualProperties());
+			leftSortProperties.setProperties(tmp);
 			leftSortProperties.addSelectionListener(new ComputeSelectionListener(this) {
 				
 				@Override
@@ -1184,7 +1194,9 @@
 			keywordSortProperties.setLayoutData(new GridData(GridData.CENTER, GridData.CENTER, false, false));
 			keywordSortProperties.setTitle(ConcordanceUIMessages.editor_21);
 			keywordSortProperties.setButtonText(ConcordanceUIMessages.editor_19);
-			keywordSortProperties.setProperties(getCorpus().getOrderedProperties());
+			tmp = new ArrayList<>(getCorpus().getOrderedProperties());
+			tmp.addAll(getCorpus().getVirtualProperties());
+			keywordSortProperties.setProperties(tmp);
 			keywordSortProperties.addSelectionListener(new ComputeSelectionListener(this) {
 				
 				@Override
@@ -1198,7 +1210,9 @@
 			rightSortProperties.setLayoutData(new GridData(GridData.CENTER, GridData.CENTER, false, false));
 			rightSortProperties.setTitle(ConcordanceUIMessages.editor_21);
 			rightSortProperties.setButtonText(ConcordanceUIMessages.editor_19);
-			rightSortProperties.setProperties(getCorpus().getOrderedProperties());
+			tmp = new ArrayList<>(getCorpus().getOrderedProperties());
+			tmp.addAll(getCorpus().getVirtualProperties());
+			rightSortProperties.setProperties(tmp);
 			rightSortProperties.addSelectionListener(new ComputeSelectionListener(this) {
 				
 				@Override
Index: tmp/org.txm.lexicaltable.rcp/src/org/txm/lexicaltable/rcp/editors/LexicalTableEditor.java
===================================================================
--- tmp/org.txm.lexicaltable.rcp/src/org/txm/lexicaltable/rcp/editors/LexicalTableEditor.java	(revision 2947)
+++ tmp/org.txm.lexicaltable.rcp/src/org/txm/lexicaltable/rcp/editors/LexicalTableEditor.java	(revision 2948)
@@ -66,6 +66,7 @@
 import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
 import org.txm.searchengine.cqp.corpus.CQPCorpus;
 import org.txm.searchengine.cqp.corpus.MainCorpus;
+import org.txm.searchengine.cqp.corpus.WordProperty;
 import org.txm.statsengine.core.StatException;
 import org.txm.statsengine.core.data.Vector;
 import org.txm.statsengine.r.rcp.views.RVariablesView;
@@ -177,11 +178,14 @@
 			
 			// unit property
 			new Label(mainParametersArea, SWT.NONE).setText(TXMCoreMessages.common_property);
+			ArrayList<WordProperty> availablesProperties = new ArrayList<>();
+			availablesProperties.addAll(CQPCorpus.getFirstParentCorpus(this.getResult()).getOrderedProperties());
+			availablesProperties.addAll(CQPCorpus.getFirstParentCorpus(this.getResult()).getVirtualProperties());
 			this.unitPropertyComboViewer = new PropertiesComboViewer(
 					mainParametersArea,
 					this,
 					false,
-					CQPCorpus.getFirstParentCorpus(this.getResult()).getOrderedProperties(),
+					availablesProperties,
 					this.getResult().getProperty(),
 					false);
 			
Index: tmp/org.txm.rcp/src/main/java/org/txm/rcp/views/cmdparameters/ParametersView.java
===================================================================
--- tmp/org.txm.rcp/src/main/java/org/txm/rcp/views/cmdparameters/ParametersView.java	(revision 2947)
+++ tmp/org.txm.rcp/src/main/java/org/txm/rcp/views/cmdparameters/ParametersView.java	(revision 2948)
@@ -507,8 +507,11 @@
 		
 		WordProperty value = selected.get(0);
 		CQPCorpus corpus = ((WordProperty) value).getCorpus();
-		List<WordProperty> availables = corpus.getOrderedProperties();
+		
+		ArrayList<WordProperty> availables = new ArrayList<>(corpus.getOrderedProperties());
+		availables.addAll(corpus.getVirtualProperties());
 		availables.remove(value);
+		
 		PropertiesSelector<WordProperty> selector = new PropertiesSelector<WordProperty>(panel, SWT.NONE);
 		selector.setProperties(availables, selected);
 		selector.addSelectionListener(new SelectionListener() {
Index: tmp/org.txm.rcp/src/main/java/org/txm/rcp/swt/dialog/SinglePropertySelectionDialog.java
===================================================================
--- tmp/org.txm.rcp/src/main/java/org/txm/rcp/swt/dialog/SinglePropertySelectionDialog.java	(revision 2947)
+++ tmp/org.txm.rcp/src/main/java/org/txm/rcp/swt/dialog/SinglePropertySelectionDialog.java	(revision 2948)
@@ -197,13 +197,9 @@
 		availablePropertiesView.removeAll();
 		for (Property property : allProperties) {
 			// if (!property.getName().equals("id")) //$NON-NLS-1$
-			if (property instanceof VirtualProperty) {
-				availablePropertiesView.add(((VirtualProperty) property).getFullName());
-			}
-			else if (property instanceof StructuralUnitProperty) {
-				availablePropertiesView.add(((StructuralUnitProperty) property).getFullName());
-			}
-			else {
+			if (property instanceof StructuralUnitProperty || property instanceof VirtualProperty) {
+				availablePropertiesView.add(property.getFullName());
+			} else {
 				availablePropertiesView.add(property.getName());
 			}
 		}
Index: tmp/org.txm.rcp/src/main/java/org/txm/rcp/swt/dialog/MultiplePropertySelectionDialog.java
===================================================================
--- tmp/org.txm.rcp/src/main/java/org/txm/rcp/swt/dialog/MultiplePropertySelectionDialog.java	(revision 2947)
+++ tmp/org.txm.rcp/src/main/java/org/txm/rcp/swt/dialog/MultiplePropertySelectionDialog.java	(revision 2948)
@@ -311,12 +311,9 @@
 		availablePropertiesView.removeAll();
 		for (Property property : availableProperties) {
 			// if (!property.getName().equals("id")) //$NON-NLS-1$
-			if (property instanceof VirtualProperty) {
-				availablePropertiesView.add(((VirtualProperty) property).getFullName());
+			if (property instanceof StructuralUnitProperty || property instanceof VirtualProperty) {
+				availablePropertiesView.add(property.getFullName());
 			}
-			else if (property instanceof StructuralUnitProperty) {
-				availablePropertiesView.add(((StructuralUnitProperty) property).getFullName());
-			}
 			else {
 				availablePropertiesView.add(property.getName());
 			}
@@ -324,8 +321,8 @@
 		selectedPropertiesView.removeAll();
 		for (Property property : selectedProperties) {
 			// if (!property.getName().equals("id")) //$NON-NLS-1$
-			if (property instanceof StructuralUnitProperty) {
-				selectedPropertiesView.add(((StructuralUnitProperty) property).getFullName());
+			if (property instanceof StructuralUnitProperty || property instanceof VirtualProperty) {
+				selectedPropertiesView.add(property.getFullName());
 			}
 			else {
 				selectedPropertiesView.add(property.getName());
Index: tmp/org.txm.rcp/src/main/java/org/txm/rcp/swt/widget/structures/PropertiesComboViewer.java
===================================================================
--- tmp/org.txm.rcp/src/main/java/org/txm/rcp/swt/widget/structures/PropertiesComboViewer.java	(revision 2947)
+++ tmp/org.txm.rcp/src/main/java/org/txm/rcp/swt/widget/structures/PropertiesComboViewer.java	(revision 2948)
@@ -7,13 +7,18 @@
 
 import org.eclipse.jface.viewers.ArrayContentProvider;
 import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
 import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Composite;
 import org.txm.core.results.TXMResult;
 import org.txm.rcp.editors.TXMEditor;
 import org.txm.rcp.editors.listeners.ComputeSelectionListener;
+import org.txm.rcp.swt.provider.SimpleLabelProvider;
 import org.txm.searchengine.cqp.corpus.Property;
+import org.txm.searchengine.cqp.corpus.StructuralUnitProperty;
+import org.txm.searchengine.cqp.corpus.VirtualProperty;
 
 /**
  * Combo viewer for token/word properties of a corpus with only single selection support.
@@ -44,7 +49,7 @@
 		this.addBlankEntry = addBlankEntry;
 		
 		this.setContentProvider(ArrayContentProvider.getInstance());
-
+		
 		this.updateFromList(properties, selectedProperty);
 		
 		// Listener
Index: tmp/org.txm.rcp/src/main/java/org/txm/rcp/swt/widget/PropertiesSelector.java
===================================================================
--- tmp/org.txm.rcp/src/main/java/org/txm/rcp/swt/widget/PropertiesSelector.java	(revision 2947)
+++ tmp/org.txm.rcp/src/main/java/org/txm/rcp/swt/widget/PropertiesSelector.java	(revision 2948)
@@ -49,6 +49,7 @@
 import org.txm.searchengine.cqp.corpus.CQPCorpus;
 import org.txm.searchengine.cqp.corpus.Property;
 import org.txm.searchengine.cqp.corpus.StructuralUnitProperty;
+import org.txm.searchengine.cqp.corpus.VirtualProperty;
 import org.txm.utils.logger.Log;
 
 /**
@@ -167,11 +168,11 @@
 				buffer.append(propSeparator);
 			}
 			
-			if (p instanceof StructuralUnitProperty)
-				buffer.append(((StructuralUnitProperty) p).getFullName());
-			else
+			if (p instanceof StructuralUnitProperty || p instanceof VirtualProperty) {
+				buffer.append(p.getFullName());
+			} else {
 				buffer.append(p.getName());
-			
+			}			
 		}
 		if (buffer.length() > 0) {
 			int l = buffer.length();
@@ -233,6 +234,8 @@
 					i--;
 				}
 			}
+			
+			availableProperties.addAll((Collection<? extends P>) corpus.getVirtualProperties());
 		}
 		catch (CqiClientException e) {
 			Log.severe(NLS.bind(TXMUIMessages.cantLoadPropertiesFromCorpusP0ColonP1, e.getMessage()));
@@ -292,7 +295,7 @@
 	 * 
 	 * @param available a list of properties set to the this.availableProperties list
 	 */
-	public void setProperties(List<P> available) {
+	public final void setProperties(List<P> available) {
 		this.setProperties(available, new ArrayList<P>());
 	}
 	
Index: tmp/org.txm.referencer.rcp/src/org/txm/referencer/rcp/editors/ReferencerEditor.java
===================================================================
--- tmp/org.txm.referencer.rcp/src/org/txm/referencer/rcp/editors/ReferencerEditor.java	(revision 2947)
+++ tmp/org.txm.referencer.rcp/src/org/txm/referencer/rcp/editors/ReferencerEditor.java	(revision 2948)
@@ -159,8 +159,7 @@
 		// [Edit]
 		propertiesSelector = new PropertiesSelector<>(getMainParametersComposite(), SWT.NONE);
 		propertiesSelector.setMaxPropertyNumber(1);
-		propertiesSelector.setLayoutData(new GridData(GridData.FILL, GridData.FILL,
-				false, false));
+		propertiesSelector.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
 		propertiesSelector.setLayout(new GridLayout(3, false));
 		propertiesSelector.addSelectionListener(computeSelectionListener);
 		
@@ -428,6 +427,7 @@
 			ArrayList<Property> selectedProps = new ArrayList<>();
 			ArrayList<Property> availables = new ArrayList<>();
 			availables.addAll(corpus.getOrderedProperties());
+			availables.addAll(corpus.getVirtualProperties());
 			
 			if (referencer.getProperty() != null) {
 				selectedProps.add(referencer.getProperty());
Index: tmp/org.txm.index.core/src/org/txm/index/core/functions/Lexicon.java
===================================================================
--- tmp/org.txm.index.core/src/org/txm/index/core/functions/Lexicon.java	(revision 2947)
+++ tmp/org.txm.index.core/src/org/txm/index/core/functions/Lexicon.java	(revision 2948)
@@ -83,11 +83,11 @@
 			// this.query = new Query("[]"); //$NON-NLS-1$
 			// this.props = new ArrayList<Property>();
 			// this.props.add(property);
-			Property property = this.pProperties.get(0);
+			WordProperty property = this.pProperties.get(0);
 			
 			CQPLexicon lexicon = CQPLexicon.getLexicon(this.getCorpus(), property, monitor.createNewMonitor(20));
-			lexicon.setProperty(property);
-			lexicon._compute();
+			//lexicon.setProperty(property);
+			//lexicon._compute();
 			
 			this.nTotalTokens = lexicon.nbrOfToken();
 			String[] forms = lexicon.getForms();
Index: tmp/org.txm.index.core/src/org/txm/index/core/functions/PartitionIndex.java
===================================================================
--- tmp/org.txm.index.core/src/org/txm/index/core/functions/PartitionIndex.java	(revision 2947)
+++ tmp/org.txm.index.core/src/org/txm/index/core/functions/PartitionIndex.java	(revision 2948)
@@ -39,7 +39,6 @@
 import org.eclipse.osgi.util.NLS;
 import org.rosuda.REngine.REXPMismatchException;
 import org.txm.core.messages.TXMCoreMessages;
-import org.txm.core.preferences.TXMPreferences;
 import org.txm.index.core.functions.LineComparator.SortMode;
 import org.txm.index.core.messages.IndexCoreMessages;
 import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
Index: tmp/org.txm.index.core/src/org/txm/index/core/functions/Index.java
===================================================================
--- tmp/org.txm.index.core/src/org/txm/index/core/functions/Index.java	(revision 2947)
+++ tmp/org.txm.index.core/src/org/txm/index/core/functions/Index.java	(revision 2948)
@@ -251,23 +251,41 @@
 		for (int t = 0; t < nbToken; t++) {
 			query += "["; //$NON-NLS-1$
 			for (int p = 0; p < nbProps; p++) {
+				
 				if (props.get(p) instanceof StructuralUnitProperty) {
 					query += "_." + ((StructuralUnitProperty) props.get(p)).getFullName() + "=\""; //$NON-NLS-1$ //$NON-NLS-2$
+					
+					for (int l = 0; l < nbLines; l++) {
+						line = lines.get(l);
+						List<List<String>> values = line.getUnitsProperties();
+						String s = values.get(p).get(t);
+						s = CQLQuery.addBackSlash(s);
+						query += s + "|"; //$NON-NLS-1$
+					}
+					query = query.substring(0, query.length() - 1);
+					
+					query += "\""; //$NON-NLS-1$
+				
 				}
-				else {
-					query += props.get(p) + "=\""; //$NON-NLS-1$
+				else if (props.get(p) instanceof WordProperty) {
+					ArrayList<String> values = new ArrayList<>();
+					for (int l = 0; l < nbLines; l++) {
+						line = lines.get(l);
+						String s = line.getUnitsProperties().get(p).get(t);
+						values.add(s);
+					}
+					
+					String test = ((WordProperty)props.get(p)).getCQLTest(values);
+					if (test != null) {
+						query += test;
+					}
 				}
-				for (int l = 0; l < nbLines; l++) {
-					line = lines.get(l);
-					List<List<String>> values = line.getUnitsProperties();
-					String s = values.get(p).get(t);
-					s = CQLQuery.addBackSlash(s);
-					query += s + "|"; //$NON-NLS-1$
+				
+				if (p < nbProps-1) {
+					query += " & "; //$NON-NLS-1$
 				}
-				query = query.substring(0, query.length() - 1);
-				query += "\" & "; //$NON-NLS-1$
 			}
-			query = query.substring(0, query.length() - 3);
+			
 			query += "] "; //$NON-NLS-1$
 		}
 		query = query.substring(0, query.length() - 1);
@@ -292,13 +310,20 @@
 			for (int t = 0; t < nbToken; t++) {
 				query += "["; //$NON-NLS-1$
 				for (int p = 0; p < nbProps; p++) {
-					query += props.get(p).getName() + "=\""; //$NON-NLS-1$
-					String s = values.get(p).get(t);
-					s = CQLQuery.addBackSlash(s);
-					query += s;
-					query += "\" & "; //$NON-NLS-1$
+					
+					if (props.get(p) instanceof WordProperty) {
+						String s = line.getUnitsProperties().get(p).get(t);
+						
+						String test = ((WordProperty)props.get(p)).getCQLTest(s);
+						if (test != null) {
+							query += test;
+						}
+					}
+										
+					if (p < nbProps -1) {
+						query += " & "; //$NON-NLS-1$
+					}
 				}
-				query = query.substring(0, query.length() - 3);
 				query += "] "; //$NON-NLS-1$
 			}
 			queries.add(new CQLQuery(query));
@@ -588,8 +613,8 @@
 					if (property instanceof StructuralUnitProperty) {
 						strs = CorpusManager.getCorpusManager().getCqiClient().struc2Str(property.getQualifiedName(), indices);
 					}
-					else {
-						strs = CorpusManager.getCorpusManager().getCqiClient().id2Str(property.getQualifiedName(), indices);
+					else if (property instanceof WordProperty) {
+						strs = ((WordProperty)property).id2Str(indices);
 					}
 				}
 				catch (Exception e) {
@@ -710,7 +735,7 @@
 	
 	@Override
 	public String getComputingStartMessage() {
-		return TXMCoreMessages.bind(IndexCoreMessages.indexOfP0PropertiesP1InTheP2Corpus, this.pQuery.asString(), WordProperty.asString(this.pProperties), this.getCorpus().getName());
+		return TXMCoreMessages.bind(IndexCoreMessages.indexOfP0PropertiesP1InTheP2Corpus, (this.pQuery!=null?this.pQuery.asString():"<no query>"), WordProperty.asString(this.pProperties), this.getCorpus().getName());
 	}
 	
 	
@@ -826,8 +851,8 @@
 					int[] structs = CorpusManager.getCorpusManager().getCqiClient().cpos2Struc(property.getQualifiedName(), allpositionsarray);
 					propsId.put(property, structs);
 				}
-				else {
-					int[] indices = CorpusManager.getCorpusManager().getCqiClient().cpos2Id(property.getQualifiedName(), allpositionsarray);
+				else if (property instanceof WordProperty) {
+					int[] indices = ((WordProperty)property).cpos2Id(allpositionsarray);
 					propsId.put(property, indices);
 				}
 			}
Index: tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/CQPLexicon.java
===================================================================
--- tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/CQPLexicon.java	(revision 2947)
+++ tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/CQPLexicon.java	(revision 2948)
@@ -35,6 +35,7 @@
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.Map;
 
 import org.eclipse.core.runtime.IProgressMonitor;
@@ -61,53 +62,87 @@
  * @author sloiseau
  */
 public class CQPLexicon {
-	
-	
+
+
 	/** The forms. */
 	private String[] forms;
-	
+
 	/** The freqs. */
 	private int[] freqs;
-	
+
 	/** The ids. */
 	private int[] ids;
-	
+
 	/** The number of tokens. */
 	int numberOfTokens = -1;
-	
+
 	/** The symbol. */
 	private String symbol;
-	
+
 	/** The writer. */
 	private OutputStreamWriter writer;
-	
+
 	/**
 	 * The property.
 	 */
-	protected Property pProperty;
-	
+	protected WordProperty pProperty;
+
 	private CQPCorpus corpus;
-	
+
 	/**
 	 * @param corpus
 	 */
 	public CQPLexicon(CQPCorpus corpus) {
 		this.corpus = corpus;
 	}
-	
+
 	public boolean _compute() throws Exception {
-		if (this.getParent() instanceof MainCorpus) {
-			return computeWithMainCorpus((MainCorpus) this.getParent(), pProperty, null);
+
+		if (pProperty instanceof VirtualProperty) {
+			return computeWithVirtualProperty(this.getParent(), (VirtualProperty)pProperty);
+		} else {
+			if (this.getParent() instanceof MainCorpus) {
+				return computeWithMainCorpus((MainCorpus) this.getParent(), pProperty, null); // uses CQi fdist method
+			}
+			else if (this.getParent() instanceof Subcorpus) {
+				return computewithSubCorpus((Subcorpus) this.getParent(), pProperty, null); // uses CQi fdist method
+			}
+			else {
+				Log.severe("Error: Lexicon parent is neither a Maincorpus nor a Subcorpus."); //$NON-NLS-1$
+				return false;
+			}
 		}
-		else if (this.getParent() instanceof Subcorpus) {
-			return computewithSubCorpus((Subcorpus) this.getParent(), pProperty, null);
+	}
+
+	private boolean computeWithVirtualProperty(CQPCorpus corpus, VirtualProperty property) {
+
+		int[] positions = MatchUtils.toPositions(corpus.getMatches());
+		int[] ids2 = property.cpos2Id(positions);
+		Arrays.sort(ids2);
+		HashSet<Integer> test = new HashSet<Integer>();
+		int[] freqs2 = new int[ids2.length]; // max freqs length
+		int[] idsHash = new int[ids2.length]; // max idsHash length
+		idsHash[0] = ids2[0];
+		int n = 0; // max size
+		for (int i = 0 ; i < ids2.length ; i++) {
+			test.add(ids2[i]);
+			if (idsHash[n] != ids2[i]) { // new entry
+				n++;
+				idsHash[n] = ids2[i];
+			}
+			freqs2[n] = freqs2[n] + 1;
 		}
-		else {
-			Log.severe("Error: Lexicon parent is neither a Maincorpus nor a Subcorpus."); //$NON-NLS-1$
-			return false;
-		}
+			
+		ids = new int[n];
+		System.arraycopy(idsHash, 0, ids, 0, n);
+		freqs = new int[n];
+		System.arraycopy(freqs2, 0, freqs, 0, n);
+			
+		init(corpus, property, freqs, ids);
+		return true;
+
 	}
-	
+
 	/**
 	 * Gets the lexicon relative to a given property.
 	 * 
@@ -119,7 +154,7 @@
 	 * @throws CqiClientException
 	 *             the cqi client exception
 	 */
-	protected boolean computeWithMainCorpus(MainCorpus corpus, Property property, IProgressMonitor monitor) throws CqiClientException {
+	protected boolean computeWithMainCorpus(MainCorpus corpus, WordProperty property, IProgressMonitor monitor) throws CqiClientException {
 		// System.out.println("in "+this.getCqpId()+" look for cached lexicon "+property);
 		// System.out.println("not found");
 		int lexiconSize;
@@ -129,12 +164,12 @@
 		catch (Exception e) {
 			throw new CqiClientException(e);
 		}
-		
+
 		int[] ids = new int[lexiconSize];
 		for (int i = 0; i < ids.length; i++) {
 			ids[i] = i;
 		}
-		
+
 		int[] freqs;
 		try {
 			freqs = CorpusManager.getCorpusManager().getCqiClient().id2Freq(property.getQualifiedName(), ids);
@@ -142,11 +177,11 @@
 		catch (Exception e) {
 			throw new CqiClientException(e);
 		}
-		
+
 		this.init(corpus, property, freqs, ids);
 		return true;
 	}
-	
+
 	// /**
 	// *
 	// * @param corpus
@@ -197,7 +232,7 @@
 	// init(corpus, property, freqs, ids);
 	// return true;
 	// }
-	
+
 	/**
 	 * 
 	 * @param corpus
@@ -208,26 +243,26 @@
 	 */
 	// FIXME: SJ: why this method needs to create and delete some new subcorpus? the computing can't be done directly on the corpus argument?
 	// eg. dist = CorpusManager.getCorpusManager().getCqiClient().fdist1(corpus.getQualifiedCqpId(), 0, ICqiClient.CQI_CONST_FIELD_MATCH, property.getName());
-	protected boolean computewithSubCorpus(Subcorpus corpus, Property property, IProgressMonitor monitor) throws CqiClientException {
-		
+	protected boolean computewithSubCorpus(Subcorpus corpus, WordProperty property, IProgressMonitor monitor) throws CqiClientException {
+
 		// System.out.println("not found");
 		// Log.finest(NLS.bind(IndexCoreMessages.computingTheLexiconOfSubcorpusP0, corpus.getName()));
 		// long start = System.currentTimeMillis();
 		int[][] fdist = null;
-		
+
 		boolean fast = false;
-		
+
 		// FIXME: SJ: old version
 		if (!fast) {
-			
+
 			AbstractCqiClient cqi = CorpusManager.getCorpusManager().getCqiClient();
 			String tmp = "TMP" + CQPCorpus.getNextSubcorpusCounter();
 			String qtmp = corpus.getMainCorpus().getQualifiedCqpId() + ":" + tmp;
-			
+
 			try {
 				// System.out.println("subcorpus: "+corpus.getQualifiedCqpId());
 				// System.out.println("query subcorpus: "+qtmp);
-				
+
 				cqi.cqpQuery(corpus.getQualifiedCqpId(), tmp, "[]"); //$NON-NLS-1$
 				fdist = CorpusManager.getCorpusManager().getCqiClient().fdist1(qtmp, 0, ICqiClient.CQI_CONST_FIELD_MATCH, property.getName());
 				// System.out.println("nb lines: "+fdist.length);
@@ -251,7 +286,7 @@
 		}
 		// FIXME: SJ: new version by MD that seems fastest, need to test on all types of lexicons corpora before replacing old version
 		else {
-			
+
 			try {
 				int[] positions = MatchUtils.toPositions(corpus.getMatches());
 				int[] indexes = CorpusManager.getCorpusManager().getCqiClient().cpos2Id(property.getQualifiedName(), positions);
@@ -261,7 +296,7 @@
 					counts[i]++;
 				}
 				fdist = new int[indexes.length][2];
-				
+
 				int n = 0;
 				for (int i : indexes) {
 					fdist[n][0] = i;
@@ -275,19 +310,19 @@
 			}
 		}
 		int lexiconSize = fdist.length;
-		
+
 		int[] freqs = new int[lexiconSize];
 		int[] ids = new int[lexiconSize];
 		for (int i = 0; i < fdist.length; i++) {
 			ids[i] = fdist[i][0];
 			freqs[i] = fdist[i][1];
 		}
-		
+
 		init(corpus, property, freqs, ids);
 		return true;
 	}
-	
-	
+
+
 	/**
 	 * Compute number of tokens. / this.nbr
 	 */
@@ -299,7 +334,7 @@
 			// if (freqs[i] != 1) System.out.println(freqs[i]);
 		}
 	}
-	
+
 	/**
 	 * Dump lexicon forms and frequencies in a String.
 	 *
@@ -315,7 +350,7 @@
 		}
 		return buffer.toString();
 	}
-	
+
 	/*
 	 * (non-Javadoc)
 	 * @see java.lang.Object#equals(java.lang.Object)
@@ -326,13 +361,13 @@
 			return false;
 		}
 		CQPLexicon other = (CQPLexicon) obj;
-		
+
 		if (other.nbrOfType() != this.nbrOfType()) {
 			return false;
 		}
 		return (Arrays.equals(freqs, other.getFreq()) && Arrays.equals(getForms(), other.getForms()));
 	}
-	
+
 	/**
 	 * The corpus or subcorpus this lexicon is build on.
 	 * 
@@ -341,12 +376,12 @@
 	public CQPCorpus getCorpus() {
 		return corpus;
 	}
-	
-	
+
+
 	public String getDetails() {
 		return this.getParent().getName() + " " + this.pProperty.getName(); //$NON-NLS-1$
 	}
-	
+
 	// TODO: move this into a Lexicon chart renderer
 	// /**
 	// * Draw a pareto graphic with this frequency list and record it into the
@@ -365,9 +400,9 @@
 	// throw new StatException(e);
 	// }
 	// }
-	
+
 	/**
-	 * The dif ferent types in the lexicon, the type at the index <code>j</code>
+	 * The different types in the lexicon, the type at the index <code>j</code>
 	 * of this array have the frequency at index <code>j</code> in the array
 	 * returned by {@link #getFreq()}.
 	 * 
@@ -379,7 +414,9 @@
 				return new String[0];
 			}
 			try {
-				forms = CorpusManager.getCorpusManager().getCqiClient().id2Str(pProperty.getQualifiedName(), ids);
+				if (pProperty instanceof WordProperty) {
+					forms = ((WordProperty)pProperty).id2Str(ids);
+				}				
 			}
 			catch (Exception e) {
 				// TODO Auto-generated catch block
@@ -388,7 +425,7 @@
 		}
 		return forms;
 	}
-	
+
 	/**
 	 * The dif ferent types in the lexicon, the type at the index <code>j</code>
 	 * of this array have the frequency at index <code>j</code> in the array
@@ -425,7 +462,7 @@
 			return subforms;
 		}
 	}
-	
+
 	/**
 	 * The dif ferent frequencies in the lexicon. See {@link #getForms()}.
 	 * 
@@ -434,7 +471,7 @@
 	public int[] getFreq() {
 		return freqs;
 	}
-	
+
 	/**
 	 * return the ids of the entries.
 	 *
@@ -443,7 +480,7 @@
 	public int[] getIds() {
 		return ids;
 	}
-	
+
 	public String getName() {
 		try {
 			return this.corpus.getSimpleName() + ": " + this.getSimpleName();
@@ -452,7 +489,7 @@
 		}
 		return ""; //$NON-NLS-1$
 	}
-	
+
 	/**
 	 * The property this lexicon is build on.
 	 * 
@@ -461,11 +498,11 @@
 	public Property getProperty() {
 		return pProperty;
 	}
-	
+
 	public String getSimpleName() {
 		return this.getProperty().getName();
 	}
-	
+
 	/**
 	 * Gets the symbol.
 	 *
@@ -474,7 +511,7 @@
 	public String getSymbol() {
 		return this.symbol;
 	}
-	
+
 	/**
 	 * Hack frequencies using a map to set forms and frequencies
 	 *
@@ -488,7 +525,7 @@
 		if (map.size() != forms.length) {
 			return false;
 		}
-		
+
 		// super(corpus);
 		int size = map.size();
 		int[] freqs = new int[size];
@@ -496,11 +533,11 @@
 		for (int i = 0; i < forms.length; i++) {
 			freqs[i] = map.get(forms[i]);
 		}
-		
+
 		this.freqs = freqs;
 		return true;
 	}
-	
+
 	/**
 	 * Protected on purpose: should be accessed through others initializer.
 	 *
@@ -511,7 +548,7 @@
 	 *            {@link CQPCorpus#getLexicon(Property)} or
 	 *            {@link Subcorpus#getLexicon(Property)}.
 	 */
-	protected void init(TXMResult corpus, Property property, int[] freq, int[] ids) {
+	protected void init(TXMResult corpus, WordProperty property, int[] freq, int[] ids) {
 		if (freq.length != ids.length) {
 			throw new IllegalArgumentException("wrong size freq.length != ids.length " + freq.length + " != " + ids.length);
 		}
@@ -520,8 +557,8 @@
 		this.forms = getForms();
 		this.pProperty = property;
 	}
-	
-	
+
+
 	/**
 	 * Number of tokens (sum of all the frequencies) in the corpus.
 	 * 
@@ -533,8 +570,8 @@
 		}
 		return numberOfTokens;
 	}
-	
-	
+
+
 	/**
 	 * Number of different types in the frequency list.
 	 * 
@@ -548,14 +585,14 @@
 			return 0;
 		}
 	}
-	
-	public void setParameters(Property property) {
+
+	public void setParameters(WordProperty property) {
 		this.pProperty = property;
 	}
-	
+
 	public boolean setParameters(TXMParameters parameters) {
 		try {
-			Property p = (Property) parameters.get("properties");
+			WordProperty p = (WordProperty) parameters.get("properties");
 			this.setParameters(p);
 		}
 		catch (Exception e) {
@@ -564,7 +601,7 @@
 		}
 		return true;
 	}
-	
+
 	/**
 	 * Sets the symbol.
 	 *
@@ -573,13 +610,13 @@
 	public void setSymbol(String symbol) {
 		this.symbol = symbol;
 	}
-	
-	
+
+
 	@Override
 	public String toString() {
 		return this.getName();
 	}
-	
+
 	/**
 	 * To txt.
 	 *
@@ -605,7 +642,7 @@
 			org.txm.utils.logger.Log.printStackTrace(e1);
 			return false;
 		}
-		
+
 		try {
 			writer.write(this.dump(colseparator, txtseparator));
 			writer.close();
@@ -614,23 +651,23 @@
 			org.txm.utils.logger.Log.printStackTrace(e);
 			return false;
 		}
-		
+
 		return true;
 	}
-	
+
 	/**
 	 * Sets the unit property.
 	 * 
 	 * @param property the unit property
 	 */
-	public void setProperty(Property property) {
+	public void setProperty(WordProperty property) {
 		this.pProperty = property;
 	}
-	
-	
-	public static CQPLexicon getLexicon(CQPCorpus corpus, Property property, TXMProgressMonitor monitor, boolean visible) throws Exception {
+
+
+	public static CQPLexicon getLexicon(CQPCorpus corpus, WordProperty property, TXMProgressMonitor monitor, boolean visible) throws Exception {
 		CQPLexicon lexicon = null;
-		
+
 		// recycling parent Lexicon if exists
 		ArrayList<CQPLexicon> partLexicons = (ArrayList<CQPLexicon>) corpus.getObjectCacheForClass(CQPLexicon.class);
 		for (int i = 0; i < partLexicons.size(); i++) {
@@ -639,20 +676,23 @@
 				break;
 			}
 		}
-		
+
 		// creating new Lexicon
 		if (lexicon == null || !lexicon.getProperty().getFullName().equals(property.getFullName())) {
 			lexicon = new CQPLexicon(corpus);
 			lexicon.setProperty(property);
 			lexicon._compute();
+			
+			// and store it !
+			partLexicons.add(lexicon);
 		}
-		
+
 		Log.finest(TXMCoreMessages.bind("Lexicon = {0} {1}.", lexicon, lexicon.hashCode()));
-		
+
 		return lexicon;
 	}
-	
-	
+
+
 	/**
 	 * Gets a Lexicon from the specified corpus.
 	 * If a Lexicon child exists in the Corpus from the specified property, returns it otherwise creates and computes a new Lexicon.
@@ -662,11 +702,11 @@
 	 * @return
 	 * @throws Exception
 	 */
-	public static CQPLexicon getLexicon(CQPCorpus corpus, Property property, TXMProgressMonitor monitor) throws Exception {
+	public static CQPLexicon getLexicon(CQPCorpus corpus, WordProperty property, TXMProgressMonitor monitor) throws Exception {
 		return getLexicon(corpus, property, monitor, true);
 	}
-	
-	
+
+
 	// /**
 	// * Find or build a lexicon given a Corpus (MainCorpus or SubCorpus).
 	// *
@@ -693,9 +733,9 @@
 	// return null;
 	// }
 	// }
-	
+
 	public CQPCorpus getParent() {
 		return corpus;
-		
+
 	}
 }
Index: tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/PositionProperty.java
===================================================================
--- tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/PositionProperty.java	(revision 0)
+++ tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/PositionProperty.java	(revision 2948)
@@ -0,0 +1,91 @@
+package org.txm.searchengine.cqp.corpus;
+
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+
+/**
+ * A CQP property at token/word level
+ * 
+ * @author mdecorde
+ *
+ */
+public class PositionProperty extends VirtualProperty {
+	
+	int maxLength;
+	NumberFormat f;
+	
+	/**
+	 * Creates a new WordProperty.
+	 * 
+	 * @param name
+	 * @param corpus
+	 */
+	public PositionProperty(CQPCorpus corpus) {
+		super("position", corpus);
+		try {
+			maxLength = Integer.toString(corpus.getMainCorpus().getSize()).length();
+		} catch (CqiClientException e) {
+			e.printStackTrace();
+			maxLength = Integer.toString(Integer.MAX_VALUE).length();
+		}
+		
+		f = NumberFormat.getNumberInstance();
+		f.setMinimumIntegerDigits(maxLength);
+	}
+	
+	public String cpos2Str(int position) {
+		return f.format(position);
+	}
+	
+	public String[] cpos2Str(int[] positions) {
+		return getValues(positions).toArray(new String[positions.length]);
+	}
+	
+	public List<String> getValues(int[] positions) {
+		ArrayList<String> rez = new ArrayList<>();
+		for (int p : positions) {
+			rez.add(cpos2Str(p));
+		}
+		return rez;
+	}
+
+	@Override
+	public int[] cpos2Id(int[] allpositionsarray) {
+		return allpositionsarray; // lol
+	}
+
+	@Override
+	public int cpos2Id(int position) {
+		return position; // lol
+	}
+
+	@Override
+	public String[] id2Str(int[] indices) {
+		String[] rez = new String[indices.length];
+		for (int i = 0 ; i < rez.length ; i++) {
+			rez[i] = cpos2Str(indices[i]);
+		}
+		return rez;
+	}
+
+	@Override
+	public String id2Str(int indice) {
+		return cpos2Str(indice);
+	}
+
+	@Override
+	public String getCQLTest(String value) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public String getCQLTest(List<String> values) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+}
+

Property changes on: tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/PositionProperty.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/CQPCorpus.java
===================================================================
--- tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/CQPCorpus.java	(revision 2947)
+++ tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/CQPCorpus.java	(revision 2948)
@@ -43,6 +43,7 @@
 import org.txm.objects.CorpusCommandPreferences;
 import org.txm.objects.Project;
 import org.txm.searchengine.core.messages.SearchEngineCoreMessages;
+import org.txm.searchengine.cqp.CQPSearchEngine;
 import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
 import org.txm.searchengine.cqp.clientExceptions.InvalidCqpIdException;
 import org.txm.searchengine.cqp.core.functions.selection.SelectionResult;
@@ -62,10 +63,13 @@
  * @see org.txm.searchengine.cqp.corpus.MainCorpus
  * @see org.txm.searchengine.cqp.corpus.Subcorpus
  * 
- * @author Jean-Philippe Magué, Sylvain Loiseau
+ * @author Jean-Philippe Magué, Sylvain Loiseau, mdecorde
  */
 public abstract class CQPCorpus extends org.txm.objects.CorpusBuild implements CqpObject {
 	
+	/**
+	 * subresults cache. eg used to store CQP lexicons
+	 */
 	protected static HashMap<Class<?>, ArrayList<?>> cache = new HashMap<>();
 	
 	private static final int CACHE_MAXIMUM_SIZE = 5;
@@ -313,6 +317,8 @@
 	protected StructuralUnit textStructuralUnit;
 	
 	protected WordProperty wordProperty = null;
+
+	private List<VirtualProperty> virtualProperties;
 	
 	/**
 	 * 
@@ -454,6 +460,7 @@
 		charset = "latin1"; //$NON-NLS-1$
 		lang = null;
 		lexicalUnitsProperties = null;
+		virtualProperties = null;
 		size = -1;
 		structuralUnits = null;
 		symbol = null;
@@ -986,18 +993,8 @@
 	public List<Partition> getPartitions() {
 		return getChildren(Partition.class);
 	}
-	
+		
 	/**
-	 * Gets the properties defined for the lexical units of this corpus.
-	 * 
-	 * @return the properties
-	 * 
-	 * @throws CqiClientException
-	 *             the cqi client exception
-	 */
-	public abstract List<WordProperty> getProperties() throws CqiClientException;
-	
-	/**
 	 * Gets the virtual properties of this corpus.
 	 * 
 	 * current implementation only returns the "position" virtual property
@@ -1008,24 +1005,79 @@
 	 *             the cqi client exception
 	 */
 	public List<VirtualProperty> getVirtualProperties() {
-		ArrayList<VirtualProperty> rez = new ArrayList<>();
-		rez.add(new VirtualProperty("position", this));
-		return rez;
+		if (virtualProperties == null) {
+			virtualProperties = new ArrayList<>();
+			virtualProperties.add(new PositionProperty(this));
+			virtualProperties.add(new LengthProperty(this));
+		}
+		return virtualProperties;
 	}
 	
 	/**
-	 * Gets a property from its name.
+	 * Gets the properties available in this corpus.
 	 * 
-	 * @param name
-	 *            the name
+	 * @return the properties
 	 * 
-	 * @return the property
-	 * 
 	 * @throws CqiClientException
 	 *             the cqi client exception
 	 */
-	public abstract WordProperty getProperty(String name) throws CqiClientException;
+	public List<WordProperty> getProperties() throws CqiClientException {
+		if (this.lexicalUnitsProperties != null) {
+			return this.lexicalUnitsProperties;
+		}
+		
+		String[] propertiesName;
+		try {
+			propertiesName = CQPSearchEngine.getCqiClient().corpusPositionalAttributes(this.getMainCorpus().pID);
+		}
+		catch (Exception e) {
+			throw new CqiClientException(e);
+		}
+		
+		List<WordProperty> properties = new ArrayList<>(propertiesName.length);
+		for (int i = 0; i < propertiesName.length; i++) {
+			properties.add(new WordProperty(propertiesName[i], this));
+		}
+		this.lexicalUnitsProperties = properties;
+		return properties;
+	}
 	
+	/*
+	 * (non-Javadoc)
+	 * @see
+	 * org.txm.searchengine.cqp.corpus.Corpus#getProperty(java.lang.
+	 * String)
+	 */
+	public WordProperty getProperty(String name) throws CqiClientException {
+		if (this.lexicalUnitsProperties == null) {
+			getProperties();
+		}
+		
+		int idx = name.indexOf(".");
+		if (idx > 0) { // the name if a qualified name
+			name = name.substring(idx + 1);
+		}
+		
+		if (VirtualProperty.isAVirtualPropertyFullName(name)) {
+			name = VirtualProperty.fullnameToName(name);
+			
+			for (WordProperty property : getVirtualProperties()) {
+				if (property.getName().equals(name)) {
+					return property;
+				}
+			}
+		} else {
+			for (WordProperty property : getProperties()) {
+				if (property.getName().equals(name)) {
+					return property;
+				}
+			}
+		}
+		
+		
+		return null;
+	}
+	
 	@Override
 	public String getSimpleName() {
 		return this.getUserName();
@@ -1418,6 +1470,16 @@
 	}
 	
 	public Property getVirtualProperty(String s) {
-		return new VirtualProperty(s, this);
+		if (s == null || s.length() == 0) {
+			return null;
+		}
+		
+		for (VirtualProperty p : this.getVirtualProperties()) {
+			if (s.equals(p.getName())) {
+				return p;
+			}
+		}
+		
+		return null;
 	}
 }
Index: tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/WordProperty.java
===================================================================
--- tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/WordProperty.java	(revision 2947)
+++ tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/WordProperty.java	(revision 2948)
@@ -1,7 +1,12 @@
 package org.txm.searchengine.cqp.corpus;
 
+import java.io.IOException;
 import java.util.List;
 
+import org.txm.searchengine.cqp.clientExceptions.UnexpectedAnswerException;
+import org.txm.searchengine.cqp.corpus.query.CQLQuery;
+import org.txm.searchengine.cqp.serverException.CqiServerError;
+
 /**
  * A CQP property at token/word level
  * 
@@ -39,9 +44,51 @@
 			if (i > 0) {
 				str += "_";
 			}
-			str += properties.get(i).getName();
+			str += properties.get(i).getFullName();
 		}
 		return "@" + str;
 	}
 	
+	public int[] cpos2Id(int[] positions) throws UnexpectedAnswerException, IOException, CqiServerError {
+		return CorpusManager.getCorpusManager().getCqiClient().cpos2Id(this.getQualifiedName(), positions);
+	}
+	
+	public String[] cpos2Str(int[] positions) throws UnexpectedAnswerException, IOException, CqiServerError {
+		return CorpusManager.getCorpusManager().getCqiClient().cpos2Str(this.getQualifiedName(), positions);
+	}
+	
+	public String[] id2Str(int[] ids) throws UnexpectedAnswerException, IOException, CqiServerError {
+		return CorpusManager.getCorpusManager().getCqiClient().id2Str(this.getQualifiedName(), ids);
+	}
+	
+	public int[] str2Id(String[] values) throws UnexpectedAnswerException, IOException, CqiServerError {
+		return CorpusManager.getCorpusManager().getCqiClient().str2Id(this.getQualifiedName(), values);
+	}
+	
+	public int[] regex2Id(String regex) throws UnexpectedAnswerException, IOException, CqiServerError {
+		return CorpusManager.getCorpusManager().getCqiClient().regex2Id(this.getQualifiedName(), regex);
+	}
+	
+	public int str2Id(String value) throws UnexpectedAnswerException, IOException, CqiServerError {
+		return CorpusManager.getCorpusManager().getCqiClient().str2Id(this.getQualifiedName(), new String[] {value})[0];
+	}
+	
+	public String getCQLTest(String value) {
+		return this.getName() + "=\"" +  CQLQuery.addBackSlash(value)+ "\"";
+	}
+	
+	public String getCQLTest(List<String> values) {
+		StringBuilder sb = new StringBuilder();
+		sb.append(this.getName() + "=\""); //$NON-NLS-1$
+		for (int i = 0 ; i < values.size() ; i++) {
+			String s = values.get(i);
+			s = CQLQuery.addBackSlash(s);
+			sb.append(s); //$NON-NLS-1$
+			if (i < values.size() -1) {
+				sb.append("|"); //$NON-NLS-1$
+			}
+		}
+		sb.append("\"");
+		return sb.toString();
+	};
 }
Index: tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/MainCorpus.java
===================================================================
--- tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/MainCorpus.java	(revision 2947)
+++ tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/MainCorpus.java	(revision 2948)
@@ -388,64 +388,9 @@
 		return 1;
 	}
 	
-	/**
-	 * Gets the properties available in this corpus.
-	 * 
-	 * @return the properties
-	 * 
-	 * @throws CqiClientException
-	 *             the cqi client exception
-	 */
-	@Override
-	public List<WordProperty> getProperties() throws CqiClientException {
-		if (this.lexicalUnitsProperties != null) {
-			return this.lexicalUnitsProperties;
-		}
-		
-		String[] propertiesName;
-		try {
-			propertiesName = CQPSearchEngine.getCqiClient().corpusPositionalAttributes(this.pID);
-		}
-		catch (Exception e) {
-			throw new CqiClientException(e);
-		}
-		
-		List<WordProperty> properties = new ArrayList<>(propertiesName.length);
-		for (int i = 0; i < propertiesName.length; i++) {
-			properties.add(new WordProperty(propertiesName[i], this));
-		}
-		this.lexicalUnitsProperties = properties;
-		return properties;
-	}
-	
 	/*
 	 * (non-Javadoc)
 	 * @see
-	 * org.txm.searchengine.cqp.corpus.Corpus#getProperty(java.lang.
-	 * String)
-	 */
-	@Override
-	public WordProperty getProperty(String name) throws CqiClientException {
-		if (this.lexicalUnitsProperties == null) {
-			getProperties();
-		}
-		
-		int idx = name.indexOf(".");
-		if (idx > 0) { // the name if a qualified name
-			name = name.substring(idx + 1);
-		}
-		
-		for (WordProperty property : this.lexicalUnitsProperties) {
-			if (property.getName().equals(name)) {
-				return property;
-			}
-		}
-		return null;
-	}
-	
-	/*
-	 * (non-Javadoc)
-	 * @see
 	 * org.txm.searchengine.cqp.corpus.CqpObject#getQualifiedCqpId()
 	 */
 	@Override
Index: tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/Property.java
===================================================================
--- tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/Property.java	(revision 2947)
+++ tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/Property.java	(revision 2948)
@@ -74,7 +74,7 @@
 	 * @return the qualified name
 	 */
 	public String getQualifiedName() {
-		return this.corpus.getCqpId() + "." + this.getFullName(); //$NON-NLS-1$
+		return this.corpus.getMainCorpus().getCqpId() + "." + this.getFullName(); //$NON-NLS-1$
 	}
 	
 	/**
@@ -158,7 +158,8 @@
 		String[] split = str.split(TXMPreferences.LIST_SEPARATOR);
 		for (String s : split) {
 			try {
-				Property p = corpus.getProperty(s);
+				Property p = corpus.getProperty(s); // manage all Property implementations : Word, StructuralUnits and Virtual
+				
 				if (p != null) {
 					properties.add(p);
 				}
Index: tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/Subcorpus.java
===================================================================
--- tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/Subcorpus.java	(revision 2947)
+++ tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/Subcorpus.java	(revision 2948)
@@ -279,27 +279,7 @@
 			return 0;
 		}
 	}
-	
-	/*
-	 * (non-Javadoc)
-	 * @see org.txm.searchengine.cqp.corpus.Corpus#getProperties()
-	 */
-	@Override
-	public List<WordProperty> getProperties() throws CqiClientException {
-		return getMainCorpus().getProperties();
-	}
-	
-	/*
-	 * (non-Javadoc)
-	 * @see
-	 * org.txm.searchengine.cqp.corpus.Corpus#getProperty(java.lang.
-	 * String)
-	 */
-	@Override
-	public WordProperty getProperty(String name) throws CqiClientException {
-		return getMainCorpus().getProperty(name);
-	}
-	
+		
 	// protected void finalize() throws Throwable {
 	// try {
 	// //
Index: tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/LengthProperty.java
===================================================================
--- tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/LengthProperty.java	(revision 0)
+++ tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/LengthProperty.java	(revision 2948)
@@ -0,0 +1,136 @@
+package org.txm.searchengine.cqp.corpus;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.TreeSet;
+
+import org.txm.searchengine.cqp.CQPSearchEngine;
+import org.txm.searchengine.cqp.clientExceptions.CqiClientException;
+import org.txm.searchengine.cqp.clientExceptions.UnexpectedAnswerException;
+import org.txm.searchengine.cqp.serverException.CqiServerError;
+
+/**
+ * A CQP property at token/word level
+ * 
+ * @author mdecorde
+ *
+ */
+public class LengthProperty extends VirtualProperty {
+	
+	/**
+	 * Creates a new WordProperty.
+	 * 
+	 * @param name
+	 * @param corpus
+	 */
+	public LengthProperty(CQPCorpus corpus) {
+		super("length", corpus);
+	}
+	
+	public String cpos2Str(int position) {
+		
+		try {
+			String[] rez = CQPSearchEngine.getCqiClient().cpos2Str(corpus.getWordProperty().getQualifiedName(), new int[] {position});
+			return Integer.toString(rez[0].length());
+		} catch (Exception e) {
+			return "0";
+		}
+	}
+	
+	public List<String> getValues(int[] positions) {
+		return Arrays.asList(cpos2Str(positions));
+	}
+	
+	public String[] cpos2Str(int[] positions) {
+		try {
+			String[] rez = CQPSearchEngine.getCqiClient().cpos2Str(corpus.getWordProperty().getQualifiedName(), positions);
+			for (int i = 0 ; i < rez.length ; i++) {
+				rez[i] = Integer.toString(rez[i].length());
+			}
+			return rez;
+		} catch (Exception e) {
+			return new String[positions.length];
+		}
+	}
+
+	@Override
+	public int[] cpos2Id(int[] positions) {
+		try {
+			String[] tmp = CQPSearchEngine.getCqiClient().cpos2Str(corpus.getWordProperty().getQualifiedName(), positions);
+			int[] rez = new int[tmp.length];
+			for (int i = 0 ; i < rez.length ; i++) {
+				rez[i] = tmp[i].length();
+			}
+			return rez;
+		} catch (Exception e) {
+			return new int[positions.length];
+		}
+	}
+
+	@Override
+	public int cpos2Id(int position) {
+		return cpos2Id(new int[] {position})[0];
+	}
+	
+	@Override
+	public String[] id2Str(int[] indices) {
+		String[] rez = new String[indices.length];
+		for (int i = 0 ; i < rez.length ; i++) {
+			rez[i] = Integer.toString(indices[i]);
+		}
+		return rez;
+	}
+
+	@Override
+	public String id2Str(int indice) {
+		return Integer.toString(indice);
+	}
+
+	@Override
+	public String getCQLTest(String value) {
+		try {
+			int l = Integer.parseInt(value);
+			StringBuilder sb = new StringBuilder();
+			sb.append("word=\"");
+			for (int i = 0 ; i < l ; i++) {
+				sb.append(".");
+			}
+			sb.append("\"");
+			return sb.toString();
+		} catch(Exception e) {
+			
+		}
+		return null;
+	}
+
+	@Override
+	public String getCQLTest(List<String> values) {
+		try {
+			TreeSet<String> hash = new TreeSet<>();
+			StringBuilder sb = new StringBuilder();
+			for (String value : values) {
+				int l = Integer.parseInt(value);
+				
+				sb.setLength(0);
+				for (int i = 0 ; i < l ; i++) {
+					sb.append(".");
+				}
+				hash.add(sb.toString());
+			}
+			
+			sb.setLength(0);
+			sb.append("word=\"");
+			for (String dots : hash) {
+				sb.append(dots);
+			}
+			sb.append("\"");
+			return sb.toString();
+		} catch(Exception e) {
+			
+		}
+		return null;
+	}
+}
+

Property changes on: tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/LengthProperty.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/VirtualProperty.java
===================================================================
--- tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/VirtualProperty.java	(revision 2947)
+++ tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/corpus/VirtualProperty.java	(revision 2948)
@@ -1,6 +1,5 @@
 package org.txm.searchengine.cqp.corpus;
 
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -9,7 +8,7 @@
  * @author mdecorde
  *
  */
-public class VirtualProperty extends Property {
+public abstract class VirtualProperty extends WordProperty {
 	
 	/**
 	 * Creates a new WordProperty.
@@ -23,37 +22,31 @@
 	
 	@Override
 	public String getFullName() {
-		return "<" + getName() + ">";
+		return "(" + getName() + ")";
 	}
 	
-	/**
-	 * Creates a readable formated string from the specified properties list.
-	 * 
-	 * @param properties
-	 * @return
-	 */
-	public static String asString(List<VirtualProperty> properties) {
-		
-		String str = "";
-		for (int i = 0; i < properties.size(); i++) {
-			if (i > 0) {
-				str += "_";
-			}
-			str += properties.get(i).getFullName();
-		}
-		return "@" + str;
-	}
+	public abstract String cpos2Str(int position);
 	
-	public String getValue(int position) {
-		return Integer.toString(position);
+	public abstract String[] cpos2Str(int[] positions);
+	
+	public abstract int[] cpos2Id(int[] allpositionsarray);
+	
+	public abstract int cpos2Id(int position);
+
+	public abstract String[] id2Str(int[] indices);
+	
+	public abstract String id2Str(int indice);
+	
+	public String toString() {
+		return getFullName();
 	}
+
+	public static boolean isAVirtualPropertyFullName(String name) {
+		return name != null && name.startsWith("(") && name.endsWith(")")&& name.length() > 2 ;
+	}
 	
-	public List<String> getValues(int[] positions) {
-		ArrayList<String> rez = new ArrayList<>();
-		for (int p : positions) {
-			rez.add(getValue(p));
-		}
-		return rez;
+	public static String fullnameToName(String fullname) {
+		return fullname.substring(1, fullname.length() - 1);
 	}
 }
 
Index: tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/ReferencePattern.java
===================================================================
--- tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/ReferencePattern.java	(revision 2947)
+++ tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/ReferencePattern.java	(revision 2948)
@@ -65,10 +65,7 @@
 			
 			String[] split = v.split("\t");
 			for (String s : split) {
-				if (s.startsWith("<") && s.endsWith(">")) {
-					props.addProperty(corpus.getVirtualProperty(s));
-				}
-				else if (s.contains("_")) {
+				if (s.contains("_")) {
 					String[] split2 = s.split("_", 2);
 					StructuralUnit su = corpus.getStructuralUnit(split2[0]);
 					if (su != null) {
@@ -184,14 +181,9 @@
 		String title = ""; //$NON-NLS-1$
 		for (Property p : this.properties) {
 			if (p == null) continue;
-			if (p instanceof StructuralUnitProperty) {
-				StructuralUnitProperty sp = (StructuralUnitProperty) p;
-				title += sp.getFullName() + ", "; //$NON-NLS-1$
+			if (p instanceof StructuralUnitProperty || p instanceof VirtualProperty) {
+				title += p.getFullName() + ", "; //$NON-NLS-1$
 			}
-			else if (p instanceof VirtualProperty) {
-				VirtualProperty sp = (VirtualProperty) p;
-				title += sp.getFullName() + ", "; //$NON-NLS-1$
-			}
 			else {
 				title += p.getName() + ", "; //$NON-NLS-1$
 			}
Index: tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/AbstractCqiClient.java
===================================================================
--- tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/AbstractCqiClient.java	(revision 2947)
+++ tmp/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/AbstractCqiClient.java	(revision 2948)
@@ -46,6 +46,7 @@
 import org.txm.searchengine.cqp.corpus.QueryResult;
 import org.txm.searchengine.cqp.corpus.StructuralUnitProperty;
 import org.txm.searchengine.cqp.corpus.VirtualProperty;
+import org.txm.searchengine.cqp.corpus.WordProperty;
 import org.txm.searchengine.cqp.corpus.query.CQLQuery;
 import org.txm.searchengine.cqp.corpus.query.Match;
 import org.txm.searchengine.cqp.serverException.CqiCqpErrorNoSuchCorpus;
@@ -115,18 +116,14 @@
 	public List<String> getSingleData(Property prop, int[] positions) throws UnexpectedAnswerException, IOException, CqiServerError {
 		String qname = prop.getQualifiedName();
 		AbstractCqiClient cqiClient = CorpusManager.getCorpusManager().getCqiClient();
-		if (prop instanceof VirtualProperty) {
-			return ((VirtualProperty) prop).getValues(positions);
-			
-		}
-		else if (prop instanceof StructuralUnitProperty) {
+		if (prop instanceof StructuralUnitProperty) {
 			int[] strucs = cqiClient.cpos2Struc(qname, positions);
 			return Arrays.asList(cqiClient.struc2Str(qname, strucs));
-			
 		}
-		else {
+		else if (prop instanceof WordProperty) {
 			return Arrays.asList(cqiClient.cpos2Str(qname, positions));
 		}
+		return null;
 	}
 	
 	public List<List<String>> getData(Property prop, List<Integer> positions,
@@ -156,17 +153,15 @@
 		
 		// get values for positions
 		String[] values;
-		if (prop instanceof VirtualProperty) {
-			values = ((VirtualProperty) prop).getValues(cpos).toArray(new String[cpos.length]);
-		}
-		else if (prop instanceof StructuralUnitProperty) {
+		if (prop instanceof StructuralUnitProperty) {
 			String qname = ((StructuralUnitProperty) prop).getQualifiedName();
 			int[] structs = this.cpos2Struc(qname, cpos);
 			values = this.struc2Str(qname, structs);
 		}
-		else {
-			String qname = prop.getQualifiedName();
-			values = this.cpos2Str(qname, cpos);
+		else if (prop instanceof WordProperty) {
+			values = ((WordProperty)prop).cpos2Str(cpos);
+		} else {
+			return null;
 		}
 		
 		// sort results by position
