3 * Copyright (C) 2017 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.taxeditor
.ui
.dialog
.selection
;
14 import java
.text
.Collator
;
15 import java
.util
.ArrayList
;
16 import java
.util
.Collections
;
17 import java
.util
.Comparator
;
18 import java
.util
.List
;
20 import org
.eclipse
.core
.runtime
.Assert
;
21 import org
.eclipse
.core
.runtime
.CoreException
;
22 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
23 import org
.eclipse
.core
.runtime
.IStatus
;
24 import org
.eclipse
.core
.runtime
.ListenerList
;
25 import org
.eclipse
.core
.runtime
.Status
;
26 import org
.eclipse
.core
.runtime
.jobs
.Job
;
27 import org
.eclipse
.jface
.action
.LegacyActionTools
;
28 import org
.eclipse
.jface
.dialogs
.Dialog
;
29 import org
.eclipse
.jface
.viewers
.DelegatingStyledCellLabelProvider
.IStyledLabelProvider
;
30 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
31 import org
.eclipse
.jface
.viewers
.IColorProvider
;
32 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
33 import org
.eclipse
.jface
.viewers
.IFontProvider
;
34 import org
.eclipse
.jface
.viewers
.ILabelProvider
;
35 import org
.eclipse
.jface
.viewers
.ILabelProviderListener
;
36 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
37 import org
.eclipse
.jface
.viewers
.IStructuredContentProvider
;
38 import org
.eclipse
.jface
.viewers
.LabelProvider
;
39 import org
.eclipse
.jface
.viewers
.LabelProviderChangedEvent
;
40 import org
.eclipse
.jface
.viewers
.SelectionChangedEvent
;
41 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
42 import org
.eclipse
.jface
.viewers
.StyledCellLabelProvider
;
43 import org
.eclipse
.jface
.viewers
.StyledString
;
44 import org
.eclipse
.jface
.viewers
.TableViewer
;
45 import org
.eclipse
.jface
.viewers
.Viewer
;
46 import org
.eclipse
.jface
.viewers
.ViewerCell
;
47 import org
.eclipse
.swt
.SWT
;
48 import org
.eclipse
.swt
.accessibility
.AccessibleAdapter
;
49 import org
.eclipse
.swt
.accessibility
.AccessibleEvent
;
50 import org
.eclipse
.swt
.events
.ModifyEvent
;
51 import org
.eclipse
.swt
.events
.ModifyListener
;
52 import org
.eclipse
.swt
.events
.TraverseEvent
;
53 import org
.eclipse
.swt
.events
.TraverseListener
;
54 import org
.eclipse
.swt
.graphics
.Color
;
55 import org
.eclipse
.swt
.graphics
.Font
;
56 import org
.eclipse
.swt
.graphics
.GC
;
57 import org
.eclipse
.swt
.graphics
.Point
;
58 import org
.eclipse
.swt
.graphics
.Rectangle
;
59 import org
.eclipse
.swt
.layout
.GridData
;
60 import org
.eclipse
.swt
.layout
.GridLayout
;
61 import org
.eclipse
.swt
.widgets
.Button
;
62 import org
.eclipse
.swt
.widgets
.Composite
;
63 import org
.eclipse
.swt
.widgets
.Control
;
64 import org
.eclipse
.swt
.widgets
.Display
;
65 import org
.eclipse
.swt
.widgets
.Event
;
66 import org
.eclipse
.swt
.widgets
.Label
;
67 import org
.eclipse
.swt
.widgets
.Shell
;
68 import org
.eclipse
.swt
.widgets
.Table
;
69 import org
.eclipse
.swt
.widgets
.Text
;
70 import org
.eclipse
.ui
.IWorkbenchPreferenceConstants
;
71 import org
.eclipse
.ui
.PlatformUI
;
72 import org
.eclipse
.ui
.dialogs
.FilteredItemsSelectionDialog
;
73 import org
.eclipse
.ui
.internal
.IWorkbenchGraphicConstants
;
74 import org
.eclipse
.ui
.internal
.WorkbenchImages
;
75 import org
.eclipse
.ui
.internal
.WorkbenchMessages
;
76 import org
.eclipse
.ui
.internal
.WorkbenchPlugin
;
78 import eu
.etaxonomy
.cdm
.model
.common
.ICdmBase
;
79 import eu
.etaxonomy
.cdm
.persistence
.dto
.UuidAndTitleCache
;
80 import eu
.etaxonomy
.taxeditor
.l10n
.Messages
;
81 import eu
.etaxonomy
.taxeditor
.ui
.dialog
.selection
.CdmFilteredItemsSelectionDialog
.ItemsListSeparator
;
88 public abstract class SearchDialog
<T
extends ICdmBase
> extends Dialog
{// implements IConversationEnabled{
90 private TableViewer list
;
91 private Text searchField
;
93 protected Button newButton1
;
96 protected Button newButton2
;
97 protected Button filterButton
;
98 protected Button btnCheckButton
;
99 private StructuredSelection currentSelection
;
101 // message to show user
102 private String message
= ""; //$NON-NLS-1$
104 protected final ContentProvider contentProvider
;
105 ItemsListLabelProvider itemsListLabelProvider
;
107 private final RefreshCacheJob refreshCacheJob
;
109 protected Object preferenceID
;
111 protected final int new_id
= 4;
112 protected final int new_id2
= 5;
113 protected final int space_id
= 6;
114 // Need to keep our own list of listeners
115 private final ListenerList listeners
= new ListenerList();
118 private static final String EMPTY_STRING
= ""; //$NON-NLS-1$
119 private GridData gd_1
;
120 protected boolean useIdentifier
;
122 public SearchDialog(Shell parent
, boolean multi
) {
124 contentProvider
= new ContentProvider();
125 refreshCacheJob
= new RefreshCacheJob();
132 protected Control
createDialogArea(Composite parent
) {
133 Composite container
= (Composite
) super.createDialogArea(parent
);
135 GridData gd
= new GridData(GridData
.FILL_BOTH
);
136 container
.setLayoutData(gd
);
138 GridLayout layout
= new GridLayout();
139 layout
.numColumns
= 1;
140 layout
.marginWidth
= 0;
141 layout
.marginHeight
= 0;
142 container
.setLayout(layout
);
144 final Label headerLabel
= createHeader(container
);
146 Composite searchAndFilter
= new Composite(container
, container
.getStyle());
148 searchAndFilter
.setLayoutData(new GridData(GridData
.GRAB_HORIZONTAL
| GridData
.HORIZONTAL_ALIGN_FILL
));
149 GridLayout searchAndFilterLayout
= new GridLayout();
150 searchAndFilterLayout
.numColumns
= 2;
151 searchAndFilter
.setLayout(searchAndFilterLayout
);
152 searchField
= new Text(searchAndFilter
, SWT
.SINGLE
| SWT
.BORDER
| SWT
.SEARCH
| SWT
.ICON_CANCEL
);
153 searchField
.getAccessible().addAccessibleListener(new AccessibleAdapter() {
155 public void getName(AccessibleEvent e
) {
156 e
.result
= LegacyActionTools
.removeMnemonics(headerLabel
160 searchField
.addModifyListener(new ModifyListener() {
162 public void modifyText(ModifyEvent e
) {
164 // fillContentProvider(null);
168 gd_1
= new GridData(GridData
.GRAB_HORIZONTAL
| GridData
.HORIZONTAL_ALIGN_FILL
);
170 searchField
.setLayoutData(gd_1
);
172 createFilterButton(searchAndFilter
);
174 addIdentifierCheckButton(searchAndFilter
);
175 setList(new TableViewer(container
, SWT
.SINGLE
176 | SWT
.BORDER
| SWT
.V_SCROLL
| SWT
.VIRTUAL
));
178 getList().setContentProvider(contentProvider
);
179 getList().setLabelProvider(getItemsListLabelProvider());
180 getList().setInput(new Object
[0]);
181 getList().setItemCount(contentProvider
.getNumberOfElements());
182 getList().addSelectionChangedListener(new ISelectionChangedListener() {
184 public void selectionChanged(SelectionChangedEvent event
) {
185 StructuredSelection selection
= (StructuredSelection
) event
187 currentSelection
= selection
;
190 getList().addDoubleClickListener(new IDoubleClickListener() {
192 public void doubleClick(DoubleClickEvent event
) {
196 // createExtendedContentArea(container);
197 new Label(container
, SWT
.NONE
);
203 protected void addIdentifierCheckButton(Composite searchAndFilter
) {
204 //as default do nothing
208 abstract void createFilterButton(Composite searchAndFilter
) ;
210 protected abstract void search();
214 * Sets the title for this dialog.
219 public void setTitle(String title
) {
224 * Create a new header which is labelled by headerLabel.
227 * @return Label the label of the header
229 private Label
createHeader(Composite parent
) {
230 Composite header
= new Composite(parent
, SWT
.NONE
);
231 GridData gd_header
= new GridData(SWT
.CENTER
, SWT
.CENTER
, false, false, 2, 1);
232 gd_header
.horizontalIndent
= 5;
233 gd_header
.widthHint
= 575;
234 header
.setLayoutData(gd_header
);
236 GridLayout layout
= new GridLayout();
237 layout
.marginLeft
= 5;
238 layout
.horizontalSpacing
= 0;
239 layout
.verticalSpacing
= 1;
240 layout
.marginWidth
= 0;
241 layout
.marginHeight
= 0;
242 header
.setLayout(layout
);
243 new Label(header
, SWT
.NONE
);
244 Label headerLabel
= new Label(header
, SWT
.NONE
);
245 headerLabel
.setText((getMessage() != null && getMessage().trim()
246 .length() > 0) ?
getMessage()
247 : Messages
.SearchDialog_patternLabel
);
248 headerLabel
.addTraverseListener(new TraverseListener() {
250 public void keyTraversed(TraverseEvent e
) {
251 if (e
.detail
== SWT
.TRAVERSE_MNEMONIC
&& e
.doit
) {
252 e
.detail
= SWT
.TRAVERSE_NONE
;
253 searchField
.setFocus();
257 GridData gd_headerLabel
= new GridData(GridData
.FILL_HORIZONTAL
);
258 gd_headerLabel
.horizontalAlignment
= SWT
.LEFT
;
259 gd_headerLabel
.grabExcessHorizontalSpace
= false;
260 gd_headerLabel
.verticalAlignment
= SWT
.BOTTOM
;
261 gd_headerLabel
.minimumHeight
= 10;
262 headerLabel
.setLayoutData(gd_headerLabel
);
266 protected String
getMessage() {
270 protected void setMessage(String message
){
271 this.message
= message
;
274 public Text
getSearchField() {
279 public void setSearchField(Text searchField
) {
280 this.searchField
= searchField
;
283 private ItemsListLabelProvider
getItemsListLabelProvider() {
284 if (itemsListLabelProvider
== null) {
285 itemsListLabelProvider
= new ItemsListLabelProvider(
286 new LabelProvider());
288 return itemsListLabelProvider
;
292 public TableViewer
getList() {
296 public void setList(TableViewer list
) {
298 Table table
= list
.getTable();
299 GridData gd_table
= new GridData(SWT
.CENTER
, SWT
.CENTER
, true, true, 2, 1);
300 gd_table
.heightHint
= 231;
301 gd_table
.widthHint
= 543;
302 table
.setLayoutData(gd_table
);
305 public Button
getNewButton1() {
310 public void setNewButton1(Button newButton1
) {
311 this.newButton1
= newButton1
;
315 public Button
getNewButton2() {
320 public void setNewButton2(Button newButton2
) {
321 this.newButton2
= newButton2
;
325 public Button
getFilterButton() {
330 public void setFilterButton(Button filterButton
) {
331 this.filterButton
= filterButton
;
335 * Sets a new label provider for items in the list. If the label provider
336 * also implements {@link
337 * org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider
338 * .IStyledLabelProvider}, the style text labels provided by it will be used
339 * provided that the corresponding preference is set.
341 * @see IWorkbenchPreferenceConstants#USE_COLORED_LABELS
343 * @param listLabelProvider
344 * the label provider for items in the list
346 public void setListLabelProvider(ILabelProvider listLabelProvider
) {
347 getItemsListLabelProvider().setProvider(listLabelProvider
);
349 protected Comparator
getItemsComparator() {
350 return new Comparator
<UuidAndTitleCache
>() {
352 public int compare(UuidAndTitleCache entity1
,
353 UuidAndTitleCache entity2
) {
354 Collator collator
= Collator
.getInstance();
355 if (entity1
.getUuid().equals(entity2
.getUuid())){
358 int result
= collator
.compare(entity1
.getTitleCache(), entity2
.getTitleCache());
360 result
= entity1
.getUuid().compareTo(entity2
.getUuid());
368 class ContentProvider
implements
369 IStructuredContentProvider
{
374 * Creates new instance of <code>ContentProvider</code>.
376 public ContentProvider() {
377 this.items
= Collections
.synchronizedList(new ArrayList(2048));
381 * Removes all content items and resets progress message.
383 public void reset() {
388 public void add(Object item
) {
389 this.items
.add(item
);
395 public void refresh() {
400 * Schedule refresh job.
402 public void scheduleRefresh() {
403 refreshCacheJob
.cancelAll();
404 refreshCacheJob
.schedule();
410 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
413 public Object
[] getElements(Object inputElement
) {
414 return items
.toArray();
417 public int getNumberOfElements() {
424 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
427 public void dispose() {
433 * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
434 * java.lang.Object, java.lang.Object)
437 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
444 public boolean isUseIdentifier() {
445 return useIdentifier
;
449 public StructuredSelection
getCurrentSelection() {
450 return currentSelection
;
454 * Fills the content provider with matching items.
456 * @param progressMonitor
457 * must be used to report search progress. The state of this
458 * progress monitor reflects the state of the filtering process.
459 * @throws CoreException
461 protected abstract void fillContentProvider(IProgressMonitor progressMonitor
) ;
465 * Refreshes the dialog - has to be called in UI thread.
467 public void refresh() {
468 if (getList() != null && !getList().getTable().isDisposed()) {
470 List lastRefreshSelection
= ((StructuredSelection
) getList()
471 .getSelection()).toList();
472 getList().getTable().deselectAll();
474 getList().setItemCount(contentProvider
.getNumberOfElements());
477 if (getList().getTable().getItemCount() > 0) {
478 // preserve previous selection
479 if ( lastRefreshSelection
!= null
480 && lastRefreshSelection
.size() > 0) {
481 getList().setSelection(new StructuredSelection(
482 lastRefreshSelection
));
485 getList().getTable().setSelection(0);
486 getList().getTable().notifyListeners(SWT
.Selection
, new Event());
489 getList().setSelection(StructuredSelection
.EMPTY
);
496 * A job responsible for computing filtered items list presented using
497 * <code>RefreshJob</code>.
499 * @see FilteredItemsSelectionDialog.RefreshJob
502 private class RefreshCacheJob
extends Job
{
504 public RefreshCacheJob() {
506 WorkbenchMessages
.FilteredItemsSelectionDialog_cacheRefreshJob
);
511 * Stops the job and all sub-jobs.
513 public void cancelAll() {
520 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
523 protected IStatus
run(IProgressMonitor monitor
) {
524 if (monitor
.isCanceled()) {
525 return new Status(IStatus
.CANCEL
, WorkbenchPlugin
.PI_WORKBENCH
,
526 IStatus
.CANCEL
, EMPTY_STRING
, null);
529 if (SearchDialog
.this != null) {
530 SearchDialog
.this.fillContentProvider(monitor
);
533 return new Status(IStatus
.OK
, PlatformUI
.PLUGIN_ID
, IStatus
.OK
,
541 * @see org.eclipse.core.runtime.jobs.Job#canceling()
544 protected void canceling() {
550 private class ItemsListLabelProvider
extends StyledCellLabelProvider
551 implements ILabelProviderListener
{
552 private ILabelProvider provider
;
555 * Creates a new instance of the class.
558 * the label provider for all items, not <code>null</code>
559 * @param selectionDecorator
560 * the decorator for selected items, can be <code>null</code>
562 public ItemsListLabelProvider(ILabelProvider provider
) {
563 Assert
.isNotNull(provider
);
564 this.provider
= provider
;
565 this.provider
.addListener(this);
569 * Sets new label provider.
572 * new label provider for items in the list, not
575 public void setProvider(ILabelProvider newProvider
) {
576 Assert
.isNotNull(newProvider
);
577 provider
.removeListener(this);
579 provider
= newProvider
;
581 if (provider
!= null) {
582 provider
.addListener(this);
588 private boolean isSelected(Object element
) {
589 if (element
!= null && getCurrentSelection() != null) {
590 if (element
.equals(getCurrentSelection())) {
600 * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
602 private String
getText(Object element
) {
603 if (element
instanceof ItemsListSeparator
) {
604 return getSeparatorLabel(((ItemsListSeparator
) element
)
607 String str
= provider
.getText(element
);
611 private StyledString
getStyledText(Object element
,
612 IStyledLabelProvider provider
) {
613 StyledString string
= provider
.getStyledText(element
);
619 public void update(ViewerCell cell
) {
620 Object element
= cell
.getElement();
622 if (!(element
instanceof ItemsListSeparator
)
623 && provider
instanceof IStyledLabelProvider
) {
624 IStyledLabelProvider styledLabelProvider
= (IStyledLabelProvider
) provider
;
625 StyledString styledString
= getStyledText(element
,
626 styledLabelProvider
);
628 cell
.setText(styledString
.getString());
629 cell
.setStyleRanges(styledString
.getStyleRanges());
630 cell
.setImage(styledLabelProvider
.getImage(element
));
632 cell
.setText(getText(element
));
635 cell
.setFont(getFont(element
));
636 cell
.setForeground(getForeground(element
));
637 cell
.setBackground(getBackground(element
));
642 private String
getSeparatorLabel(String separatorLabel
) {
643 Rectangle rect
= getList().getTable().getBounds();
645 int borderWidth
= getList().getTable().computeTrim(0, 0, 0, 0).width
;
647 int imageWidth
= WorkbenchImages
.getImage(
648 IWorkbenchGraphicConstants
.IMG_OBJ_SEPARATOR
).getBounds().width
;
650 int width
= rect
.width
- borderWidth
- imageWidth
;
652 GC gc
= new GC(getList().getTable());
653 gc
.setFont(getList().getTable().getFont());
655 int fSeparatorWidth
= gc
.getAdvanceWidth('-');
656 int fMessageLength
= gc
.textExtent(separatorLabel
).x
;
660 StringBuffer dashes
= new StringBuffer();
661 int chars
= (((width
- fMessageLength
) / fSeparatorWidth
) / 2) - 2;
662 for (int i
= 0; i
< chars
; i
++) {
666 StringBuffer result
= new StringBuffer();
667 result
.append(dashes
);
668 result
.append(" " + separatorLabel
+ " "); //$NON-NLS-1$//$NON-NLS-2$
669 result
.append(dashes
);
670 return result
.toString().trim();
676 * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
679 public void addListener(ILabelProviderListener listener
) {
680 listeners
.add(listener
);
686 * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
689 public void dispose() {
690 provider
.removeListener(this);
698 * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object,
702 public boolean isLabelProperty(Object element
, String property
) {
703 if (provider
.isLabelProperty(element
, property
)) {
712 * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
715 public void removeListener(ILabelProviderListener listener
) {
716 listeners
.remove(listener
);
719 private Color
getBackground(Object element
) {
720 if (element
instanceof ItemsListSeparator
) {
723 if (provider
instanceof IColorProvider
) {
724 return ((IColorProvider
) provider
).getBackground(element
);
729 private Color
getForeground(Object element
) {
730 if (element
instanceof ItemsListSeparator
) {
731 return Display
.getCurrent().getSystemColor(
732 SWT
.COLOR_WIDGET_NORMAL_SHADOW
);
734 if (provider
instanceof IColorProvider
) {
735 return ((IColorProvider
) provider
).getForeground(element
);
740 private Font
getFont(Object element
) {
741 if (element
instanceof ItemsListSeparator
) {
744 if (provider
instanceof IFontProvider
) {
745 return ((IFontProvider
) provider
).getFont(element
);
753 * @see org.eclipse.jface.viewers.ILabelProviderListener#labelProviderChanged(org.eclipse.jface.viewers.LabelProviderChangedEvent)
756 public void labelProviderChanged(LabelProviderChangedEvent event
) {
757 Object
[] l
= listeners
.getListeners();
758 for (int i
= 0; i
< listeners
.size(); i
++) {
759 ((ILabelProviderListener
) l
[i
]).labelProviderChanged(event
);
765 protected Point
getInitialSize() {
766 return new Point(593, 399);