ref #7439 Re-select after entity has been loaded
[taxeditor.git] / eu.etaxonomy.taxeditor.bulkeditor / src / main / java / eu / etaxonomy / taxeditor / bulkeditor / input / AbstractBulkEditorInput.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.taxeditor.bulkeditor.input;
10
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Map.Entry;
17 import java.util.Set;
18 import java.util.UUID;
19
20 import org.eclipse.core.runtime.ICoreRunnable;
21 import org.eclipse.core.runtime.jobs.Job;
22 import org.eclipse.jface.viewers.IStructuredSelection;
23
24 import ca.odell.glazedlists.BasicEventList;
25 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
26 import eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase;
27 import eu.etaxonomy.cdm.api.service.config.IIdentifiableEntityServiceConfigurator;
28 import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
29 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
30 import eu.etaxonomy.cdm.model.common.CdmBase;
31 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
32 import eu.etaxonomy.cdm.model.common.MarkerType;
33 import eu.etaxonomy.cdm.strategy.merge.IMergable;
34 import eu.etaxonomy.cdm.strategy.merge.MergeException;
35 import eu.etaxonomy.taxeditor.annotatedlineeditor.IEntityCreator;
36 import eu.etaxonomy.taxeditor.annotatedlineeditor.IEntityPersistenceService;
37 import eu.etaxonomy.taxeditor.bulkeditor.BulkEditorQuery;
38 import eu.etaxonomy.taxeditor.bulkeditor.IBulkEditorSortProvider;
39 import eu.etaxonomy.taxeditor.bulkeditor.input.sortprovider.CdmBaseSortProvider;
40 import eu.etaxonomy.taxeditor.bulkeditor.internal.TaxeditorBulkeditorPlugin;
41 import eu.etaxonomy.taxeditor.editor.CdmEntitySessionInput;
42 import eu.etaxonomy.taxeditor.event.EventUtility;
43 import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
44 import eu.etaxonomy.taxeditor.l10n.Messages;
45 import eu.etaxonomy.taxeditor.model.MessagingUtils;
46 import eu.etaxonomy.taxeditor.store.CdmStore;
47
48 /**
49 * @author p.ciardelli
50 * @created 25.06.2009
51 * @version 1.0
52 * @param <T>
53 */
54 public abstract class AbstractBulkEditorInput<T extends CdmBase> extends CdmEntitySessionInput implements
55 IEntityPersistenceService<T> {
56
57 private UUID entityUuid;
58
59 private BasicEventList<T> model = new BasicEventList<>();
60
61 private Map<T, DeleteConfiguratorBase> toDelete = new HashMap<>();
62 private Set<T> saveCandidates = new HashSet<>();
63
64
65 private Set<T> markedMergeCandidates = new HashSet<>();
66 private T markedMergeTarget = null;
67
68 private HashMap<T, Set<T>> mergedEntities = new HashMap<>();
69
70 private IEntityCreator<T> entityCreator;
71 private final ConversationHolder conversation;
72
73 private Job searchJob;
74
75 public AbstractBulkEditorInput() {
76 super(true);
77 this.conversation = CdmStore.createConversation();
78 }
79
80 static public AbstractBulkEditorInput NewInstance(BulkEditorInputType inputType) {
81
82 return BulkEditorInputType.getInput(inputType);
83 }
84
85 public static AbstractBulkEditorInput NewInstance(IdentifiableEntity entity) {
86
87 BulkEditorInputType inputType = BulkEditorInputType.getByType(entity.getClass());
88
89 AbstractBulkEditorInput editorInput = NewInstance(inputType);
90
91 editorInput.setEntityUuid(entity.getUuid());
92
93 return editorInput;
94 }
95
96 public abstract String getName();
97
98 public String getEditorName(){
99 return getName();
100 }
101
102 protected int getPageSize(){
103 return 100;
104 }
105
106 protected abstract List<T> listEntities(IIdentifiableEntityServiceConfigurator configurator);
107
108 protected abstract long countEntities(IIdentifiableEntityServiceConfigurator configurator);
109
110 protected abstract T loadEntity(UUID entityUuid);
111
112 public void setMergeTarget(T t){
113 markedMergeTarget = t;
114 }
115
116 public Set<T> getMergeCandidates() {
117 return markedMergeCandidates;
118 }
119
120 public T getMergeTarget() {
121 return markedMergeTarget;
122 }
123
124 public void removeMergeTarget(){
125 markedMergeTarget = null;
126 }
127
128 public void addMergeCandidate(T t){
129 markedMergeCandidates.add(t);
130 }
131
132 public void removeMergeCandidate(T t){
133 markedMergeCandidates.remove(t);
134 }
135
136 public void addToDelete(T t, DeleteConfiguratorBase config) {
137 toDelete.put(t, config);
138 }
139 public void addSaveCandidate(T t){
140 saveCandidates.add(t);
141 }
142 private void setEntityUuid(UUID entityUuid){
143 this.entityUuid = entityUuid;
144 }
145
146 public UUID getEntityUuid() {
147 return entityUuid;
148 }
149
150 public void performSearch(final BulkEditorQuery bulkEditorQuery, IStructuredSelection selection) {
151 //cancel previous search job
152 if(searchJob!=null && searchJob.getState()!=Job.NONE){
153 searchJob.cancel();
154 searchJob = null;
155 }
156 model.clear();
157
158 if(getEntityUuid() != null){
159
160 T entity = loadEntity(getEntityUuid());
161 model.add(entity);
162 }
163 else if(bulkEditorQuery != null){
164
165 IIdentifiableEntityServiceConfigurator configurator = bulkEditorQuery.getSearchConfigurator();
166
167 int pageSize = configurator.getPageSize()!=null?configurator.getPageSize():getPageSize();
168 long count = countEntities(configurator);
169 int totalWork = count>Integer.MAX_VALUE?Integer.MAX_VALUE:(int)count;
170 String jobLabel = String.format(Messages.AbstractBulkEditorInput_LOADING, getName(), bulkEditorQuery.getSearchString());
171 searchJob = Job.create(jobLabel, (ICoreRunnable) monitor -> {
172 monitor.beginTask(jobLabel, totalWork);
173 int pageNumber = 0;
174 List<T> entities;
175 do {
176 if (monitor.isCanceled()) {
177 break;
178 }
179 configurator.setPageNumber(pageNumber);
180 entities = listEntities(configurator);
181 model.addAll(entities);
182 //select if entity is loaded
183 if(selection!=null && model.containsAll(selection.toList())){
184 EventUtility.postAsyncEvent(WorkbenchEventConstants.BULK_EDITOR_SEARCH_FINISHED, selection);
185 }
186 pageNumber++;
187 monitor.worked(pageSize);
188 long workedLong = pageSize*pageNumber;
189 int loadedCount = workedLong>Integer.MAX_VALUE?Integer.MAX_VALUE:(int)workedLong;
190 monitor.setTaskName(String.format(Messages.AbstractBulkEditorInput_LOADED, loadedCount, totalWork, getName()));
191 } while (!entities.isEmpty());
192 monitor.done();
193 if(selection!=null){
194 EventUtility.postAsyncEvent(WorkbenchEventConstants.BULK_EDITOR_SEARCH_FINISHED, selection);
195 }
196 });
197 searchJob.schedule();
198 }
199 }
200
201 public boolean isMergingEnabled() {
202 return false;
203 }
204
205 public boolean isConvertingEnabled() {
206 return false;
207 }
208
209 public boolean isMarkerTypeEditingEnabled(MarkerType markerType) {
210 return false;
211 }
212
213
214 /** {@inheritDoc} */
215 @Override
216 public boolean merge(T entity, T mergeTarget) {
217 if (entity instanceof IMergable) {
218 try {
219 CdmStore.getCommonService().merge(mergeTarget.getUuid(), entity.getUuid(), (Class<? extends CdmBase>)entity.getClass());
220 } catch (MergeException e) {
221 MessagingUtils.errorDialog(Messages.AbstractBulkEditorInput_MERGE_ERROR_TITLE,
222 this,
223 String.format(Messages.AbstractBulkEditorInput_MERGE_ERROR_MESSAGE, entity.getClass().getName()),
224 TaxeditorBulkeditorPlugin.PLUGIN_ID,
225 e,
226 true);
227 }
228 }
229 return true;
230 }
231
232 public void saveModel(){
233 saveModel(true);
234 }
235
236 public void saveModel(boolean resetMerge){
237 //delete entities
238 for(Entry<T, DeleteConfiguratorBase> entry:toDelete.entrySet()){
239 try {
240 delete(entry.getKey(), entry.getValue());
241 } catch (ReferencedObjectUndeletableException e) {
242 e.printStackTrace();
243 }
244 }
245 if (!saveCandidates.isEmpty()){
246 CdmStore.getService(saveCandidates.iterator().next()).merge(new ArrayList<>(saveCandidates), true);
247 }
248 if(resetMerge){
249 //merge entities
250 for(T mergeTarget:mergedEntities.keySet()){
251 for (T mergeCandidate: mergedEntities.get(mergeTarget)){
252 merge(mergeCandidate, mergeTarget);
253 }
254 }
255 }
256 toDelete.clear();
257 saveCandidates.clear();
258 mergedEntities.clear();
259 }
260
261
262 /** {@inheritDoc} */
263 @Override
264 public T create(T entity) {
265 return save(entity);
266 }
267
268 public IEntityCreator<T> getEntityCreator(){
269 if(entityCreator == null){
270 entityCreator = createEntityCreator();
271 }
272 return entityCreator;
273 }
274
275 protected abstract IEntityCreator<T> createEntityCreator();
276
277 /**
278 * The default implementation returns an empty list of sort providers.
279 * @return
280 */
281 public List<IBulkEditorSortProvider<T>> getSortProviders(){
282 List<IBulkEditorSortProvider<T>> sortProviders = new ArrayList<IBulkEditorSortProvider<T>>();
283
284 sortProviders.add(new CdmBaseSortProvider<T>());
285
286 return sortProviders;
287 }
288
289 /**
290 * Returns a textual representation given object. The default implementation
291 * in the abstract base class returns the simple name of the class, this may
292 * be overwritten to something more specific in subclasses.
293 *
294 * @param entity
295 * @return a textual representation given object.
296 */
297 public String getTypeText(Object entity){
298 return entity.getClass().getSimpleName();
299 }
300
301 public String getText(T entity) {
302 if(entity instanceof IdentifiableEntity){
303 IdentifiableEntity identifiableEntity = (IdentifiableEntity) HibernateProxyHelper.deproxy(entity);
304 String text = ""; //$NON-NLS-1$
305 if(markedMergeCandidates.contains(entity)){
306 text += Messages.AbstractBulkEditorInput_CANDIDATE;
307 }
308 else if(markedMergeTarget==entity){
309 text += Messages.AbstractBulkEditorInput_TARGET;
310 }
311 text += identifiableEntity.getTitleCache();
312 return text;
313 }
314
315 return "No text. Implement in subclass"; //$NON-NLS-1$
316 }
317
318 public BasicEventList<T> getModel() {
319 return model;
320 }
321
322 public boolean replaceInModel(T entity) {
323 int index = model.indexOf(entity);
324 if(index >= 0) {
325 model.set(index, entity);
326 return true;
327 } else {
328 return false;
329 }
330 }
331
332 @Override
333 public List<T> getRootEntities() {
334 return getModel();
335 }
336
337
338 @Override
339 public Map<Object, List<String>> getPropertyPathsMap() {
340 // TODO Auto-generated method stub
341 return null;
342 }
343
344 public ConversationHolder getConversation() {
345 return conversation;
346 }
347
348 public Set<T> getSaveCandidates() {
349 return saveCandidates;
350 }
351
352 public HashMap<T, Set<T>> getMergedEntities() {
353 return mergedEntities;
354 }
355
356 public void setMergedEntities(HashMap<T, Set<T>> mergedEntities) {
357 this.mergedEntities = mergedEntities;
358 }
359 }