View Javadoc
1   /**
2    * 
3    * Copyright (c) 2014-2015, Openflexo
4    * 
5    * This file is part of Flexodiagram, a component of the software infrastructure 
6    * developed at Openflexo.
7    * 
8    * 
9    * Openflexo is dual-licensed under the European Union Public License (EUPL, either 
10   * version 1.1 of the License, or any later version ), which is available at 
11   * https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
12   * and the GNU General Public License (GPL, either version 3 of the License, or any 
13   * later version), which is available at http://www.gnu.org/licenses/gpl.html .
14   * 
15   * You can redistribute it and/or modify under the terms of either of these licenses
16   * 
17   * If you choose to redistribute it and/or modify under the terms of the GNU GPL, you
18   * must include the following additional permission.
19   *
20   *          Additional permission under GNU GPL version 3 section 7
21   *
22   *          If you modify this Program, or any covered work, by linking or 
23   *          combining it with software containing parts covered by the terms 
24   *          of EPL 1.0, the licensors of this Program grant you additional permission
25   *          to convey the resulting work. * 
26   * 
27   * This software is distributed in the hope that it will be useful, but WITHOUT ANY 
28   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
29   * PARTICULAR PURPOSE. 
30   *
31   * See http://www.openflexo.org/license.html for details.
32   * 
33   * 
34   * Please contact Openflexo (openflexo-contacts@openflexo.org)
35   * or visit www.openflexo.org if you need additional information.
36   * 
37   */
38  
39  package org.openflexo.foundation.doc.fml;
40  
41  import java.util.ArrayList;
42  import java.util.List;
43  import java.util.StringTokenizer;
44  import java.util.logging.Logger;
45  
46  import org.openflexo.connie.BindingFactory;
47  import org.openflexo.connie.BindingModel;
48  import org.openflexo.connie.DataBinding;
49  import org.openflexo.connie.DataBinding.BindingDefinitionType;
50  import org.openflexo.connie.exception.NotSettableContextException;
51  import org.openflexo.connie.exception.NullReferenceException;
52  import org.openflexo.connie.exception.TypeMismatchException;
53  import org.openflexo.foundation.doc.FlexoDocElement;
54  import org.openflexo.foundation.doc.FlexoDocElementContainer;
55  import org.openflexo.foundation.doc.FlexoDocParagraph;
56  import org.openflexo.foundation.doc.FlexoDocRun;
57  import org.openflexo.foundation.doc.FlexoDocument;
58  import org.openflexo.foundation.doc.FlexoTextRun;
59  import org.openflexo.foundation.doc.TextSelection;
60  import org.openflexo.foundation.doc.fml.FragmentActorReference.ElementReference;
61  import org.openflexo.foundation.fml.FlexoConcept;
62  import org.openflexo.foundation.fml.rt.FlexoConceptInstance;
63  import org.openflexo.foundation.technologyadapter.ModelSlot;
64  import org.openflexo.foundation.technologyadapter.ModelSlotObject;
65  import org.openflexo.foundation.technologyadapter.TechnologyAdapter;
66  import org.openflexo.pamela.annotations.DefineValidationRule;
67  import org.openflexo.pamela.annotations.Getter;
68  import org.openflexo.pamela.annotations.ImplementationClass;
69  import org.openflexo.pamela.annotations.ModelEntity;
70  import org.openflexo.pamela.annotations.PropertyIdentifier;
71  import org.openflexo.pamela.annotations.Setter;
72  import org.openflexo.pamela.annotations.XMLAttribute;
73  import org.openflexo.pamela.annotations.XMLElement;
74  import org.openflexo.toolbox.StringUtils;
75  
76  /**
77   * This class represent a text binding declared in a document fragment.<br>
78   * A {@link TextSelection} is an expression that is to be replaced as text of a run in a document fragment.<br>
79   * More exactely we maintain here a bi-directional synchronization between text and data if the binding is declared as settable <br>
80   * A {@link TextBinding} might be declared as multiline. In this case, {@link TextSelection} applies on multiple paragraphs.
81   * 
82   * 
83   * @author sylvain
84   * 
85   */
86  @ModelEntity
87  @ImplementationClass(TextBinding.TextBindingImpl.class)
88  @XMLElement
89  public interface TextBinding<D extends FlexoDocument<D, TA>, TA extends TechnologyAdapter<TA>> extends ModelSlotObject<D> {
90  
91  	@PropertyIdentifier(type = TextSelection.class)
92  	public static final String TEXT_SELECTION_KEY = "textSelection";
93  
94  	@PropertyIdentifier(type = DataBinding.class)
95  	public static final String VALUE_KEY = "value";
96  
97  	@PropertyIdentifier(type = FlexoFragmentRole.class)
98  	public static final String FRAGMENT_ROLE_KEY = "fragmentRole";
99  
100 	@PropertyIdentifier(type = Boolean.class)
101 	public static final String IS_MULTILINE_KEY = "isMultiline";
102 
103 	@Getter(TEXT_SELECTION_KEY)
104 	@XMLElement
105 	public TextSelection<D, TA> getTextSelection();
106 
107 	@Setter(TEXT_SELECTION_KEY)
108 	public void setTextSelection(TextSelection<D, TA> textSelection);
109 
110 	@Getter(VALUE_KEY)
111 	@XMLAttribute
112 	public DataBinding<String> getValue();
113 
114 	@Setter(VALUE_KEY)
115 	public void setValue(DataBinding<String> value);
116 
117 	@Getter(FRAGMENT_ROLE_KEY)
118 	public FlexoFragmentRole<?, D, TA> getFragmentRole();
119 
120 	@Setter(FRAGMENT_ROLE_KEY)
121 	public void setFragmentRole(FlexoFragmentRole<?, D, TA> fragmentRole);
122 
123 	@Getter(value = IS_MULTILINE_KEY, defaultValue = "false")
124 	@XMLAttribute
125 	public boolean isMultiline();
126 
127 	@Setter(IS_MULTILINE_KEY)
128 	public void setMultiline(boolean multiline);
129 
130 	/**
131 	 * This method is called to extract a value from the federated data and apply it to the represented fragment representation
132 	 * 
133 	 * @param gr
134 	 * @param element
135 	 */
136 	public void applyToFragment(FlexoConceptInstance fci);
137 
138 	/**
139 	 * This method is called to extract a value from the fragment, and apply it to underlying federated data
140 	 * 
141 	 * @param gr
142 	 * @param element
143 	 * @return
144 	 */
145 	public String extractFromFragment(FlexoConceptInstance fci);
146 
147 	public static abstract class TextBindingImpl<D extends FlexoDocument<D, TA>, TA extends TechnologyAdapter<TA>>
148 			extends FlexoConceptObjectImpl implements TextBinding<D, TA> {
149 
150 		@SuppressWarnings("unused")
151 		private static final Logger logger = Logger.getLogger(TextBinding.class.getPackage().getName());
152 
153 		private DataBinding<String> value;
154 
155 		// Use it only for deserialization
156 		public TextBindingImpl() {
157 			super();
158 		}
159 
160 		@Override
161 		public ModelSlot<D> getModelSlot() {
162 			if (getFragmentRole() != null) {
163 				return (ModelSlot<D>) getFragmentRole().getModelSlot();
164 			}
165 			return null;
166 		}
167 
168 		@Override
169 		public TechnologyAdapter getModelSlotTechnologyAdapter() {
170 			if (getModelSlot() != null) {
171 				return getModelSlot().getModelSlotTechnologyAdapter();
172 			}
173 			return null;
174 		}
175 
176 		/*
177 		@Override
178 		public VirtualModel getVirtualModel() {
179 			if (getFragmentRole() != null) {
180 				return getFragmentRole().getFlexoConcept().getOwner();
181 			}
182 			return null;
183 		}
184 		*/
185 
186 		@Override
187 		public TextSelection<D, TA> getTextSelection() {
188 			TextSelection<D, TA> returned = (TextSelection<D, TA>) performSuperGetter(TEXT_SELECTION_KEY);
189 			if (returned != null && returned.getFragment() == null && getFragmentRole() != null) {
190 				returned.setFragment(getFragmentRole().getFragment());
191 			}
192 			return returned;
193 		}
194 
195 		public int getIndex() {
196 			if (getFragmentRole() != null) {
197 				return getFragmentRole().getTextBindings().indexOf(this);
198 			}
199 			return -1;
200 		}
201 
202 		@Override
203 		public DataBinding<String> getValue() {
204 			if (value == null) {
205 				value = new DataBinding<>(this, String.class, DataBinding.BindingDefinitionType.GET);
206 				value.setBindingName("TextSelection" + getIndex());
207 				value.setMandatory(true);
208 			}
209 			return value;
210 		}
211 
212 		@Override
213 		public void setValue(DataBinding<String> value) {
214 			if (value != null) {
215 				value.setOwner(this);
216 				value.setDeclaredType(String.class);
217 				value.setBindingName("TextSelection" + getIndex());
218 				value.setMandatory(true);
219 				value.setBindingDefinitionType(BindingDefinitionType.GET);
220 			}
221 			this.value = value;
222 			notifiedBindingChanged(getValue());
223 		}
224 
225 		@Override
226 		public FlexoConcept getFlexoConcept() {
227 			return getFragmentRole() != null ? getFragmentRole().getFlexoConcept() : null;
228 		}
229 
230 		@Override
231 		public BindingFactory getBindingFactory() {
232 			return getFlexoConcept().getInspector().getBindingFactory();
233 		}
234 
235 		@Override
236 		public BindingModel getBindingModel() {
237 			if (getFlexoConcept() != null && getFlexoConcept().getInspector() != null) {
238 				return getFlexoConcept().getInspector().getBindingModel();
239 			}
240 			return null;
241 		}
242 
243 		/**
244 		 * This method is called to extract a value from the data and apply it to the represented fragment representation
245 		 * 
246 		 * @param gr
247 		 * @param element
248 		 */
249 		@Override
250 		public void applyToFragment(FlexoConceptInstance fci) {
251 
252 			// System.out.println("Applying text binding " + getName() + " with selection " + getTextSelection() + " and value " +
253 			// getValue());
254 
255 			try {
256 				FragmentActorReference<?> actorReference = (FragmentActorReference<?>) fci.getActorReference(getFragmentRole());
257 				// FlexoDocFragment<?, ?> templateFragment = getFragmentRole().getFragment();
258 				// FlexoDocFragment<?, ?> fragment = actorReference.getModellingElement();
259 
260 				String value = getValue().getBindingValue(fci);
261 
262 				if (value == null) {
263 					// In this case, we purely escape: original text will be kept
264 					return;
265 				}
266 
267 				if (isMultiline()) {
268 					List<String> newStructure = new ArrayList<>();
269 					StringTokenizer st = new StringTokenizer(value, StringUtils.LINE_SEPARATOR);
270 					while (st.hasMoreTokens()) {
271 						newStructure.add(st.nextToken());
272 					}
273 					performTextReplacementInMultilineContext(newStructure, actorReference);
274 				}
275 
276 				else {
277 
278 					TextSelection<D, TA> txtSelection = getTextSelection();
279 					if (txtSelection.isSingleParagraph()) {
280 
281 						FlexoDocRun<?, ?> templateStartRun = txtSelection.getStartRun();
282 						FlexoDocRun<?, ?> templateEndRun = txtSelection.getEndRun();
283 						if (templateStartRun == templateEndRun) {
284 							logger.warning("debut et fin sont identiques?");
285 						}
286 						List<String> newStructure = new ArrayList<>();
287 						if (txtSelection.getStartCharacterIndex() > -1) {
288 							if (templateStartRun instanceof FlexoTextRun) {
289 								newStructure.add(((FlexoTextRun<?, ?>) templateStartRun).getText().substring(0,
290 										txtSelection.getStartCharacterIndex()));
291 							}
292 							newStructure.add(value);
293 							if (txtSelection.getEndCharacterIndex() > -1) {
294 								if (templateEndRun instanceof FlexoTextRun) {
295 									newStructure.add(
296 											((FlexoTextRun<?, ?>) templateEndRun).getText().substring(txtSelection.getEndCharacterIndex()));
297 								}
298 							}
299 						}
300 						else {
301 							newStructure.add(value);
302 							if (txtSelection.getEndCharacterIndex() > -1) {
303 								if (templateEndRun instanceof FlexoTextRun) {
304 									newStructure.add(
305 											((FlexoTextRun<?, ?>) templateEndRun).getText().substring(txtSelection.getEndCharacterIndex()));
306 								}
307 							}
308 						}
309 
310 						performTextReplacementInSingleParagraphContext(newStructure, actorReference);
311 					}
312 
313 					else {
314 						logger.warning(
315 								"Inconsistent data: TextBinding with non-single-paragraph TextSelection must be declared as multiline");
316 					}
317 				}
318 				// run.setText(value);
319 
320 			} catch (TypeMismatchException e) {
321 				e.printStackTrace();
322 			} catch (NullReferenceException e) {
323 				e.printStackTrace();
324 			} catch (ReflectiveOperationException e) {
325 				e.printStackTrace();
326 			}
327 		}
328 
329 		/**
330 		 * Internally used to perform text replacement in single paragraph context (when TextSelection apply on a single paraggraph)
331 		 * 
332 		 * @param newStructure
333 		 * @param actorReference
334 		 */
335 		private void performTextReplacementInSingleParagraphContext(List<String> newStructure, FragmentActorReference<?> actorReference) {
336 
337 			FlexoDocRun<D, TA> templateStartRun = getTextSelection().getStartRun();
338 			FlexoDocRun<D, TA> templateEndRun = getTextSelection().getEndRun();
339 
340 			FlexoDocParagraph<D, TA> templateParagraph = (FlexoDocParagraph<D, TA>) getTextSelection().getStartElement();
341 
342 			List<FlexoDocElement<?, ?>> matchingElements = actorReference
343 					.getElementsMatchingTemplateElement(getTextSelection().getStartElement());
344 
345 			if (matchingElements.size() > 0) {
346 
347 				FlexoDocElement<?, ?> targetDocumentElement = actorReference
348 						.getElementsMatchingTemplateElement(getTextSelection().getStartElement()).get(0);
349 				if (targetDocumentElement instanceof FlexoDocParagraph) {
350 					FlexoDocParagraph<D, TA> targetParagraph = (FlexoDocParagraph<D, TA>) targetDocumentElement;
351 
352 					// We compute start target run relatively to the beginning of actual target paragraph, because
353 					// we cannot rely on structure that may have changed because of concurrent modifications
354 					FlexoDocRun<D, TA> startTargetRun = null;
355 					if (templateStartRun.getIndex() < targetParagraph.getRuns().size()) {
356 						startTargetRun = targetParagraph.getRuns().get(templateStartRun.getIndex());
357 					}
358 					else {
359 						startTargetRun = targetParagraph.getRuns().get(targetParagraph.getRuns().size() - 1);
360 					}
361 
362 					// We compute end target run relatively to the end of actual target paragraph, because
363 					// we cannot rely on structure that may have changed because of concurrent modifications
364 					FlexoDocRun<D, TA> endTargetRun = null;
365 					if (targetParagraph.getRuns().size() - templateParagraph.getRuns().size() + templateEndRun.getIndex() < targetParagraph
366 							.getRuns().size()) {
367 						endTargetRun = targetParagraph.getRuns()
368 								.get(targetParagraph.getRuns().size() - templateParagraph.getRuns().size() + templateEndRun.getIndex());
369 					}
370 					else {
371 						endTargetRun = targetParagraph.getRuns().get(targetParagraph.getRuns().size() - 1);
372 					}
373 
374 					int targetRunsNb = endTargetRun.getIndex() - startTargetRun.getIndex() + 1;
375 
376 					// We compare cardinality of the two structures to synchronize
377 
378 					if (targetRunsNb < newStructure.size()) {
379 						// We have to add extra runs, at the end of actual structure
380 						int currentIndex = endTargetRun.getIndex() + 1;
381 						for (int i = 0; i < newStructure.size() - targetRunsNb; i++) {
382 							FlexoDocRun<D, TA> clonedRun = (FlexoDocRun<D, TA>) startTargetRun.cloneObject();
383 							targetParagraph.insertRunAtIndex(clonedRun, currentIndex);
384 							currentIndex++;
385 							endTargetRun = clonedRun;
386 						}
387 					}
388 
389 					else if (targetRunsNb > newStructure.size()) {
390 						// We have to remove extra runs
391 						// We remove runs from the end of actual structure
392 						int lastRunIndex = endTargetRun.getIndex();
393 						endTargetRun = targetParagraph.getRuns().get(lastRunIndex - targetRunsNb + newStructure.size());
394 						for (int i = 0; i < targetRunsNb - newStructure.size(); i++) {
395 							FlexoDocRun<D, TA> runToRemove = targetParagraph.getRuns().get(lastRunIndex - i);
396 							targetParagraph.removeFromRuns(runToRemove);
397 						}
398 					}
399 
400 					targetRunsNb = endTargetRun.getIndex() - startTargetRun.getIndex() + 1;
401 
402 					if (targetRunsNb != newStructure.size()) {
403 						logger.warning("Something was wrong when performing text replacement");
404 					}
405 
406 					// Now the structures are same: targetRunNb == newStructure.size()
407 					for (int i = 0; i < newStructure.size(); i++) {
408 						FlexoDocRun<?, ?> run = targetParagraph.getRuns().get(i + startTargetRun.getIndex());
409 						String v = newStructure.get(i);
410 						if (run instanceof FlexoTextRun) {
411 							((FlexoTextRun<?, ?>) run).setText(v);
412 						}
413 					}
414 
415 				}
416 				else {
417 					logger.warning("Text replacement not implemented for " + targetDocumentElement);
418 				}
419 			}
420 			else {
421 				logger.warning("Could not find element in target document matching " + getTextSelection().getStartElement());
422 			}
423 		}
424 
425 		/**
426 		 * Internally used to perform text replacement in multiline paragraph context (when TextSelection apply on a multiple consecutive
427 		 * paragraphs)
428 		 * 
429 		 * @param newStructure
430 		 * @param actorReference
431 		 */
432 		private void performTextReplacementInMultilineContext(List<String> newStructure, FragmentActorReference<?> actorReference) {
433 
434 			FlexoDocument<D, TA> document = (FlexoDocument<D, TA>) actorReference.getModellingElement().getFlexoDocument();
435 
436 			int startIndex = -1;
437 			int endIndex = -1;
438 
439 			// This is the container of elements located in generated fragment (not template fragment)
440 			FlexoDocElementContainer<D, TA> container = null;
441 
442 			System.out.println("start=" + getTextSelection().getStartElement());
443 			System.out.println("end=" + getTextSelection().getEndElement());
444 
445 			if (getTextSelection().getStartElement() == null || getTextSelection().getEndElement() == null) {
446 				logger.warning("Unexpected start and/or end element found/ Aborting text replacement");
447 				return;
448 			}
449 
450 			for (FlexoDocElement e : actorReference.getElementsMatchingTemplateElement(getTextSelection().getStartElement())) {
451 				if (container == null) {
452 					container = e.getContainer();
453 				}
454 				int index = e.getIndex();
455 				System.out.println("pour start on trouve " + index);
456 				if ((index > -1) && ((startIndex == -1) || (index < startIndex))) {
457 					startIndex = index;
458 				}
459 			}
460 			for (FlexoDocElement e : actorReference.getElementsMatchingTemplateElement(getTextSelection().getEndElement())) {
461 				if (container == null) {
462 					container = e.getContainer();
463 				}
464 				int index = e.getIndex();
465 				System.out.println("pour end on trouve " + index);
466 				if ((index > -1) && ((endIndex == -1) || (index > endIndex))) {
467 					endIndex = index;
468 				}
469 			}
470 
471 			// Maybe the end element could not be found, in this case, we will consider a unique paragraph
472 			if (endIndex == -1) {
473 				endIndex = startIndex;
474 			}
475 
476 			System.out.println("container=" + container);
477 			System.out.println("elements: " + container.getElements().size() + " = " + container.getElements());
478 			System.out.println("startIndex=" + startIndex);
479 			System.out.println("endIndex=" + endIndex);
480 			for (String l : newStructure) {
481 				System.out.println("> " + l);
482 			}
483 
484 			FlexoDocParagraph<D, TA> startParagraph = (FlexoDocParagraph<D, TA>) container.getElements().get(startIndex);
485 			FlexoDocParagraph<D, TA> endParagraph = (FlexoDocParagraph<D, TA>) container.getElements().get(endIndex);
486 
487 			int targetParagraphsNb = endIndex - startIndex + 1;
488 
489 			// We compare cardinality of the two structures to synchronize
490 
491 			if (targetParagraphsNb < newStructure.size()) {
492 				// We have to add extra paragraphs, at the end of actual structure
493 				int currentIndex = endIndex + 1;
494 				for (int i = 0; i < newStructure.size() - targetParagraphsNb; i++) {
495 					// System.out.println("Adding paragraph");
496 					FlexoDocParagraph<D, TA> clonedParagraph = (FlexoDocParagraph<D, TA>) startParagraph.cloneObject();
497 					clonedParagraph.setBaseIdentifier(getTextSelection().getEndElement().getIdentifier());
498 					document.insertElementAtIndex(clonedParagraph, currentIndex++);
499 					ElementReference er = actorReference.getFactory().newInstance(ElementReference.class);
500 					er.setTemplateElementId(clonedParagraph.getBaseIdentifier());
501 					er.setElementId(clonedParagraph.getIdentifier());
502 					actorReference.addToElementReferences(er);
503 					endParagraph = clonedParagraph;
504 					// endIndex = document.getElements().indexOf(endParagraph);
505 					endIndex = endParagraph.getIndex();
506 				}
507 			}
508 
509 			else if (targetParagraphsNb > newStructure.size()) {
510 				// We have to remove extra paragraphs
511 				// We remove runs from the end of actual structure
512 				int lastParagraphIndex = endIndex;
513 				endParagraph = (FlexoDocParagraph<D, TA>) document.getElements()
514 						.get(lastParagraphIndex - targetParagraphsNb + newStructure.size());
515 				endIndex = endParagraph.getIndex();
516 				for (int i = 0; i < targetParagraphsNb - newStructure.size(); i++) {
517 					// System.out.println("Removing paragraph");
518 					FlexoDocParagraph<D, TA> paragraphToRemove = (FlexoDocParagraph<D, TA>) container.getElements()
519 							.get(lastParagraphIndex - i);
520 					// Removed references BEFORE to remove from elements
521 					// (otherwise, identifier could not be computed anymore)
522 					actorReference.removeReferencesTo(paragraphToRemove);
523 					document.removeFromElements(paragraphToRemove);
524 				}
525 			}
526 
527 			for (int i = 0; i < endIndex - startIndex + 1; i++) {
528 				FlexoDocParagraph<D, TA> paragraph = (FlexoDocParagraph<D, TA>) container.getElements().get(i + startIndex);
529 				if (paragraph.getRuns().size() > 1) {
530 					// We have to remove extra runs
531 					// We remove runs from the end of actual structure
532 					int runsToRemove = paragraph.getRuns().size() - 1;
533 					for (int j = 0; j < runsToRemove; j++) {
534 						FlexoDocRun<D, TA> runToRemove = paragraph.getRuns().get(paragraph.getRuns().size() - 1);
535 						paragraph.removeFromRuns(runToRemove);
536 					}
537 				}
538 				else if (paragraph.getRuns().size() == 0) {
539 					// We have to add default run
540 					FlexoDocRun<D, TA> newRun = document.getFactory().makeTextRun("");
541 					paragraph.addToRuns(newRun);
542 				}
543 
544 				if (paragraph.getRuns().get(0) instanceof FlexoTextRun) {
545 					((FlexoTextRun<?, ?>) paragraph.getRuns().get(0)).setText(newStructure.get(i));
546 				}
547 
548 			}
549 
550 		}
551 
552 		/**
553 		 * This method is called to extract a value from the graphical representation and conform to the related feature, and apply it to
554 		 * model
555 		 * 
556 		 * @param gr
557 		 * @param element
558 		 * @return
559 		 */
560 		@Override
561 		public String extractFromFragment(FlexoConceptInstance fci) {
562 			if (getValue().isSettable()) {
563 
564 				FragmentActorReference<?> actorReference = (FragmentActorReference<?>) fci.getActorReference(getFragmentRole());
565 				// FlexoDocFragment<?, ?> fragment = fci.getFlexoActor(getFragmentRole());
566 
567 				String value = null;
568 
569 				if (isMultiline()) {
570 					value = extractTextInMultilineContext(actorReference);
571 				}
572 
573 				else if (getTextSelection().isSingleParagraph()) {
574 					value = extractTextInSingleParagraphContext(actorReference);
575 
576 				}
577 
578 				else {
579 					logger.warning("Inconsistent data: TextBinding with non-single-paragraph TextSelection must be declared as multiline");
580 					return null;
581 				}
582 
583 				// System.out.println("Sets binding " + getValue() + " with " + value);
584 
585 				try {
586 					getValue().setBindingValue(value, fci);
587 				} catch (TypeMismatchException e) {
588 					e.printStackTrace();
589 				} catch (NullReferenceException e) {
590 					e.printStackTrace();
591 				} catch (ReflectiveOperationException e) {
592 					e.printStackTrace();
593 				} catch (NotSettableContextException e) {
594 					e.printStackTrace();
595 				}
596 
597 			}
598 			return null;
599 		}
600 
601 		/**
602 		 * Internally used to extract text in single paragraph context (when TextSelection apply on a single paraggraph)
603 		 * 
604 		 * @param actorReference
605 		 */
606 		private String extractTextInSingleParagraphContext(FragmentActorReference<?> actorReference) {
607 
608 			FlexoDocRun<D, TA> templateStartRun = getTextSelection().getStartRun();
609 			FlexoDocRun<D, TA> templateEndRun = getTextSelection().getEndRun();
610 			FlexoDocParagraph<D, TA> templateParagraph = (FlexoDocParagraph<D, TA>) getTextSelection().getStartElement();
611 
612 			if (actorReference.getElementsMatchingTemplateElement(getTextSelection().getStartElement()).size() > 0) {
613 
614 				FlexoDocElement<?, ?> targetDocumentElement = actorReference
615 						.getElementsMatchingTemplateElement(getTextSelection().getStartElement()).get(0);
616 				if (targetDocumentElement instanceof FlexoDocParagraph) {
617 					FlexoDocParagraph<D, TA> targetParagraph = (FlexoDocParagraph<D, TA>) targetDocumentElement;
618 
619 					// We compute start target run relatively to the beginning of actual target paragraph, because
620 					// we cannot rely on structure that may have changed because of concurrent modifications
621 					FlexoDocRun<D, TA> startTargetRun = null;
622 					if (templateStartRun.getIndex() < targetParagraph.getRuns().size()) {
623 						startTargetRun = targetParagraph.getRuns().get(templateStartRun.getIndex());
624 					}
625 					else {
626 						startTargetRun = targetParagraph.getRuns().get(targetParagraph.getRuns().size() - 1);
627 					}
628 
629 					// We compute end target run relatively to the end of actual target paragraph, because
630 					// we cannot rely on structure that may have changed because of concurrent modifications
631 					FlexoDocRun<D, TA> endTargetRun = null;
632 					if (targetParagraph.getRuns().size() - templateParagraph.getRuns().size() + templateEndRun.getIndex() < targetParagraph
633 							.getRuns().size()) {
634 						endTargetRun = targetParagraph.getRuns()
635 								.get(targetParagraph.getRuns().size() - templateParagraph.getRuns().size() + templateEndRun.getIndex());
636 					}
637 					else {
638 						endTargetRun = targetParagraph.getRuns().get(targetParagraph.getRuns().size() - 1);
639 					}
640 
641 					StringBuffer sb = new StringBuffer();
642 
643 					boolean extraStartRun = (getTextSelection().getStartCharacterIndex() > -1);
644 					boolean extraEndRun = (getTextSelection().getEndCharacterIndex() > -1);
645 
646 					for (int i = startTargetRun.getIndex() + (extraStartRun ? 1 : 0); i <= endTargetRun.getIndex()
647 							- (extraEndRun ? 1 : 0); i++) {
648 						if (targetParagraph.getRuns().get(i) instanceof FlexoTextRun) {
649 							sb.append(((FlexoTextRun<?, ?>) targetParagraph.getRuns().get(i)).getText());
650 						}
651 					}
652 
653 					return sb.toString();
654 				}
655 				else {
656 					logger.warning("Text extraction not implemented for " + targetDocumentElement);
657 				}
658 			}
659 			else {
660 				logger.warning("Could not find element in target document matching " + getTextSelection().getStartElement());
661 			}
662 
663 			return null;
664 		}
665 
666 		/**
667 		 * Internally used to extract text in multiline context (when TextSelection apply on a multiple consecutive paragraphs)
668 		 * 
669 		 * @param actorReference
670 		 */
671 		private String extractTextInMultilineContext(FragmentActorReference<?> actorReference) {
672 			FlexoDocument<D, TA> document = (FlexoDocument<D, TA>) actorReference.getModellingElement().getFlexoDocument();
673 
674 			int startIndex = -1;
675 			int endIndex = -1;
676 
677 			// This is the container of elements located in generated fragment (not template fragment)
678 			FlexoDocElementContainer<D, TA> container = null;
679 
680 			for (FlexoDocElement e : actorReference.getElementsMatchingTemplateElement(getTextSelection().getStartElement())) {
681 				if (container == null) {
682 					container = e.getContainer();
683 				}
684 				int index = document.getElements().indexOf(e);
685 				if ((index > -1) && ((startIndex == -1) || (index < startIndex))) {
686 					startIndex = index;
687 				}
688 			}
689 			for (FlexoDocElement e : actorReference.getElementsMatchingTemplateElement(getTextSelection().getEndElement())) {
690 				if (container == null) {
691 					container = e.getContainer();
692 				}
693 				int index = document.getElements().indexOf(e);
694 				if ((index > -1) && ((endIndex == -1) || (index > endIndex))) {
695 					endIndex = index;
696 				}
697 			}
698 
699 			// Now, we look for the paragraphs that come just after
700 			// If they are not bound to a template paragraph, we include them as part of FragmentActorReference
701 			FlexoDocElement<D, TA> nextElement = null;
702 			if (endIndex < container.getElements().size() - 1) {
703 				nextElement = container.getElements().get(endIndex + 1);
704 			}
705 			while (nextElement != null && StringUtils.isEmpty(nextElement.getBaseIdentifier())) {
706 				// Taking under account nextElement
707 				nextElement.setBaseIdentifier(getTextSelection().getEndElement().getIdentifier());
708 				ElementReference er = actorReference.getFactory().newInstance(ElementReference.class);
709 				er.setTemplateElementId(nextElement.getBaseIdentifier());
710 				er.setElementId(nextElement.getIdentifier());
711 				actorReference.addToElementReferences(er);
712 				endIndex++;
713 				if (endIndex < container.getElements().size() - 1) {
714 					nextElement = container.getElements().get(endIndex + 1);
715 				}
716 				else {
717 					nextElement = null;
718 				}
719 			}
720 
721 			StringBuffer sb = new StringBuffer();
722 			boolean isFirst = true;
723 			for (int i = 0; i < endIndex - startIndex + 1; i++) {
724 				FlexoDocParagraph<D, TA> paragraph = (FlexoDocParagraph<D, TA>) container.getElements().get(i + startIndex);
725 				sb.append((isFirst ? "" : StringUtils.LINE_SEPARATOR) + paragraph.getRawText());
726 				isFirst = false;
727 			}
728 
729 			return sb.toString();
730 		}
731 
732 	}
733 
734 	@DefineValidationRule
735 	public static class AssignationBindingIsRequiredAndMustBeValid extends BindingIsRequiredAndMustBeValid<TextBinding> {
736 		public AssignationBindingIsRequiredAndMustBeValid() {
737 			super("'value'_binding_is_required_and_must_be_valid", TextBinding.class);
738 		}
739 
740 		@Override
741 		public DataBinding<Object> getBinding(TextBinding object) {
742 			return object.getValue();
743 		}
744 
745 	}
746 
747 }