Index: TXM/trunk/org.txm.concordance.rcp/src/org/txm/concordance/rcp/editors/ConcordanceEditor.java
===================================================================
--- TXM/trunk/org.txm.concordance.rcp/src/org/txm/concordance/rcp/editors/ConcordanceEditor.java	(revision 3360)
+++ TXM/trunk/org.txm.concordance.rcp/src/org/txm/concordance/rcp/editors/ConcordanceEditor.java	(revision 3361)
@@ -1465,10 +1465,9 @@
 		StatusLine.setMessage(ConcordanceUIMessages.startComputingConcordance);
 		
 		try {
-			
 			QueriesView.refresh();
 			
-			this.fillDisplayArea(update);
+			this.fillDisplayArea(update );
 			
 			boolean b = concordance.getQueryResultParameter() == null;
 			this.queryWidget.setEnabled(b); // disable the widget if a QueryResult was provided
@@ -2306,13 +2305,14 @@
 		getResultArea().layout(true, true);
 	}
 	
-	/*
-	 * 
+	/**
+	 * @return the number of lines in the table
 	 */
-	public void resetRightTableColumnWidths() {
+	public int resetRightTableColumnWidths() {
 		
 		float W = 1f + queryLabel.getSize().x / (float) queryLabel.getText().length();
 		
+		int n = 0;
 		TableColumn[] columns = viewerRight.getTable().getColumns();
 		for (int i = 0; i < columns.length; i++) {
 			TableColumn column = columns[i];
@@ -2321,7 +2321,7 @@
 			int max = column.getText().length();
 			if (max == 0) continue; // skip no-title columns
 			
-			int n = 0;
+			n = 0;
 			for (TableItem item : viewerRight.getTable().getItems()) {
 				if (max < item.getText(i).length()) max = item.getText(i).length();
 				if (n++ > 100) break; // stop testing after 100 lines
@@ -2336,6 +2336,7 @@
 		
 		viewerRight.getTable().layout(true, true);
 		tableResizeListener.handleEvent(null); // center on keyword column
+		return n;
 	}
 	
 	/**
@@ -2344,10 +2345,11 @@
 	 * Use this method after recomputing a result
 	 * 
 	 * The characters width is estimated using the queryLabel length
+	 * @return the number of lines in the table
 	 */
-	public void resetColumnWidths() {
+	public int resetColumnWidths() {
 		resetLeftTableColumnWidths();
-		resetRightTableColumnWidths();
+		return resetRightTableColumnWidths();
 	}
 	
 	public Composite getExtensionButtonComposite() {
Index: TXM/trunk/org.txm.concordance.rcp/src/org/txm/concordance/rcp/handlers/ComputeConcordance.java
===================================================================
--- TXM/trunk/org.txm.concordance.rcp/src/org/txm/concordance/rcp/handlers/ComputeConcordance.java	(revision 3360)
+++ TXM/trunk/org.txm.concordance.rcp/src/org/txm/concordance/rcp/handlers/ComputeConcordance.java	(revision 3361)
@@ -81,8 +81,7 @@
 		}
 		
 		StatusLine.setMessage(ConcordanceUIMessages.openingTheConcordanceResult);
-		TXMEditor.openEditor(concordance, ConcordanceEditor.class.getName());
-		return null;
+		return TXMEditor.openEditor(concordance, ConcordanceEditor.class.getName());
 	}
 	
 	public static TXMEditor openEditor(Concordance concordance) {
Index: TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/NetCqiClient.java
===================================================================
--- TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/NetCqiClient.java	(revision 3360)
+++ TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/NetCqiClient.java	(revision 3361)
@@ -1938,4 +1938,18 @@
 		this.writeString(entry);
 		return readBoolean();
 	}
+
+	@Override
+	public String getOption(String name) throws UnexpectedAnswerException, IOException, CqiServerError {
+		
+		Log.warning("NOT IMPLEMENTED: NetCqiClient.getOption");
+		return null;
+	}
+
+	@Override
+	public String setOption(String name, String value) throws UnexpectedAnswerException, IOException, CqiServerError {
+		
+		Log.warning("NOT IMPLEMENTED: NetCqiClient.setOption");
+		return null;
+	}
 }
\ No newline at end of file
Index: TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/ICqiClient.java
===================================================================
--- TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/ICqiClient.java	(revision 3360)
+++ TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/ICqiClient.java	(revision 3361)
@@ -351,6 +351,24 @@
 	 * @return the name of the charset
 	 */
 	public String corpusCharset(String corpus) throws UnexpectedAnswerException, IOException, CqiServerError;
+	
+	/**
+	 * Get the String value of a CQP environment option 
+	 *
+	 * @param name the option full name
+	 * @return the value
+	 */
+	public String getOption(String name) throws UnexpectedAnswerException, IOException, CqiServerError;
+	
+	// None
+	/**
+	 * set the String value of a CQP environment option 
+	 *
+	 * @param name the option full name
+	 * @param value the option value to set
+	 * @return the value
+	 */
+	public String setOption(String name, String value) throws UnexpectedAnswerException, IOException, CqiServerError;
 
 	// None (not really implemented anyway)
 	/**
Index: TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/AbstractCqiClient.java
===================================================================
--- TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/AbstractCqiClient.java	(revision 3360)
+++ TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/AbstractCqiClient.java	(revision 3361)
@@ -273,6 +273,9 @@
 	@Override
 	public abstract String[] listCorpora() throws UnexpectedAnswerException, IOException, CqiServerError;
 	
+
+	
+	
 	// None
 	/**
 	 * Gives the corpus charset.
@@ -283,6 +286,7 @@
 	@Override
 	public abstract String corpusCharset(String corpus) throws UnexpectedAnswerException, IOException, CqiServerError;
 	
+	
 	// None (not really implemented anyway)
 	/**
 	 * Gives the corpus properties.
Index: TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/MemCqiServer.java
===================================================================
--- TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/MemCqiServer.java	(revision 3360)
+++ TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/MemCqiServer.java	(revision 3361)
@@ -348,6 +348,10 @@
 	
 	public native String corpusCharset(String arg0) throws UnexpectedAnswerException, IOException, CqiServerError;
 	
+	public native String getOption(String name) throws UnexpectedAnswerException, IOException, CqiServerError;
+	
+	public native String setOption(String name, String value) throws UnexpectedAnswerException, IOException, CqiServerError;
+	
 	public native String corpusFullName(String arg0) throws UnexpectedAnswerException, IOException, CqiServerError;
 	
 	public native String[] corpusInfo(String arg0) throws UnexpectedAnswerException, IOException, CqiServerError;
Index: TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/MemCqiClient.java
===================================================================
--- TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/MemCqiClient.java	(revision 3360)
+++ TXM/trunk/org.txm.searchengine.cqp.core/src/org/txm/searchengine/cqp/MemCqiClient.java	(revision 3361)
@@ -4,7 +4,6 @@
 
 import org.eclipse.osgi.util.NLS;
 import org.txm.core.messages.TXMCoreMessages;
-import org.txm.searchengine.core.messages.SearchEngineCoreMessages;
 import org.txm.searchengine.cqp.clientExceptions.UnexpectedAnswerException;
 import org.txm.searchengine.cqp.core.messages.CQPSearchEngineCoreMessages;
 import org.txm.searchengine.cqp.serverException.CqiClErrorCorpusAccess;
@@ -721,4 +720,31 @@
 		}
 		return server.load_a_system_corpus(regfilepath, entry);
 	}
+
+	@Override
+	public String getOption(String name) throws UnexpectedAnswerException, IOException, CqiServerError {
+		if (name == null) {
+			throw new CqiServerError("getOption called with NULL name parameter.");
+		}
+		String rez = server.getOption(name);
+		if (rez == null) {
+			throwExceptionFromCqi(server.getErrorCode());
+		}
+		return rez;
+	}
+
+	@Override
+	public String setOption(String name, String value) throws UnexpectedAnswerException, IOException, CqiServerError {
+		if (name == null) {
+			throw new CqiServerError("setOption called with NULL name parameter.");
+		}
+		if (value == null) {
+			throw new CqiServerError("setOption called with NULL value parameter.");
+		}
+		String rez = server.setOption(name, value);
+		if (rez == null) {
+			throwExceptionFromCqi(server.getErrorCode());
+		}
+		return rez;
+	}
 }
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/edit/CloneUnitPropertyMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/edit/CloneUnitPropertyMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/edit/CloneUnitPropertyMacro.groovy	(revision 3361)
@@ -0,0 +1,189 @@
+package org.txm.macro.urs.edit
+
+// Copyright © 2021 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author sheiden
+
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.*
+import org.txm.*
+import org.txm.rcpapplication.views.*
+import org.txm.macro.cqp.*
+import org.txm.annotation.urs.URSCorpora
+import org.txm.macro.urs.AnalecUtils
+import visuAnalec.elements.Unite
+
+
+// BEGINNING OF PARAMETERS
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	scriptName = this.class.getSimpleName()
+	println "** $scriptName: please select a corpus in the Corpus view or provide a corpus name (current selection is $corpusViewSelection). Aborting."
+	return false
+}
+// Declare each parameter here
+// (available widget types: Query, File, Folder, String, Text, Boolean, Integer, Float and Date)
+
+@Field @Option(name="unit_type", usage="Unit Type", widget="String", required=false, def="Biblical Reference")
+def unit_type
+
+@Field @Option(name="unit_ursql", usage="TYPE or TYPE@PROP or TYPE@PROP=<regex>", widget="String", required=false, def="Biblical Reference")
+def unit_ursql
+
+@Field @Option(name="propertyToClone", usage="name of the property to clone", widget="String", required=true, def="")
+def propertyToClone
+
+@Field @Option(name="newProperty", usage="name of the new property", widget="String", required=true, def="")
+def newProperty
+
+@Field @Option(name="debug", usage="Show debug information", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=false, def="OFF")
+def debug
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return false
+
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+// check availability of the corpus
+
+CQI = CQPSearchEngine.getCqiClient()
+
+scriptName = this.class.getSimpleName()
+
+corpus = corpusViewSelection
+corpusName = corpus.getName()
+
+// check availability of every information needed in the corpus
+
+if (!URSCorpora.isAnnotationStructureReady(corpus)) {
+	println "** URS Annotation Structure of "+corpusName+" is not ready. Aborting."
+	return false
+}
+
+analecCorpus = URSCorpora.getCorpus(corpus)
+
+if (analecCorpus == null) {
+	println "** no URS Annotations for "+corpusName+" corpus. Aborting."
+	return false
+}
+
+// select Units
+
+selectedUnits = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, null, null, null, unit_ursql, 0, null, false, 0)
+
+nUnits = selectedUnits.size()
+
+if (nUnits == 0) {
+	println "No units selected, no property cloned."
+	return
+}
+
+// check availability of every information needed in the corpus
+
+corpus_units = analecCorpus.getUnites(unit_type)
+
+if (corpus_units == null) {
+	println "** no URS Annotations '"+unit_type+"' corpus unit type in corpus "+corpusName+". Aborting."
+	return false
+}
+
+struct = analecCorpus.getStructure()
+
+if (struct == null) {
+	println "** no URS Annotations structure in corpus "+corpusName+". Aborting."
+	return false
+}
+
+struct_units = struct.getUnites()
+
+if (struct_units == null) {
+	println "** no URS Annotations structure units in corpus "+corpusName+". Aborting."
+	return false
+}
+
+if (debug > 0) {
+
+println "unit types: "+struct_units
+println unit_type+" properties: "+struct.getNomsProps(Unite.class, unit_type)
+
+}
+
+// check Unit type
+props = struct.getNomsProps(Unite.class, unit_type)
+
+// if necessary, add new property to unit type
+
+if ((props == null) || (!props.contains(newProperty))) {
+	struct.ajouterProp(Unite.class, unit_type, newProperty)
+}
+
+// verify that the property is added to unit_type unit type
+props = struct.getNomsProps(Unite.class, unit_type)
+
+if (props == null) {
+	println "** impossible to add new property '"+newProperty+"' to '"+unit_type+"' unit type in corpus "+corpusName+". Aborting."
+	return false
+}
+	
+if (!props.contains(newProperty)) {
+	println "** impossible to add new property '"+newProperty+"' to '"+unit_type+"' unit type in corpus "+corpusName+". Aborting."
+	return false
+}
+
+// check Vue
+vue = URSCorpora.getVue(corpus)
+
+if (vue == null) {
+	println "** no URS 'vue' for corpus "+corpusName+". Aborting."
+	return false
+}
+
+vue_units = vue.getTypesUnitesAVoir()
+
+if (vue_units == null) {
+	println "** no URS Annotations vue units in corpus "+corpusName+". Aborting."
+	return false
+}
+
+props = vue.getNomsChamps(Unite.class, unit_type)
+
+if (debug > 0) {
+	println "vue unit types: "+vue_units
+	println unit_type+" vue fields: "+props
+}
+
+// if necessary, add the new property to unit_type unit type in vue
+
+if ((props == null) || (!props.contains(newProperty))) {
+	vue.ajouterProp(Unite.class, unit_type, newProperty)
+}
+
+// verify that the property is added to unit_type unit type in vue
+props = vue.getNomsChamps(Unite.class, unit_type)
+
+if (props == null) {
+	println "** impossible to add properties to '"+unit_type+"' unit type in vue of corpus "+corpusName+". Aborting."
+	return false
+}
+
+if (!props.contains(newProperty)) {
+		println "** impossible to add property '"+newProperty+"' to '"+unit_type+"' unit type in vue of corpus "+corpusName+". Aborting."
+		return false
+}
+
+selectedUnits.each { unit ->
+	def val = unit.getProp(propertyToClone)
+   	vue.setValeurChamp(unit, newProperty, val)
+}
+
+println nUnits+" properties cloned (but not saved)."
+
+corpus.setIsModified(true)
+
+return true
+
Index: TXM/trunk/org.txm.edition.rcp/src/org/txm/edition/rcp/editors/SynopticEditionEditor.java
===================================================================
--- TXM/trunk/org.txm.edition.rcp/src/org/txm/edition/rcp/editors/SynopticEditionEditor.java	(revision 3360)
+++ TXM/trunk/org.txm.edition.rcp/src/org/txm/edition/rcp/editors/SynopticEditionEditor.java	(revision 3361)
@@ -824,7 +824,9 @@
 		// remove previous EditionPanel
 		if (reloadPanels) {
 			for (EditionPanel panel : editionPanels.values()) {
-				panel.dispose();
+				if (!panel.isDisposed()) {
+					panel.dispose();
+				}
 			}
 			editionPanels = new LinkedHashMap<>();
 			
@@ -890,6 +892,11 @@
 			this.addHighlightWordsById(BackToText.lightred, Arrays.asList(wordIdsArray));
 			this.setFocusedWordID(wordIds);
 		}
+		
+		String url = this.editionPanels.get(editionNames.get(0)).getURL();
+		if (url == null || url.equals("about:blank")) {
+			setText(text,  true);
+		}
 		return true;
 	}
 	
Index: TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/ApplicationWorkbenchAdvisor.java
===================================================================
--- TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/ApplicationWorkbenchAdvisor.java	(revision 3360)
+++ TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/ApplicationWorkbenchAdvisor.java	(revision 3361)
@@ -622,21 +622,6 @@
 				
 				installPreferenceRestored = false; // reset and finally set true if the process ended correctly
 				
-				try {
-					Display.getDefault().syncExec(new Runnable() {
-						
-						@Override
-						public void run() {
-							OpenWelcomePage.openWelcomePage();
-						}
-					});
-				}
-				catch (Exception e2) {
-					try {
-						OpenWelcomePage.openWelcomePage();
-					} catch (Exception e3) { }
-				}
-				
 				// set the install directory preference
 				String installpath = Platform.getInstallLocation().getURL().getFile(); // the TXM.exe file path
 				File installDirectory = new File(installpath);
@@ -1020,6 +1005,32 @@
 			}
 		});
 		
+		try {
+			Display.getDefault().syncExec(new Runnable() {
+				
+				@Override
+				public void run() {
+					OpenWelcomePage.openWelcomePage();
+				}
+			});
+		}
+		catch (Exception e2) {
+			try {
+				Display.getCurrent().syncExec(new Runnable() {
+					
+					@Override
+					public void run() {
+						OpenWelcomePage.openWelcomePage();
+					}
+				});
+			}
+			catch (Exception e3) {
+				try {
+					OpenWelcomePage.openWelcomePage();
+				} catch (Exception e4) { }
+			}
+		}
+		
 		monitor.setTaskName(""); //$NON-NLS-1$
 	}
 	
Index: TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/swt/dialog/ComputeProgressMonitorDialog.java
===================================================================
--- TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/swt/dialog/ComputeProgressMonitorDialog.java	(revision 3360)
+++ TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/swt/dialog/ComputeProgressMonitorDialog.java	(revision 3361)
@@ -101,7 +101,6 @@
 		this.run(cancelable, runnable);
 	}
 	
-	
 	/**
 	 * Runs the given <code>IRunnableWithProgress</code>.
 	 * 
@@ -114,7 +113,6 @@
 		this.run(true, cancelable, runnable);
 	}
 	
-	
 	@Override
 	public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException {
 		
