gvsig-projects-pool / org.gvsig.online / trunk / org.gvsig.online / org.gvsig.online.lib / org.gvsig.online.lib.impl / src / main / java / org / gvsig / online / lib / impl / workspace / tables / EntitiesTable.java @ 9512
History | View | Annotate | Download (20 KB)
1 |
package org.gvsig.online.lib.impl.workspace.tables; |
---|---|
2 |
|
3 |
import java.util.List; |
4 |
import javax.json.JsonObject; |
5 |
import org.apache.commons.collections.CollectionUtils; |
6 |
import org.apache.commons.lang3.StringUtils; |
7 |
import org.cresques.cts.IProjection; |
8 |
import org.gvsig.fmap.crs.CRSFactory; |
9 |
import org.gvsig.fmap.dal.DALLocator; |
10 |
import org.gvsig.fmap.dal.DataManager; |
11 |
import static org.gvsig.fmap.dal.DataManager.RECOMENDED_SIZE_FOR_CLOB; |
12 |
import org.gvsig.fmap.dal.DataTransaction; |
13 |
import org.gvsig.fmap.dal.feature.DisposableFeatureSetIterable; |
14 |
import org.gvsig.fmap.dal.feature.EditableFeatureType; |
15 |
import org.gvsig.fmap.dal.feature.Feature; |
16 |
import org.gvsig.fmap.dal.feature.FeatureStore; |
17 |
import org.gvsig.fmap.dal.feature.FeatureType; |
18 |
import org.gvsig.json.Json; |
19 |
import org.gvsig.json.JsonObjectBuilder; |
20 |
import org.gvsig.online.lib.api.workingcopy.OnlineEntity; |
21 |
import org.gvsig.online.lib.api.workingcopy.OnlineEntityEditable; |
22 |
import org.gvsig.online.lib.api.OnlineManager; |
23 |
import org.gvsig.online.lib.impl.OnlineUtils; |
24 |
import org.gvsig.tools.dataTypes.DataTypes; |
25 |
import org.gvsig.tools.dispose.DisposeUtils; |
26 |
import org.gvsig.tools.dynform.spi.DynFormSPIManager; |
27 |
import org.gvsig.online.lib.api.workingcopy.OnlineWorkingcopy; |
28 |
|
29 |
/**
|
30 |
*
|
31 |
* @author gvSIG Team
|
32 |
*/
|
33 |
@SuppressWarnings("UseSpecificCatch") |
34 |
public class EntitiesTable extends AbstractTable { |
35 |
|
36 |
public static final String TABLE_NAME = OnlineWorkingcopy.TABLE_NAME_ENTITIES; |
37 |
|
38 |
public static final String COD_ENTITY = "COD_ENTITY"; |
39 |
public static final String ENTITY_NAME = "ENT_NAME"; |
40 |
private static final String ENTITY_STATE = "ENT_STATE"; |
41 |
private static final String FEATUREID_FIELD_NAME = "ENT_FEATURECODE"; |
42 |
private static final String GEOMETRY_FIELD_NAME = "ENT_GEOMNAME"; |
43 |
private static final String DESCRIPTION = "ENT_DESCRIPTION"; |
44 |
private static final String FIELD_FOR_LABEL = "ENT_FIELDFORLABEL"; |
45 |
private static final String FEATURETYPE = "ENT_FEATURETYPE"; |
46 |
private static final String LABEL = "ENT_LABEL"; |
47 |
private static final String DATA_MODELS = "ENT_DATA_MODELS"; |
48 |
private static final String ENT_PROJECTION = "ENT_PROJECTION"; |
49 |
private static final String ENT_CUSTOMDATA = "ENT_CUSTOMDATA"; |
50 |
private static final String ENT_TILESIZE = "ENT_TILESIZE"; |
51 |
|
52 |
public static class EntityRow extends AbstractRow implements OnlineEntityEditable { |
53 |
|
54 |
private FeatureType featureType;
|
55 |
|
56 |
public EntityRow(OnlineWorkingcopy workspace) {
|
57 |
super(workspace, TABLE_NAME, COD_ENTITY);
|
58 |
} |
59 |
|
60 |
public EntityRow(OnlineWorkingcopy workspace, Feature feature) {
|
61 |
super(workspace, TABLE_NAME, COD_ENTITY,feature);
|
62 |
} |
63 |
|
64 |
@Override
|
65 |
public String getEntityName() { |
66 |
return this.getString(ENTITY_NAME); |
67 |
} |
68 |
|
69 |
@Override
|
70 |
public String getFeatureIdFieldName() { |
71 |
return this.getString(FEATUREID_FIELD_NAME); |
72 |
} |
73 |
|
74 |
|
75 |
@Override
|
76 |
public String getGeometryFieldName() { |
77 |
return this.getString(GEOMETRY_FIELD_NAME); |
78 |
} |
79 |
|
80 |
@Override
|
81 |
public String getDescription() { |
82 |
return this.getString(DESCRIPTION); |
83 |
} |
84 |
|
85 |
@Override
|
86 |
public String getFieldForLabel() { |
87 |
return this.getString(FIELD_FOR_LABEL); |
88 |
} |
89 |
|
90 |
@Override
|
91 |
public String getEntityCode() { |
92 |
return this.getCode(); |
93 |
} |
94 |
|
95 |
@Override
|
96 |
public String getFirstDataModel() { |
97 |
List<String> l = getDataModelsAsList(); |
98 |
if( CollectionUtils.isEmpty(l) ) {
|
99 |
return null; |
100 |
} |
101 |
return l.get(0); |
102 |
} |
103 |
|
104 |
@Override
|
105 |
public String getLabel() { |
106 |
return this.getString(LABEL); |
107 |
} |
108 |
|
109 |
@Override
|
110 |
public String getFeatureTypeAsJson() { |
111 |
return this.getString(FEATURETYPE); |
112 |
} |
113 |
|
114 |
@Override
|
115 |
public FeatureType getFeatureType() {
|
116 |
if (this.featureType == null) { |
117 |
String s = this.getFeatureTypeAsJson(); |
118 |
// s = StringUtils.replace(s, "\"\"", "\"");
|
119 |
JsonObject json = Json.createObject(s); |
120 |
this.featureType = DALLocator.getDataManager().createFeatureType(json);
|
121 |
} |
122 |
return this.featureType; |
123 |
} |
124 |
|
125 |
|
126 |
@Override
|
127 |
public EntityRow setEntityName(String entityName) { |
128 |
this.set(ENTITY_NAME, entityName);
|
129 |
if( StringUtils.isBlank(this.getLabel())) { |
130 |
this.setLabel(entityName);
|
131 |
} |
132 |
return this; |
133 |
} |
134 |
|
135 |
@Override
|
136 |
public EntityRow setFeatureIdFieldName(String name) { |
137 |
this.set(FEATUREID_FIELD_NAME, name);
|
138 |
return this; |
139 |
} |
140 |
|
141 |
@Override
|
142 |
public EntityRow setGeometryFieldName(String name) { |
143 |
this.set(GEOMETRY_FIELD_NAME, name);
|
144 |
return this; |
145 |
} |
146 |
|
147 |
@Override
|
148 |
public EntityRow setDescription(String description) { |
149 |
this.set(DESCRIPTION, description);
|
150 |
return this; |
151 |
} |
152 |
|
153 |
@Override
|
154 |
public EntityRow setFieldForLabel(String fieldForLabel) { |
155 |
this.set(FIELD_FOR_LABEL, fieldForLabel);
|
156 |
return this; |
157 |
} |
158 |
|
159 |
@Override
|
160 |
public EntityRow setFeatureTypeAsJson(String json) { |
161 |
this.set(FEATURETYPE, json);
|
162 |
this.featureType = null; |
163 |
return this; |
164 |
} |
165 |
|
166 |
public EntityRow setFeatureType(FeatureType featureType) {
|
167 |
this.set(FEATURETYPE, featureType.toJson().toString());
|
168 |
return this; |
169 |
} |
170 |
|
171 |
@Override
|
172 |
public OnlineEntityEditable setLabel(String label) { |
173 |
if(label != null){ |
174 |
this.set(LABEL, label);
|
175 |
} |
176 |
return this; |
177 |
} |
178 |
|
179 |
public long getCountLocalChanges() { |
180 |
return this.getCountLocalChanges(null); |
181 |
} |
182 |
|
183 |
public long getCountLocalChanges(DataTransaction transaction) { |
184 |
WorkspaceChangesTable changesTable = new WorkspaceChangesTable();
|
185 |
return changesTable.getCountLocalChangesOfEntity(workspace, transaction, this.getCode()); |
186 |
} |
187 |
|
188 |
public long getCountRemoteChanges(DataTransaction transaction) { |
189 |
RemoteChangesTable changesTable = new RemoteChangesTable();
|
190 |
return changesTable.getCountRemoteChangesOfEntity(workspace, transaction, this.getCode()); |
191 |
} |
192 |
|
193 |
/**
|
194 |
* Actualiza el estado si es necesario y retorna cierto si este ha cambiado.
|
195 |
* @return
|
196 |
*/
|
197 |
public boolean updateState() { |
198 |
return this.updateState(null); |
199 |
} |
200 |
|
201 |
public boolean updateState(DataTransaction transaction) { |
202 |
long countChanges;
|
203 |
int prevstate = this.getInt(ENTITY_STATE, -1); |
204 |
int state = prevstate;
|
205 |
if( state == -1 ) { |
206 |
state = OnlineManager.STATE_LOCAL_UNMODIFIED; |
207 |
this.setState(state);
|
208 |
} |
209 |
switch (state) {
|
210 |
case OnlineManager.STATE_DISCONNECTED:
|
211 |
case OnlineManager.STATE_CORRUPT:
|
212 |
return false; |
213 |
case OnlineManager.STATE_LOCAL_UNMODIFIED:
|
214 |
countChanges = this.getCountLocalChanges(transaction);
|
215 |
if (countChanges > 0) { |
216 |
state = OnlineManager.STATE_LOCAL_MODIFIED; |
217 |
if(this.isOutdated()){ |
218 |
state = OnlineManager.STATE_LOCAL_OUTDATED_AND_MODIFIED; |
219 |
} |
220 |
this.setState(state);
|
221 |
} else if(this.isOutdated()){ |
222 |
state = OnlineManager.STATE_LOCAL_OUTDATED; |
223 |
this.setState(state);
|
224 |
} |
225 |
break;
|
226 |
case OnlineManager.STATE_LOCAL_OUTDATED:
|
227 |
if(!this.isOutdated()){ |
228 |
countChanges = this.getCountLocalChanges(transaction);
|
229 |
if (countChanges > 0) { |
230 |
state = OnlineManager.STATE_LOCAL_MODIFIED; |
231 |
} else {
|
232 |
state = OnlineManager.STATE_LOCAL_UNMODIFIED; |
233 |
} |
234 |
} else {
|
235 |
countChanges = this.getCountLocalChanges(transaction);
|
236 |
if (countChanges > 0) { |
237 |
state = OnlineManager.STATE_LOCAL_OUTDATED_AND_MODIFIED; |
238 |
this.setState(state);
|
239 |
} |
240 |
} |
241 |
this.setState(state);
|
242 |
break;
|
243 |
case OnlineManager.STATE_LOCAL_MODIFIED:
|
244 |
countChanges = this.getCountLocalChanges(transaction);
|
245 |
if (countChanges == 0) { |
246 |
state = OnlineManager.STATE_LOCAL_UNMODIFIED; |
247 |
if(this.isOutdated()){ |
248 |
state = OnlineManager.STATE_LOCAL_OUTDATED; |
249 |
} |
250 |
} else {
|
251 |
if(this.isOutdated()){ |
252 |
state = OnlineManager.STATE_LOCAL_OUTDATED_AND_MODIFIED; |
253 |
} |
254 |
} |
255 |
|
256 |
this.setState(state);
|
257 |
break;
|
258 |
case OnlineManager.STATE_LOCAL_OUTDATED_AND_MODIFIED:
|
259 |
if(!this.isOutdated()){ |
260 |
countChanges = this.getCountLocalChanges(transaction);
|
261 |
if (countChanges > 0) { |
262 |
state = OnlineManager.STATE_LOCAL_MODIFIED; |
263 |
this.setState(state);
|
264 |
} else {
|
265 |
state = OnlineManager.STATE_LOCAL_UNMODIFIED; |
266 |
} |
267 |
} else {
|
268 |
countChanges = this.getCountLocalChanges(transaction);
|
269 |
if (countChanges > 0) { |
270 |
state = OnlineManager.STATE_LOCAL_OUTDATED_AND_MODIFIED; |
271 |
this.setState(state);
|
272 |
} else {
|
273 |
state = OnlineManager.STATE_LOCAL_OUTDATED; |
274 |
} |
275 |
} |
276 |
this.setState(state);
|
277 |
break;
|
278 |
|
279 |
case OnlineManager.STATE_LOCAL_NEW:
|
280 |
countChanges = this.getCountLocalChanges(transaction);
|
281 |
if (countChanges > 0) { |
282 |
state = OnlineManager.STATE_LOCAL_MODIFIED; |
283 |
if(this.isOutdated()){ |
284 |
state = OnlineManager.STATE_LOCAL_OUTDATED_AND_MODIFIED; |
285 |
} |
286 |
} else {
|
287 |
state = OnlineManager.STATE_LOCAL_UNMODIFIED; |
288 |
} |
289 |
this.setState(state);
|
290 |
break;
|
291 |
case OnlineManager.STATE_CONFLICT:
|
292 |
//TODO: Migrar a VCSGIS
|
293 |
long countLocalChanges = this.getCountLocalChanges(transaction); |
294 |
long countRemoteChanges = this.getCountRemoteChanges(transaction); |
295 |
if (countRemoteChanges < 1 && countLocalChanges < 1) { |
296 |
state = OnlineManager.STATE_LOCAL_UNMODIFIED; |
297 |
} else if (countRemoteChanges < 1 && countLocalChanges > 0) { |
298 |
state = OnlineManager.STATE_LOCAL_MODIFIED; |
299 |
} else if (countRemoteChanges > 0 && countLocalChanges < 1) { |
300 |
state = OnlineManager.STATE_REMOTE_MODIFIED; |
301 |
} else if (countRemoteChanges > 0 && countLocalChanges > 0) { |
302 |
state = OnlineManager.STATE_CONFLICT; |
303 |
} else {
|
304 |
LOGGER.warn("Por aqui no deberia pasar");
|
305 |
state = OnlineManager.STATE_CORRUPT; |
306 |
} |
307 |
this.setState(state);
|
308 |
break;
|
309 |
|
310 |
default:
|
311 |
if(this.isOutdated()){ |
312 |
state = OnlineManager.STATE_LOCAL_OUTDATED; |
313 |
this.setState(state);
|
314 |
} |
315 |
} |
316 |
return prevstate != state;
|
317 |
} |
318 |
|
319 |
@Override
|
320 |
public int getState() { |
321 |
// this.updateState();
|
322 |
int state = this.getInt(ENTITY_STATE); |
323 |
return state;
|
324 |
} |
325 |
|
326 |
@Override
|
327 |
public boolean isOutdated() { |
328 |
return false; |
329 |
// final String repositoryRevisionCode = this.getRepositoryRevisionCode();
|
330 |
// if(StringUtils.isBlank(repositoryRevisionCode)){
|
331 |
// return false;
|
332 |
// }
|
333 |
// return !StringUtils.equalsIgnoreCase(repositoryRevisionCode,this.getLocalRevisionCode());
|
334 |
} |
335 |
|
336 |
public String getStateLabel() { |
337 |
return OnlineUtils.getStateLabel(this.getState()); |
338 |
} |
339 |
|
340 |
public void setState(int state) { |
341 |
this.set(ENTITY_STATE, state);
|
342 |
} |
343 |
|
344 |
@Override
|
345 |
public void update() { |
346 |
super.update();
|
347 |
} |
348 |
|
349 |
@Override
|
350 |
public OnlineEntityEditable getValue() {
|
351 |
return this; |
352 |
} |
353 |
|
354 |
@Override
|
355 |
public String toString() { |
356 |
return OnlineUtils.getLabelOrName(this); |
357 |
} |
358 |
|
359 |
@Override
|
360 |
public EntityRow setEntityCode(String code) { |
361 |
this.setCode(code);
|
362 |
return this; |
363 |
} |
364 |
|
365 |
@Override
|
366 |
public void copyfrom(OnlineEntity entity) { |
367 |
OnlineUtils.copy(entity, this, null); |
368 |
} |
369 |
|
370 |
@Override
|
371 |
public void copyto(OnlineEntityEditable entity) { |
372 |
OnlineUtils.copy(this, entity, null); |
373 |
} |
374 |
|
375 |
@Override
|
376 |
public JsonObject toJson() {
|
377 |
return this.toJsonBuilder().build(); |
378 |
} |
379 |
|
380 |
@Override
|
381 |
public JsonObjectBuilder toJsonBuilder() {
|
382 |
return OnlineUtils.toJsonBuilder(this, null); |
383 |
} |
384 |
|
385 |
@Override
|
386 |
public void fromJson(JsonObject json) { |
387 |
OnlineUtils.fromJson(this, json);
|
388 |
} |
389 |
|
390 |
@Override
|
391 |
public OnlineEntityEditable setDataModels(String dataModels) { |
392 |
this.set(DATA_MODELS, dataModels);
|
393 |
return this; |
394 |
} |
395 |
|
396 |
@Override
|
397 |
public String getDataModels() { |
398 |
return this.getString(DATA_MODELS); |
399 |
} |
400 |
|
401 |
@Override
|
402 |
public List<String> getDataModelsAsList() { |
403 |
String s = getDataModels();
|
404 |
return OnlineUtils.getAsList(s, false); |
405 |
} |
406 |
|
407 |
@Override
|
408 |
public String getLabelOrName() { |
409 |
return OnlineUtils.getLabelOrName(this); |
410 |
} |
411 |
|
412 |
@Override
|
413 |
public String getCRS() { |
414 |
return this.getString(ENT_PROJECTION); |
415 |
} |
416 |
|
417 |
@Override
|
418 |
public IProjection getCRSAsProjection() {
|
419 |
String s = this.getString(ENT_PROJECTION); |
420 |
if( StringUtils.isBlank(s) ) {
|
421 |
return null; |
422 |
} |
423 |
return CRSFactory.getCRS(s);
|
424 |
} |
425 |
|
426 |
@Override
|
427 |
public String getCustomData() { |
428 |
return this.getString(ENT_CUSTOMDATA); |
429 |
} |
430 |
|
431 |
@Override
|
432 |
public int getTileSize() { |
433 |
return this.getInt(ENT_TILESIZE); |
434 |
} |
435 |
|
436 |
@Override
|
437 |
public OnlineEntityEditable setCRS(IProjection crs) {
|
438 |
this.set(ENT_PROJECTION, crs.getAbrev());
|
439 |
return this; |
440 |
} |
441 |
|
442 |
@Override
|
443 |
public OnlineEntityEditable setCRS(String crs) { |
444 |
this.set(ENT_PROJECTION, crs);
|
445 |
return this; |
446 |
} |
447 |
|
448 |
@Override
|
449 |
public OnlineEntityEditable setCustomData(String customData) { |
450 |
this.set(ENT_CUSTOMDATA, customData);
|
451 |
return this; |
452 |
} |
453 |
|
454 |
@Override
|
455 |
public OnlineEntityEditable setTileSize(int tileSize) { |
456 |
this.set(ENT_TILESIZE, tileSize);
|
457 |
return this; |
458 |
} |
459 |
|
460 |
} |
461 |
|
462 |
|
463 |
public EntitiesTable() {
|
464 |
super(TABLE_NAME, featureType());
|
465 |
} |
466 |
|
467 |
public EntityRow getByEntityName(OnlineWorkingcopy workspace, String entityName) { |
468 |
FeatureStore store = null;
|
469 |
try {
|
470 |
store = workspace.getFeatureStore(TABLE_NAME); |
471 |
Feature f = store.findFirst("\"" + ENTITY_NAME + "\"='" + entityName + "'"); |
472 |
if (f == null) { |
473 |
return null; |
474 |
} |
475 |
EntityRow row = new EntityRow(workspace, f);
|
476 |
return row;
|
477 |
} catch (Exception ex) { |
478 |
throw new RuntimeException("Can't retrieve entity '" + entityName + "'.", ex); |
479 |
} finally {
|
480 |
DisposeUtils.disposeQuietly(store); |
481 |
} |
482 |
} |
483 |
|
484 |
public EntityRow getByEntityCode(OnlineWorkingcopy workspace, String entityCode) { |
485 |
FeatureStore store = null;
|
486 |
try {
|
487 |
store = workspace.getFeatureStore(TABLE_NAME); |
488 |
Feature f = store.findFirst("\"" + COD_ENTITY + "\"='" + entityCode + "'"); |
489 |
if (f == null) { |
490 |
return null; |
491 |
} |
492 |
EntityRow row = new EntityRow(workspace, f);
|
493 |
return row;
|
494 |
} catch (Exception ex) { |
495 |
throw new RuntimeException("Can't retrieve entity '" + entityCode + "'.", ex); |
496 |
} finally {
|
497 |
DisposeUtils.disposeQuietly(store); |
498 |
} |
499 |
} |
500 |
|
501 |
public DisposableFeatureSetIterable getAll(OnlineWorkingcopy workspace) {
|
502 |
FeatureStore store = null;
|
503 |
try {
|
504 |
store = workspace.getFeatureStore(TABLE_NAME); |
505 |
DisposableFeatureSetIterable items = store.getFeatureSet().iterable(); |
506 |
return items;
|
507 |
} catch (Exception ex) { |
508 |
throw new RuntimeException("Can't retrieve all entities.", ex); |
509 |
} finally {
|
510 |
if (store != null) { |
511 |
DisposeUtils.dispose(store); |
512 |
} |
513 |
} |
514 |
} |
515 |
|
516 |
public static final FeatureType featureType() { |
517 |
DataManager dataManager = DALLocator.getDataManager(); |
518 |
EditableFeatureType ft = dataManager.createFeatureType(); |
519 |
ft.setLabel("VCSGIS Entities");
|
520 |
ft.getTags().set("ID", TABLE_NAME);
|
521 |
ft.add(COD_ENTITY, DataTypes.STRING) |
522 |
.setSize(OnlineManager.ONLINECODELEN) |
523 |
.setIsPrimaryKey(true)
|
524 |
.setLabel("Code");
|
525 |
ft.add(ENTITY_NAME, DataTypes.STRING) |
526 |
.setIsIndexed(true)
|
527 |
.setAllowIndexDuplicateds(false)
|
528 |
.setSize(200)
|
529 |
.setLabel("Name");
|
530 |
ft.add(FEATUREID_FIELD_NAME, DataTypes.STRING) |
531 |
.setSize(200)
|
532 |
.setLabel("Pk field name")
|
533 |
.setDescription("Name of the primary key of the table.");
|
534 |
ft.add(ENTITY_STATE, DataTypes.INTEGER) |
535 |
.setLabel("State")
|
536 |
.setDescription("State of entity.");
|
537 |
ft.add(GEOMETRY_FIELD_NAME, DataTypes.STRING) |
538 |
.setSize(200)
|
539 |
.setLabel("Geometry field name")
|
540 |
.setDescription("Name of the geometry attribute.");
|
541 |
ft.add(FIELD_FOR_LABEL, DataTypes.STRING) |
542 |
.setSize(200)
|
543 |
.setLabel("Field for label");
|
544 |
ft.add(LABEL, DataTypes.STRING) |
545 |
.setSize(200)
|
546 |
.setLabel("Label");
|
547 |
ft.add(DESCRIPTION, DataTypes.STRING) |
548 |
.setSize(RECOMENDED_SIZE_FOR_CLOB) |
549 |
.setLabel("Description");
|
550 |
ft.add(FEATURETYPE, DataTypes.STRING) |
551 |
.setSize(RECOMENDED_SIZE_FOR_CLOB) |
552 |
.setLabel("Feature type");
|
553 |
ft.add(DATA_MODELS, DataTypes.STRING) |
554 |
.setSize(200)
|
555 |
.setLabel("Data models");
|
556 |
ft.add(ENT_PROJECTION, DataTypes.STRING) |
557 |
.setSize(100)
|
558 |
.setLabel("Projection");
|
559 |
|
560 |
ft.add(ENT_TILESIZE, DataTypes.INTEGER) |
561 |
.setLabel("Tile size");
|
562 |
|
563 |
ft.add(ENT_CUSTOMDATA, DataTypes.STRING) |
564 |
.setTag(DynFormSPIManager.TAG_DYNFORM_RESIZEWEIGHT, 60)
|
565 |
.setTag(DynFormSPIManager.TAG_DYNFORM_LABEL_EMPTY, true)
|
566 |
.setDataProfileName("Text")
|
567 |
.setSize(RECOMENDED_SIZE_FOR_CLOB) |
568 |
.setLabel("Custom data")
|
569 |
.setGroup("Custom data")
|
570 |
.setOrder(10);
|
571 |
|
572 |
return ft.getNotEditableCopy();
|
573 |
} |
574 |
|
575 |
} |