ref #8494: better handling of providers provided by webservice and from preference...
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / preference / ListComponent.java
1 /**
2 * Copyright (C) 2017 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.preference;
10
11
12 import java.awt.Toolkit;
13 import java.io.BufferedReader;
14 import java.io.IOException;
15 import java.io.InputStreamReader;
16 import java.net.HttpURLConnection;
17 import java.net.URL;
18 import java.util.ArrayList;
19
20 import javax.swing.event.DocumentEvent;
21
22 import org.apache.commons.lang.StringUtils;
23 import org.eclipse.equinox.internal.p2.ui.misc.StringMatcher;
24 import org.eclipse.jface.fieldassist.ComboContentAdapter;
25 import org.eclipse.jface.fieldassist.ContentProposalAdapter;
26 import org.eclipse.jface.fieldassist.IContentProposal;
27 import org.eclipse.jface.fieldassist.IContentProposalProvider;
28 import org.eclipse.jface.resource.JFaceResources;
29 import org.eclipse.swt.SWT;
30 import org.eclipse.swt.custom.CLabel;
31 import org.eclipse.swt.events.ModifyEvent;
32 import org.eclipse.swt.events.ModifyListener;
33 import org.eclipse.swt.events.MouseEvent;
34 import org.eclipse.swt.events.MouseListener;
35 import org.eclipse.swt.graphics.Rectangle;
36 import org.eclipse.swt.layout.GridData;
37 import org.eclipse.swt.widgets.Button;
38 import org.eclipse.swt.widgets.Combo;
39 import org.eclipse.swt.widgets.Composite;
40 import org.eclipse.swt.widgets.Display;
41 import org.eclipse.swt.widgets.Label;
42 import org.eclipse.swt.widgets.List;
43 import org.eclipse.swt.widgets.Text;
44 import org.json.JSONArray;
45 import org.json.JSONException;
46 import org.json.JSONObject;
47
48 import eu.etaxonomy.cdm.model.metadata.CdmPreference;
49 import eu.etaxonomy.cdm.model.metadata.PreferencePredicate;
50 import eu.etaxonomy.taxeditor.l10n.Messages;
51 import eu.etaxonomy.taxeditor.preference.menu.CdmPreferencePage;
52
53
54 /**
55 * @author k.luther
56 * @date 20.04.2017
57 *
58 */
59 public class ListComponent implements ModifyListener
60 {
61 private List list;
62
63 private static final String addString = Messages.ListComponent_ADD_PROVIDER;
64 private static final String removeString = Messages.ListComponent_REMOVE_PROVIDER;
65 private static final String noProvider = Messages.ListComponent_NO_PROVIDER_AVAILABLE;
66 private static final String serverSidePreference = "Server Side Preference:";
67 private Button removeButton;
68 private Combo providerURI;
69 protected Label labelException;
70 boolean isAdmin = false;
71 CdmPreferencePage preferencePage;
72 CdmPreference providerListPreference;
73 String providerList;
74 String[] items;
75
76
77 public CdmPreference getProviderListPreference() {
78 return providerListPreference;
79 }
80
81
82 public void setProviderListPreference(CdmPreference providerListPreference) {
83 this.providerListPreference = providerListPreference;
84 }
85
86
87 public ListComponent(Composite parent, int style, boolean isAdmin, CdmPreferencePage parentPage) {
88 this.isAdmin= isAdmin;
89 this.preferencePage = parentPage;
90
91 providerListPreference = PreferencesUtil.getPreferenceFromDB(PreferencePredicate.BioCaseProvider);
92 if (!isAdmin && providerListPreference != null && !providerListPreference.isAllowOverride()){
93 Label editingNotAllowed = new Label(parent, style);
94 editingNotAllowed.setText(Messages.AbcdImportProvider_description_not_available);
95 return ;
96 }
97 final CLabel description = new CLabel(parent, SWT.NULL);
98 description.setText(Messages.AbcdImportProvider_description);
99 list = new List(parent, SWT.BORDER | SWT.V_SCROLL);
100 GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, true, 2, 3);
101 gridData.grabExcessHorizontalSpace = true;
102 list.setLayoutData(gridData);
103
104 Rectangle clientArea = parent.getShell().getClientArea ();
105 list.setBounds (clientArea.x, clientArea.y, 50, 500);
106
107
108 providerList = null; //$NON-NLS-1$
109 String allProviderStringDB = "";
110
111 if (!isAdmin && ((providerListPreference != null && providerListPreference.isAllowOverride()) || providerListPreference == null)){
112 providerList = PreferencesUtil.getStringValue(PreferencePredicate.BioCaseProvider.getKey(), true);
113
114 }else{
115 if (providerListPreference != null){
116 providerList = providerListPreference.getValue();
117 }
118 }
119
120 //the string is structured like this: http://ww3.bgbm.org/biocase/pywrapper.cgi?dsa=DNA_Bank;http:...;
121 if (providerList != null){
122 String[] providerArray = providerList.split(";"); //$NON-NLS-1$
123 for (String providerString : providerArray){
124 if (!StringUtils.isBlank(providerString)){
125 list.add(providerString);
126
127 }
128 }
129 }
130
131 if (list.getItemCount() == 0){
132 list.add(noProvider);
133 }
134 list.add(""); //$NON-NLS-1$
135
136 // list.setSelection(0);
137 GridData dataList = new GridData();
138 dataList.horizontalAlignment = GridData.FILL;
139 dataList.horizontalSpan = 3;
140
141
142 // dataList.grabExcessVerticalSpace = true;
143
144 list.setLayoutData(dataList);
145
146
147 providerURI = new Combo(parent, SWT.BORDER);
148
149 URL url;
150 String response = null;
151 try {
152 url = new URL("https://www.biocase.org/whats_biocase/gbif_biocase.cgi");
153
154 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
155 conn.setRequestProperty("Accept", "application/json");
156 // conn.setConnectTimeout(TIMEOUT*9);
157 // conn.setReadTimeout(TIMEOUT*9);
158
159 if (conn.getResponseCode() != 200) {
160 throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode());
161 }
162 BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
163
164 StringBuilder builder = new StringBuilder();
165 String line;
166 while ((line = br.readLine()) != null) {
167 builder.append(line);
168 }
169 conn.disconnect();
170 response = builder.toString();
171 } catch (IOException e) {
172 // TODO Auto-generated catch block
173 e.printStackTrace();
174 }
175
176 JSONArray jsonResponseArray;
177 try {
178 jsonResponseArray =new JSONArray(response);
179
180 int i = 0;
181 String service_url = null;
182 JSONArray dataSets = null;
183 items = new String[jsonResponseArray.length()];
184 while (i<jsonResponseArray.length()){
185 JSONObject object = jsonResponseArray.getJSONObject(i);
186 service_url = (String) object.get("service_url");
187 dataSets = (JSONArray) object.get("datasets");
188 if (service_url != null){
189 providerURI.add(service_url);
190 items[i] = service_url;
191 }
192 i++;
193 }
194
195 } catch (JSONException e) {
196 // TODO Auto-generated catch block
197 e.printStackTrace();
198 }
199
200
201 GridData dataProviderUri = new GridData();
202 dataProviderUri.horizontalAlignment = GridData.FILL;
203 dataProviderUri.horizontalSpan = 3;
204 providerURI.setLayoutData(dataProviderUri);
205 // providerURI.setVisible(false);
206
207 ContentProposalAdapter adapter = new ContentProposalAdapter(providerURI, new ComboContentAdapter(), getProposalProvider(), null, null);
208 adapter.setPropagateKeys(true);
209 adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
210 // String[] proposals = new String[providerURI.getItems().length];
211 //
212 // for (int i = 0; i < providerURI.getItems().length; i++) {
213 // proposals[i] = providerURI.getItem(i);
214 // }
215 //
216 // ComboViewer comboViewer = new ComboViewer(parent, SWT.NONE);
217 // comboViewer.setContentProvider(new ArrayContentProvider());
218 // comboViewer.setLabelProvider(new LabelProvider(){
219 // @Override
220 // public String getText(final Object element){
221 // if(element instanceof String){
222 // return (String) element;
223 // }
224 // return element.toString();
225 // }
226 // });
227 // comboViewer.setInput(proposals);
228 // // additionally, configure the comboViewer arbitrary
229 // AutoCompleteField field = new AutoCompleteField(comboViewer.getCombo(), new ComboContentAdapter(), proposals);
230
231
232
233
234 //providerURI.addModifyListener(this);
235 labelException = new Label(parent, SWT.NULL);
236 labelException.setText("");
237
238
239 labelException.setLayoutData(dataProviderUri);
240
241 Button addButton = new Button(parent, SWT.NULL);
242 AddListener addListener = new AddListener(addButton);
243 addButton.setText(addString);
244 addButton.addMouseListener(addListener);
245
246 removeButton = new Button(parent, SWT.NULL);
247 removeButton.setText(removeString);
248 removeButton.addMouseListener(new RemoveListener());
249 }
250
251
252 /**
253 * @return
254 */
255 IContentProposalProvider getProposalProvider() {
256 return new IContentProposalProvider() {
257 @Override
258 public IContentProposal[] getProposals(String contents, int position) {
259 //String[] items = getStringItems();
260 if (contents.length() == 0 || items.length == 0) {
261 return new IContentProposal[0];
262 }
263 StringMatcher matcher = new StringMatcher("*" + contents + "*", true, false); //$NON-NLS-1$ //$NON-NLS-2$
264 ArrayList<String> matches = new ArrayList<String>();
265 for (int i = 0; i < items.length; i++) {
266 if (matcher.match(items[i])) {
267 matches.add(items[i]);
268 }
269 }
270
271 // We don't want to autoactivate if the only proposal exactly matches
272 // what is in the combo. This prevents the popup from
273 // opening when the user is merely scrolling through the combo values or
274 // has accepted a combo value.
275 if (matches.size() == 1 && matches.get(0).equals(providerURI.getText())) {
276 return new IContentProposal[0];
277 }
278
279 if (matches.isEmpty()) {
280 return new IContentProposal[0];
281 }
282
283 // Make the proposals
284 IContentProposal[] proposals = new IContentProposal[matches.size()];
285 for (int i = 0; i < matches.size(); i++) {
286 final String proposal = matches.get(i);
287 proposals[i] = new IContentProposal() {
288
289 @Override
290 public String getContent() {
291 return proposal;
292 }
293
294 @Override
295 public int getCursorPosition() {
296 return proposal.length();
297 }
298
299 @Override
300 public String getDescription() {
301 return null;
302 }
303
304 @Override
305 public String getLabel() {
306 return null;
307 }
308 };
309 }
310 return proposals;
311 }
312 };
313 }
314
315 public boolean isAdmin() {
316 return isAdmin;
317 }
318
319 public void setAdmin(boolean isAdmin) {
320 this.isAdmin = isAdmin;
321 }
322
323 class RemoveListener implements MouseListener {
324 @Override
325 public void mouseUp(MouseEvent e) {
326 //This method can be called only if
327 //there's a valid selection
328 //so go ahead and remove whatever's selected.
329 int index = list.getSelectionIndex();
330 try{
331 String item = list.getItem(index);
332 if (item.equals(serverSidePreference)) {
333 return;
334 }
335 list.remove(index);
336
337
338 int size = list.getItemCount();
339
340 if (size == 0) { //Nothing's left, disable removing.
341 removeButton.setEnabled(false);
342
343 } else { //Select an index.
344 if (index == size) {
345 //removed item in last position
346 index--;
347 }
348
349 list.setSelection(index-1);
350 preferencePage.setApply(true);
351
352 }
353 }catch(IllegalArgumentException iae){
354 //nothing was selected
355 return;
356 }
357
358 }
359 /**
360 * {@inheritDoc}
361 */
362 @Override
363 public void mouseDoubleClick(MouseEvent e) {
364 // TODO Auto-generated method stub
365
366 }
367
368
369 /**
370 * {@inheritDoc}
371 */
372 @Override
373 public void mouseDown(MouseEvent e) {
374 // TODO Auto-generated method stub
375
376 }
377 }
378
379 //This listener is shared by the text field and the add button.
380 class AddListener implements MouseListener {
381 private boolean alreadyEnabled = false;
382 private Button button;
383
384 public AddListener(Button button) {
385 this.button = button;
386 }
387
388
389 protected boolean alreadyInList(String name) {
390 return list.getData(name) != null;
391 }
392
393
394 private void enableButton() {
395 if (!alreadyEnabled) {
396 button.setEnabled(true);
397 }
398 }
399
400 private boolean handleEmptyTextField(DocumentEvent e) {
401 if (e.getDocument().getLength() <= 0) {
402 button.setEnabled(false);
403 alreadyEnabled = false;
404 return true;
405 }
406 return false;
407 }
408
409
410
411 /**
412 * {@inheritDoc}
413 */
414 @Override
415 public void mouseDoubleClick(MouseEvent e) {
416 // TODO Auto-generated method stub
417
418 }
419
420 /**
421 * {@inheritDoc}
422 */
423 @Override
424 public void mouseDown(MouseEvent e) {
425 // TODO Auto-generated method stub
426
427 }
428
429 /**
430 * {@inheritDoc}
431 */
432 @Override
433 public void mouseUp(MouseEvent event) {
434 String name = providerURI.getText();
435
436 //User didn't type in a unique name...
437 if (name.equals("") || alreadyInList(name) || !StringUtils.isBlank(labelException.getText())) { //$NON-NLS-1$
438 Toolkit.getDefaultToolkit().beep();
439 //providerURI.selectAll();
440 return;
441 }
442
443 int index = list.getSelectionIndex(); //get selected index
444 if (index == -1) { //no selection, so insert at beginning
445 index = 0;
446 } else { //add after the selected item
447 index++;
448 }
449 if(list.getItemCount() == 0){
450 index = 0;
451 }else if (list.getItem(0).equals(noProvider)){
452 list.remove(noProvider);
453 }
454 int itemCount = list.getItemCount();
455
456
457 list.add(providerURI.getText(), index);
458 list.setSelection(index);
459 list.update();
460 list.redraw();
461
462 //Select the new item
463
464 providerURI.setText(""); //$NON-NLS-1$
465 preferencePage.setApply(true);
466 }
467 }
468
469 public String createAllProviderString(){
470 String allProviderString = null;
471 boolean first = true;
472 for (String item: list.getItems()){
473 if (item.equals(noProvider) || item.equals(serverSidePreference)){
474 //do nothing
475 }else if (first || StringUtils.isBlank(allProviderString)){ //$NON-NLS-1$
476 allProviderString = item.trim();
477 first = false;
478 }else {
479 allProviderString +=";"+ item.trim(); //$NON-NLS-1$
480 }
481 }
482
483 return allProviderString;
484
485 }
486
487
488 @Override
489 public void modifyText(ModifyEvent e) {
490 if(e.widget==providerURI){
491 Text text = (Text) e.widget;
492 boolean hasControlCharacters = false;
493 String textString = text.getText();
494 int stringLength = textString.length();
495 for (int i = 0; i < stringLength; i++) {
496 if (Character.isISOControl(textString.charAt(i))) {
497 hasControlCharacters = true;
498 break;
499 }
500 }
501
502 //remove control character such as line breaks etc.
503 try {
504 getParsedText();
505 labelException.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT));
506 labelException.setForeground(Display.getCurrent().getSystemColor(SWT.NULL));
507 labelException.setText("");
508 } catch (Exception exception) {
509 labelException.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT));
510 labelException.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
511 labelException.setText(Messages.UriWithLabelElement_URL_NOT_SAVED+exception.getLocalizedMessage());
512 }
513 }
514
515
516 }
517
518
519 protected URL getParsedText() throws Exception {
520 String uriText = providerURI.getText();
521 if(!StringUtils.isBlank(uriText)){
522 return new URL(providerURI.getText());
523 }
524 return null;
525 }
526
527
528
529 }
530