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