View Javadoc
1   /*
2    * (c) Copyright 2013 Openflexo
3    *
4    * This file is part of OpenFlexo.
5    *
6    * OpenFlexo is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * OpenFlexo is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
18   *
19   */
20  
21  package org.openflexo.foundation.doc;
22  
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.StringTokenizer;
26  import java.util.logging.Logger;
27  
28  import org.openflexo.foundation.FlexoException;
29  import org.openflexo.foundation.technologyadapter.TechnologyAdapter;
30  import org.openflexo.pamela.annotations.Getter;
31  import org.openflexo.pamela.annotations.ImplementationClass;
32  import org.openflexo.pamela.annotations.Import;
33  import org.openflexo.pamela.annotations.Imports;
34  import org.openflexo.pamela.annotations.ModelEntity;
35  import org.openflexo.pamela.annotations.PropertyIdentifier;
36  import org.openflexo.pamela.annotations.Setter;
37  import org.openflexo.toolbox.StringUtils;
38  
39  /**
40   * Represents a consecutive sequence of {@link FlexoDocElement} in a {@link FlexoDocument}
41   * 
42   * @author sylvain
43   *
44   * @param <D>
45   *            type of {@link FlexoDocument} involving this concept
46   * @param <TA>
47   *            {@link TechnologyAdapter} of current implementation
48   */
49  @ModelEntity(isAbstract = true)
50  @ImplementationClass(FlexoDocFragment.FlexoDocumentFragmentImpl.class)
51  @Imports({ @Import(TextSelection.class) })
52  public interface FlexoDocFragment<D extends FlexoDocument<D, TA>, TA extends TechnologyAdapter<TA>> extends FlexoDocObject<D, TA> {
53  
54  	@PropertyIdentifier(type = String.class)
55  	public static final String START_ELEMENT_KEY = "startElement";
56  
57  	@PropertyIdentifier(type = String.class)
58  	public static final String END_ELEMENT_KEY = "endElement";
59  
60  	/**
61  	 * Return start element in related {@link FlexoDocument}<br>
62  	 * 
63  	 * @return
64  	 */
65  	@Getter(START_ELEMENT_KEY)
66  	public FlexoDocElement<D, TA> getStartElement();
67  
68  	@Setter(START_ELEMENT_KEY)
69  	public void setStartElement(FlexoDocElement<D, TA> startElement);
70  
71  	/**
72  	 * Return start element in related {@link FlexoDocument}<br>
73  	 * 
74  	 * @return
75  	 */
76  	@Getter(END_ELEMENT_KEY)
77  	public FlexoDocElement<D, TA> getEndElement();
78  
79  	@Setter(END_ELEMENT_KEY)
80  	public void setEndElement(FlexoDocElement<D, TA> endElement);
81  
82  	/**
83  	 * Return the run as identified by runIdentifier, under the form: paraIndex.runIndex
84  	 * 
85  	 * @param runIdentifier
86  	 * @return
87  	 */
88  	public FlexoDocRun<?, ?> getRun(String runIdentifier);
89  
90  	public void checkConsistency() throws FragmentConsistencyException;
91  
92  	public class FragmentConsistencyException extends FlexoException {
93  		public FragmentConsistencyException(String message) {
94  			super(message);
95  		}
96  	}
97  
98  	/**
99  	 * Return all elements this fragment is composed of
100 	 * 
101 	 * @return
102 	 */
103 	public List<? extends FlexoDocElement<D, TA>> getElements();
104 
105 	public String getStringRepresentationPreview();
106 
107 	public String getStringRepresentation();
108 
109 	public TextSelection<D, TA> makeTextSelection(FlexoDocElement<D, TA> startElement, int startRunId, int startCharId,
110 			FlexoDocElement<D, TA> endElement, int endRunId, int endCharId) throws FragmentConsistencyException;
111 
112 	public TextSelection<D, TA> makeTextSelection(FlexoDocElement<D, TA> startElement, int startRunId, FlexoDocElement<D, TA> endElement,
113 			int endRunId) throws FragmentConsistencyException;
114 
115 	public TextSelection<D, TA> makeTextSelection(FlexoDocElement<D, TA> element, int startRunId, int startCharId, int endRunId,
116 			int endCharId) throws FragmentConsistencyException;
117 
118 	public TextSelection<D, TA> makeTextSelection(FlexoDocElement<D, TA> element, int startRunId, int endRunId)
119 			throws FragmentConsistencyException;
120 
121 	public TextSelection<D, TA> makeTextSelection(FlexoDocElement<D, TA> startElement, FlexoDocElement<D, TA> endElement)
122 			throws FragmentConsistencyException;
123 
124 	public TextSelection<D, TA> makeTextSelection(FlexoDocElement<D, TA> element) throws FragmentConsistencyException;
125 
126 	public static abstract class FlexoDocumentFragmentImpl<D extends FlexoDocument<D, TA>, TA extends TechnologyAdapter<TA>>
127 			extends FlexoDocObjectImpl<D, TA> implements FlexoDocFragment<D, TA> {
128 
129 		private static final Logger logger = Logger.getLogger(FlexoDocumentFragmentImpl.class.getPackage().getName());
130 
131 		@Override
132 		public List<? extends FlexoDocElement<D, TA>> getElements() {
133 			if (getStartElement() == null || getEndElement() == null) {
134 				return Collections.emptyList();
135 			}
136 			int startIndex = getStartElement().getContainer().getElements().indexOf(getStartElement());
137 			int endIndex = getStartElement().getContainer().getElements().indexOf(getEndElement());
138 			if (startIndex > -1 && endIndex >= startIndex) {
139 				return getStartElement().getContainer().getElements().subList(startIndex, endIndex + 1);
140 			}
141 			return Collections.emptyList();
142 		}
143 
144 		/**
145 		 * Return the run as identified by runIdentifier, under the form: elementId.runIndex
146 		 * 
147 		 * @param runIdentifier
148 		 * @return
149 		 */
150 		@Override
151 		public FlexoDocRun<?, ?> getRun(String runIdentifier) {
152 			StringTokenizer st = new StringTokenizer(runIdentifier, ".");
153 			String elementId = null;
154 			if (st.hasMoreTokens()) {
155 				elementId = st.nextToken();
156 			}
157 			int runId = -1;
158 			if (st.hasMoreTokens()) {
159 				runId = Integer.parseInt(st.nextToken());
160 			}
161 			if (StringUtils.isNotEmpty(elementId)) {
162 				FlexoDocElement<?, ?> element = getFlexoDocument().getElementWithIdentifier(elementId);
163 				if (element instanceof FlexoDocParagraph) {
164 					FlexoDocParagraph<?, ?> para = (FlexoDocParagraph<?, ?>) element;
165 					if (runId > -1 && runId < para.getRuns().size()) {
166 						return para.getRuns().get(runId);
167 					}
168 				}
169 				else if (element != null) {
170 					logger.warning("!!! Not implemented: " + element.getClass());
171 				}
172 				else {
173 					logger.warning("!!! Cannot find element with id: " + elementId + " in " + getFlexoDocument());
174 					System.out.println(getFlexoDocument().debugStructuredContents());
175 				}
176 			}
177 			return null;
178 		}
179 
180 		@Override
181 		public void checkConsistency() throws FragmentConsistencyException {
182 			if (getFlexoDocument() == null) {
183 				throw new FragmentConsistencyException("Undefined FlexoDocument");
184 			}
185 			if (getStartElement().getContainer() == null) {
186 				throw new FragmentConsistencyException("Undefined start element container");
187 			}
188 			if (getEndElement().getContainer() == null) {
189 				throw new FragmentConsistencyException("Undefined end element container");
190 			}
191 			if (getStartElement().getContainer() != getEndElement().getContainer()) {
192 				throw new FragmentConsistencyException("Inconsistent containers");
193 			}
194 
195 			int startIndex = getStartElement().getContainer().getElements().indexOf(getStartElement());
196 			if (startIndex == -1) {
197 				throw new FragmentConsistencyException("Cannot find start index");
198 			}
199 			int endIndex = getStartElement().getContainer().getElements().indexOf(getEndElement());
200 			if (endIndex == -1) {
201 				throw new FragmentConsistencyException("Cannot find end index");
202 			}
203 			if (endIndex < startIndex) {
204 				throw new FragmentConsistencyException("Inconsistent fragment (reverse order)");
205 			}
206 			// Otherwise, that's ok
207 		}
208 
209 		@Override
210 		public boolean equals(Object obj) {
211 			if (!(obj instanceof FlexoDocFragment)) {
212 				return false;
213 			}
214 			FlexoDocFragment f2 = (FlexoDocFragment) obj;
215 			return getFlexoDocument().equals(f2.getFlexoDocument()) && getStartElement().equals(f2.getStartElement())
216 					&& getEndElement().equals(f2.getEndElement());
217 		}
218 
219 		@Override
220 		public String getStringRepresentationPreview() {
221 			return (getStartElement() instanceof FlexoDocParagraph ? ((FlexoDocParagraph) getStartElement()).getRawTextPreview()
222 					: (getStartElement() != null ? getStartElement().toString() : "?"))
223 					+ " : "
224 					+ (getStartElement() != getEndElement()
225 							? (getEndElement() instanceof FlexoDocParagraph ? ((FlexoDocParagraph) getEndElement()).getRawTextPreview()
226 									: (getEndElement() != null ? getEndElement().toString() : "?"))
227 							: "");
228 		}
229 
230 		@Override
231 		public String getStringRepresentation() {
232 			StringBuffer sb = new StringBuffer();
233 			for (FlexoDocElement<D, TA> element : getElements()) {
234 				if (element instanceof FlexoDocParagraph) {
235 					sb.append(((FlexoDocParagraph<D, TA>) element).getRawText() + "\n");
236 				}
237 			}
238 			return sb.toString();
239 		}
240 
241 		@Override
242 		public TextSelection<D, TA> makeTextSelection(FlexoDocElement<D, TA> startElement, int startRunId, int startCharId,
243 				FlexoDocElement<D, TA> endElement, int endRunId, int endCharId) throws FragmentConsistencyException {
244 			return getFlexoDocument().getFactory().makeTextSelection(this, startElement, startRunId, startCharId, endElement, endRunId,
245 					endCharId);
246 		}
247 
248 		@Override
249 		public TextSelection<D, TA> makeTextSelection(FlexoDocElement<D, TA> startElement, int startRunId,
250 				FlexoDocElement<D, TA> endElement, int endRunId) throws FragmentConsistencyException {
251 			return makeTextSelection(startElement, startRunId, -1, endElement, endRunId, -1);
252 		}
253 
254 		@Override
255 		public TextSelection<D, TA> makeTextSelection(FlexoDocElement<D, TA> element, int startRunId, int startCharId, int endRunId,
256 				int endCharId) throws FragmentConsistencyException {
257 			return makeTextSelection(element, startRunId, startCharId, element, endRunId, endCharId);
258 		}
259 
260 		@Override
261 		public TextSelection<D, TA> makeTextSelection(FlexoDocElement<D, TA> element, int startRunId, int endRunId)
262 				throws FragmentConsistencyException {
263 			return makeTextSelection(element, startRunId, -1, element, endRunId, -1);
264 		}
265 
266 		@Override
267 		public TextSelection<D, TA> makeTextSelection(FlexoDocElement<D, TA> startElement, FlexoDocElement<D, TA> endElement)
268 				throws FragmentConsistencyException {
269 			return makeTextSelection(startElement, -1, -1, endElement, -1, -1);
270 		}
271 
272 		@Override
273 		public TextSelection<D, TA> makeTextSelection(FlexoDocElement<D, TA> element) throws FragmentConsistencyException {
274 			return makeTextSelection(element, element);
275 		}
276 
277 	}
278 
279 }