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
.KeyAdapter
;
51 import org
.eclipse
.swt
.events
.KeyEvent
;
52 import org
.eclipse
.swt
.events
.ModifyEvent
;
53 import org
.eclipse
.swt
.events
.ModifyListener
;
54 import org
.eclipse
.swt
.events
.TraverseEvent
;
55 import org
.eclipse
.swt
.events
.TraverseListener
;
56 import org
.eclipse
.swt
.graphics
.Color
;
57 import org
.eclipse
.swt
.graphics
.Font
;
58 import org
.eclipse
.swt
.graphics
.GC
;
59 import org
.eclipse
.swt
.graphics
.Point
;
60 import org
.eclipse
.swt
.graphics
.Rectangle
;
61 import org
.eclipse
.swt
.layout
.GridData
;
62 import org
.eclipse
.swt
.layout
.GridLayout
;
63 import org
.eclipse
.swt
.widgets
.Button
;
64 import org
.eclipse
.swt
.widgets
.Composite
;
65 import org
.eclipse
.swt
.widgets
.Control
;
66 import org
.eclipse
.swt
.widgets
.Display
;
67 import org
.eclipse
.swt
.widgets
.Event
;
68 import org
.eclipse
.swt
.widgets
.Label
;
69 import org
.eclipse
.swt
.widgets
.Shell
;
70 import org
.eclipse
.swt
.widgets
.Table
;
71 import org
.eclipse
.swt
.widgets
.Text
;
72 import org
.eclipse
.ui
.IWorkbenchPreferenceConstants
;
73 import org
.eclipse
.ui
.PlatformUI
;
74 import org
.eclipse
.ui
.dialogs
.FilteredItemsSelectionDialog
;
75 import org
.eclipse
.ui
.internal
.IWorkbenchGraphicConstants
;
76 import org
.eclipse
.ui
.internal
.WorkbenchImages
;
77 import org
.eclipse
.ui
.internal
.WorkbenchMessages
;
78 import org
.eclipse
.ui
.internal
.WorkbenchPlugin
;
80 import eu
.etaxonomy
.cdm
.model
.common
.ICdmBase
;
81 import eu
.etaxonomy
.cdm
.persistence
.dto
.UuidAndTitleCache
;
82 import eu
.etaxonomy
.taxeditor
.l10n
.Messages
;
83 import eu
.etaxonomy
.taxeditor
.ui
.dialog
.selection
.CdmFilteredItemsSelectionDialog
.ItemsListSeparator
;
90 public abstract class SearchDialog
<T
extends ICdmBase
> extends Dialog
{// implements IConversationEnabled{
92 private TableViewer list
;
93 private Text searchField
;
95 protected Button newButton1
;
98 protected Button newButton2
;
99 protected Button filterButton
;
100 protected Button btnCheckButton
;
101 private StructuredSelection currentSelection
;
103 // message to show user
104 private String message
= ""; //$NON-NLS-1$
106 protected final ContentProvider contentProvider
;
107 ItemsListLabelProvider itemsListLabelProvider
;
109 private final RefreshCacheJob refreshCacheJob
;
111 protected Object preferenceID
;
113 protected final int new_id
= 4;
114 protected final int new_id2
= 5;
115 protected final int space_id
= 6;
116 // Need to keep our own list of listeners
117 private final ListenerList listeners
= new ListenerList();
120 private static final String EMPTY_STRING
= ""; //$NON-NLS-1$
121 private GridData gd_1
;
122 protected boolean useIdentifier
;
124 public SearchDialog(Shell parent
, boolean multi
) {
126 contentProvider
= new ContentProvider();
127 refreshCacheJob
= new RefreshCacheJob();
134 protected Control
createDialogArea(Composite parent
) {
135 Composite container
= (Composite
) super.createDialogArea(parent
);
137 GridData gd
= new GridData(GridData
.FILL_BOTH
);
138 container
.setLayoutData(gd
);
140 GridLayout layout
= new GridLayout();
141 layout
.numColumns
= 1;
142 layout
.marginWidth
= 0;
143 layout
.marginHeight
= 0;
144 container
.setLayout(layout
);
146 final Label headerLabel
= createHeader(container
);
148 Composite searchAndFilter
= new Composite(container
, container
.getStyle());
150 searchAndFilter
.setLayoutData(new GridData(GridData
.GRAB_HORIZONTAL
| GridData
.HORIZONTAL_ALIGN_FILL
));
151 GridLayout searchAndFilterLayout
= new GridLayout();
152 searchAndFilterLayout
.numColumns
= 2;
153 searchAndFilter
.setLayout(searchAndFilterLayout
);
154 searchField
= new Text(searchAndFilter
, SWT
.SINGLE
| SWT
.BORDER
| SWT
.SEARCH
| SWT
.ICON_CANCEL
);
155 searchField
.getAccessible().addAccessibleListener(new AccessibleAdapter() {
157 public void getName(AccessibleEvent e
) {
158 e
.result
= LegacyActionTools
.removeMnemonics(headerLabel
162 searchField
.addModifyListener(new ModifyListener() {
164 public void modifyText(ModifyEvent e
) {
166 // fillContentProvider(null);
170 gd_1
= new GridData(GridData
.GRAB_HORIZONTAL
| GridData
.HORIZONTAL_ALIGN_FILL
);
171 gd_1
.horizontalIndent
= 7;
173 searchField
.setLayoutData(gd_1
);
175 createFilterButton(searchAndFilter
);
177 addIdentifierCheckButton(searchAndFilter
);
178 // new Label(searchAndFilter, SWT.NONE);
179 setList(new TableViewer(container
, SWT
.SINGLE
180 | SWT
.BORDER
| SWT
.V_SCROLL
| SWT
.VIRTUAL
));
182 getList().setContentProvider(contentProvider
);
183 getList().setLabelProvider(getItemsListLabelProvider());
184 getList().setInput(new Object
[0]);
185 getList().setItemCount(contentProvider
.getNumberOfElements());
186 getList().addSelectionChangedListener(new ISelectionChangedListener() {
188 public void selectionChanged(SelectionChangedEvent event
) {
189 StructuredSelection selection
= (StructuredSelection
) event
191 currentSelection
= selection
;
194 getList().addDoubleClickListener(new IDoubleClickListener() {
196 public void doubleClick(DoubleClickEvent event
) {
200 searchField
.addKeyListener(new KeyAdapter() {
202 public void keyPressed(KeyEvent e
) {
203 if (e
.keyCode
== SWT
.ARROW_DOWN
) {
204 if (getList().getTable().getItemCount() > 0) {
205 getList().getTable().setFocus();
211 // createExtendedContentArea(container);
212 new Label(container
, SWT
.NONE
);
219 protected void addIdentifierCheckButton(Composite searchAndFilter
) {
220 //as default do nothing
224 abstract void createFilterButton(Composite searchAndFilter
) ;
226 protected abstract void search();
230 * Sets the title for this dialog.
235 public void setTitle(String title
) {
240 * Create a new header which is labelled by headerLabel.
243 * @return Label the label of the header
245 private Label
createHeader(Composite parent
) {
246 Composite header
= new Composite(parent
, SWT
.NONE
);
247 GridData gd_header
= new GridData(SWT
.CENTER
, SWT
.CENTER
, false, false, 2, 1);
248 gd_header
.horizontalIndent
= 5;
249 gd_header
.widthHint
= 575;
250 header
.setLayoutData(gd_header
);
252 GridLayout layout
= new GridLayout();
253 layout
.marginLeft
= 5;
254 layout
.horizontalSpacing
= 0;
255 layout
.verticalSpacing
= 1;
256 layout
.marginWidth
= 0;
257 layout
.marginHeight
= 0;
258 header
.setLayout(layout
);
259 new Label(header
, SWT
.NONE
);
260 Label headerLabel
= new Label(header
, SWT
.NONE
);
261 headerLabel
.setText((getMessage() != null && getMessage().trim()
262 .length() > 0) ?
getMessage()
263 : Messages
.SearchDialog_patternLabel
);
264 headerLabel
.addTraverseListener(new TraverseListener() {
266 public void keyTraversed(TraverseEvent e
) {
267 if (e
.detail
== SWT
.TRAVERSE_MNEMONIC
&& e
.doit
) {
268 e
.detail
= SWT
.TRAVERSE_NONE
;
269 searchField
.setFocus();
273 GridData gd_headerLabel
= new GridData(GridData
.FILL_HORIZONTAL
);
274 gd_headerLabel
.horizontalAlignment
= SWT
.LEFT
;
275 gd_headerLabel
.grabExcessHorizontalSpace
= false;
276 gd_headerLabel
.verticalAlignment
= SWT
.BOTTOM
;
277 gd_headerLabel
.minimumHeight
= 10;
278 headerLabel
.setLayoutData(gd_headerLabel
);
282 protected String
getMessage() {
286 protected void setMessage(String message
){
287 this.message
= message
;
290 public Text
getSearchField() {
295 public void setSearchField(Text searchField
) {
296 this.searchField
= searchField
;
299 private ItemsListLabelProvider
getItemsListLabelProvider() {
300 if (itemsListLabelProvider
== null) {
301 itemsListLabelProvider
= new ItemsListLabelProvider(
302 new LabelProvider());
304 return itemsListLabelProvider
;
308 public TableViewer
getList() {
312 public void setList(TableViewer list
) {
314 Table table
= list
.getTable();
315 GridData gd_table
= new GridData(SWT
.CENTER
, SWT
.CENTER
, true, true, 2, 1);
316 gd_table
.heightHint
= 231;
317 gd_table
.widthHint
= 543;
318 table
.setLayoutData(gd_table
);
321 public Button
getNewButton1() {
326 public void setNewButton1(Button newButton1
) {
327 this.newButton1
= newButton1
;
331 public Button
getNewButton2() {
336 public void setNewButton2(Button newButton2
) {
337 this.newButton2
= newButton2
;
341 public Button
getFilterButton() {
346 public void setFilterButton(Button filterButton
) {
347 this.filterButton
= filterButton
;
351 * Sets a new label provider for items in the list. If the label provider
352 * also implements {@link
353 * org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider
354 * .IStyledLabelProvider}, the style text labels provided by it will be used
355 * provided that the corresponding preference is set.
357 * @see IWorkbenchPreferenceConstants#USE_COLORED_LABELS
359 * @param listLabelProvider
360 * the label provider for items in the list
362 public void setListLabelProvider(ILabelProvider listLabelProvider
) {
363 getItemsListLabelProvider().setProvider(listLabelProvider
);
365 protected Comparator
getItemsComparator() {
366 return new Comparator
<UuidAndTitleCache
>() {
368 public int compare(UuidAndTitleCache entity1
,
369 UuidAndTitleCache entity2
) {
370 Collator collator
= Collator
.getInstance();
371 if (entity1
.getUuid().equals(entity2
.getUuid())){
374 int result
= collator
.compare(entity1
.getTitleCache(), entity2
.getTitleCache());
376 result
= entity1
.getUuid().compareTo(entity2
.getUuid());
384 class ContentProvider
implements
385 IStructuredContentProvider
{
390 * Creates new instance of <code>ContentProvider</code>.
392 public ContentProvider() {
393 this.items
= Collections
.synchronizedList(new ArrayList(2048));
397 * Removes all content items and resets progress message.
399 public void reset() {
404 public void add(Object item
) {
405 this.items
.add(item
);
411 public void refresh() {
416 * Schedule refresh job.
418 public void scheduleRefresh() {
419 refreshCacheJob
.cancelAll();
420 refreshCacheJob
.schedule();
426 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
429 public Object
[] getElements(Object inputElement
) {
430 return items
.toArray();
433 public int getNumberOfElements() {
440 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
443 public void dispose() {
449 * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
450 * java.lang.Object, java.lang.Object)
453 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
460 public boolean isUseIdentifier() {
461 return useIdentifier
;
465 public StructuredSelection
getCurrentSelection() {
466 return currentSelection
;
470 * Fills the content provider with matching items.
472 * @param progressMonitor
473 * must be used to report search progress. The state of this
474 * progress monitor reflects the state of the filtering process.
475 * @throws CoreException
477 protected abstract void fillContentProvider(IProgressMonitor progressMonitor
) ;
481 * Refreshes the dialog - has to be called in UI thread.
483 public void refresh() {
484 if (getList() != null && !getList().getTable().isDisposed()) {
486 List lastRefreshSelection
= ((StructuredSelection
) getList()
487 .getSelection()).toList();
488 getList().getTable().deselectAll();
490 getList().setItemCount(contentProvider
.getNumberOfElements());
493 if (getList().getTable().getItemCount() > 0) {
494 // preserve previous selection
495 if ( lastRefreshSelection
!= null
496 && lastRefreshSelection
.size() > 0) {
497 getList().setSelection(new StructuredSelection(
498 lastRefreshSelection
));
501 getList().getTable().setSelection(0);
502 getList().getTable().notifyListeners(SWT
.Selection
, new Event());
505 getList().setSelection(StructuredSelection
.EMPTY
);
512 * A job responsible for computing filtered items list presented using
513 * <code>RefreshJob</code>.
515 * @see FilteredItemsSelectionDialog.RefreshJob
518 private class RefreshCacheJob
extends Job
{
520 public RefreshCacheJob() {
522 WorkbenchMessages
.FilteredItemsSelectionDialog_cacheRefreshJob
);
527 * Stops the job and all sub-jobs.
529 public void cancelAll() {
536 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
539 protected IStatus
run(IProgressMonitor monitor
) {
540 if (monitor
.isCanceled()) {
541 return new Status(IStatus
.CANCEL
, WorkbenchPlugin
.PI_WORKBENCH
,
542 IStatus
.CANCEL
, EMPTY_STRING
, null);
545 if (SearchDialog
.this != null) {
546 SearchDialog
.this.fillContentProvider(monitor
);
549 return new Status(IStatus
.OK
, PlatformUI
.PLUGIN_ID
, IStatus
.OK
,
557 * @see org.eclipse.core.runtime.jobs.Job#canceling()
560 protected void canceling() {
566 private class ItemsListLabelProvider
extends StyledCellLabelProvider
567 implements ILabelProviderListener
{
568 private ILabelProvider provider
;
571 * Creates a new instance of the class.
574 * the label provider for all items, not <code>null</code>
575 * @param selectionDecorator
576 * the decorator for selected items, can be <code>null</code>
578 public ItemsListLabelProvider(ILabelProvider provider
) {
579 Assert
.isNotNull(provider
);
580 this.provider
= provider
;
581 this.provider
.addListener(this);
585 * Sets new label provider.
588 * new label provider for items in the list, not
591 public void setProvider(ILabelProvider newProvider
) {
592 Assert
.isNotNull(newProvider
);
593 provider
.removeListener(this);
595 provider
= newProvider
;
597 if (provider
!= null) {
598 provider
.addListener(this);
604 private boolean isSelected(Object element
) {
605 if (element
!= null && getCurrentSelection() != null) {
606 if (element
.equals(getCurrentSelection())) {
616 * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
618 private String
getText(Object element
) {
619 if (element
instanceof ItemsListSeparator
) {
620 return getSeparatorLabel(((ItemsListSeparator
) element
)
623 String str
= provider
.getText(element
);
627 private StyledString
getStyledText(Object element
,
628 IStyledLabelProvider provider
) {
629 StyledString string
= provider
.getStyledText(element
);
635 public void update(ViewerCell cell
) {
636 Object element
= cell
.getElement();
638 if (!(element
instanceof ItemsListSeparator
)
639 && provider
instanceof IStyledLabelProvider
) {
640 IStyledLabelProvider styledLabelProvider
= (IStyledLabelProvider
) provider
;
641 StyledString styledString
= getStyledText(element
,
642 styledLabelProvider
);
644 cell
.setText(styledString
.getString());
645 cell
.setStyleRanges(styledString
.getStyleRanges());
646 cell
.setImage(styledLabelProvider
.getImage(element
));
648 cell
.setText(getText(element
));
651 cell
.setFont(getFont(element
));
652 cell
.setForeground(getForeground(element
));
653 cell
.setBackground(getBackground(element
));
658 private String
getSeparatorLabel(String separatorLabel
) {
659 Rectangle rect
= getList().getTable().getBounds();
661 int borderWidth
= getList().getTable().computeTrim(0, 0, 0, 0).width
;
663 int imageWidth
= WorkbenchImages
.getImage(
664 IWorkbenchGraphicConstants
.IMG_OBJ_SEPARATOR
).getBounds().width
;
666 int width
= rect
.width
- borderWidth
- imageWidth
;
668 GC gc
= new GC(getList().getTable());
669 gc
.setFont(getList().getTable().getFont());
671 int fSeparatorWidth
= gc
.getAdvanceWidth('-');
672 int fMessageLength
= gc
.textExtent(separatorLabel
).x
;
676 StringBuffer dashes
= new StringBuffer();
677 int chars
= (((width
- fMessageLength
) / fSeparatorWidth
) / 2) - 2;
678 for (int i
= 0; i
< chars
; i
++) {
682 StringBuffer result
= new StringBuffer();
683 result
.append(dashes
);
684 result
.append(" " + separatorLabel
+ " "); //$NON-NLS-1$//$NON-NLS-2$
685 result
.append(dashes
);
686 return result
.toString().trim();
692 * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
695 public void addListener(ILabelProviderListener listener
) {
696 listeners
.add(listener
);
702 * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
705 public void dispose() {
706 provider
.removeListener(this);
714 * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object,
718 public boolean isLabelProperty(Object element
, String property
) {
719 if (provider
.isLabelProperty(element
, property
)) {
728 * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
731 public void removeListener(ILabelProviderListener listener
) {
732 listeners
.remove(listener
);
735 private Color
getBackground(Object element
) {
736 if (element
instanceof ItemsListSeparator
) {
739 if (provider
instanceof IColorProvider
) {
740 return ((IColorProvider
) provider
).getBackground(element
);
745 private Color
getForeground(Object element
) {
746 if (element
instanceof ItemsListSeparator
) {
747 return Display
.getCurrent().getSystemColor(
748 SWT
.COLOR_WIDGET_NORMAL_SHADOW
);
750 if (provider
instanceof IColorProvider
) {
751 return ((IColorProvider
) provider
).getForeground(element
);
756 private Font
getFont(Object element
) {
757 if (element
instanceof ItemsListSeparator
) {
760 if (provider
instanceof IFontProvider
) {
761 return ((IFontProvider
) provider
).getFont(element
);
769 * @see org.eclipse.jface.viewers.ILabelProviderListener#labelProviderChanged(org.eclipse.jface.viewers.LabelProviderChangedEvent)
772 public void labelProviderChanged(LabelProviderChangedEvent event
) {
773 Object
[] l
= listeners
.getListeners();
774 for (int i
= 0; i
< listeners
.size(); i
++) {
775 ((ILabelProviderListener
) l
[i
]).labelProviderChanged(event
);
781 protected Point
getInitialSize() {
782 return new Point(593, 399);