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 private StructuredSelection currentSelection
;
100 // message to show user
101 private String message
= ""; //$NON-NLS-1$
103 protected final ContentProvider contentProvider
;
104 ItemsListLabelProvider itemsListLabelProvider
;
106 private final RefreshCacheJob refreshCacheJob
;
108 protected Object preferenceID
;
110 protected final int new_id
= 4;
111 protected final int new_id2
= 5;
112 // Need to keep our own list of listeners
113 private final ListenerList listeners
= new ListenerList();
116 private static final String EMPTY_STRING
= ""; //$NON-NLS-1$
117 private GridData gd_1
;
119 public SearchDialog(Shell parent
, boolean multi
) {
121 contentProvider
= new ContentProvider();
122 refreshCacheJob
= new RefreshCacheJob();
129 protected Control
createDialogArea(Composite parent
) {
130 Composite container
= (Composite
) super.createDialogArea(parent
);
132 GridData gd
= new GridData(GridData
.FILL_BOTH
);
133 container
.setLayoutData(gd
);
135 GridLayout layout
= new GridLayout();
136 layout
.numColumns
= 1;
137 layout
.marginWidth
= 0;
138 layout
.marginHeight
= 0;
139 container
.setLayout(layout
);
141 final Label headerLabel
= createHeader(container
);
143 Composite searchAndFilter
= new Composite(container
, container
.getStyle());
144 GridData gd_searchAndFilter
=new GridData(GridData
.GRAB_HORIZONTAL
| GridData
.HORIZONTAL_ALIGN_FILL
);
146 searchAndFilter
.setLayoutData(gd_searchAndFilter
);
147 GridLayout searchAndFilterLayout
= new GridLayout();
148 searchAndFilterLayout
.numColumns
= 2;
149 searchAndFilter
.setLayout(searchAndFilterLayout
);
150 searchField
= new Text(searchAndFilter
, SWT
.SINGLE
| SWT
.BORDER
| SWT
.SEARCH
| SWT
.ICON_CANCEL
);
151 searchField
.getAccessible().addAccessibleListener(new AccessibleAdapter() {
153 public void getName(AccessibleEvent e
) {
154 e
.result
= LegacyActionTools
.removeMnemonics(headerLabel
158 searchField
.addModifyListener(new ModifyListener() {
160 public void modifyText(ModifyEvent e
) {
162 fillContentProvider(null);
166 gd_1
= new GridData(GridData
.GRAB_HORIZONTAL
| GridData
.HORIZONTAL_ALIGN_FILL
);
168 searchField
.setLayoutData(gd_1
);
170 createFilterButton(searchAndFilter
);
171 new Label(searchAndFilter
, SWT
.NONE
);
172 setList(new TableViewer(container
, SWT
.SINGLE
173 | SWT
.BORDER
| SWT
.V_SCROLL
| SWT
.VIRTUAL
));
175 getList().setContentProvider(contentProvider
);
176 getList().setLabelProvider(getItemsListLabelProvider());
177 getList().setInput(new Object
[0]);
178 getList().setItemCount(contentProvider
.getNumberOfElements());
179 getList().addSelectionChangedListener(new ISelectionChangedListener() {
181 public void selectionChanged(SelectionChangedEvent event
) {
182 StructuredSelection selection
= (StructuredSelection
) event
184 currentSelection
= selection
;
187 getList().addDoubleClickListener(new IDoubleClickListener() {
189 public void doubleClick(DoubleClickEvent event
) {
193 // createExtendedContentArea(container);
194 new Label(container
, SWT
.NONE
);
200 abstract void createFilterButton(Composite searchAndFilter
) ;
202 protected abstract void search();
206 * Sets the title for this dialog.
211 public void setTitle(String title
) {
216 * Create a new header which is labelled by headerLabel.
219 * @return Label the label of the header
221 private Label
createHeader(Composite parent
) {
222 Composite header
= new Composite(parent
, SWT
.NONE
);
223 GridData gd_header
= new GridData(SWT
.CENTER
, SWT
.CENTER
, false, false, 2, 1);
224 gd_header
.horizontalIndent
= 5;
225 gd_header
.widthHint
= 575;
226 header
.setLayoutData(gd_header
);
228 GridLayout layout
= new GridLayout();
229 layout
.marginLeft
= 5;
230 layout
.horizontalSpacing
= 0;
231 layout
.verticalSpacing
= 1;
232 layout
.marginWidth
= 0;
233 layout
.marginHeight
= 0;
234 header
.setLayout(layout
);
235 new Label(header
, SWT
.NONE
);
236 Label headerLabel
= new Label(header
, SWT
.NONE
);
237 headerLabel
.setText((getMessage() != null && getMessage().trim()
238 .length() > 0) ?
getMessage()
239 : Messages
.SearchDialog_patternLabel
);
240 headerLabel
.addTraverseListener(new TraverseListener() {
242 public void keyTraversed(TraverseEvent e
) {
243 if (e
.detail
== SWT
.TRAVERSE_MNEMONIC
&& e
.doit
) {
244 e
.detail
= SWT
.TRAVERSE_NONE
;
245 searchField
.setFocus();
249 GridData gd_headerLabel
= new GridData(GridData
.FILL_HORIZONTAL
);
250 gd_headerLabel
.horizontalAlignment
= SWT
.LEFT
;
251 gd_headerLabel
.grabExcessHorizontalSpace
= false;
252 gd_headerLabel
.verticalAlignment
= SWT
.BOTTOM
;
253 gd_headerLabel
.minimumHeight
= 10;
254 headerLabel
.setLayoutData(gd_headerLabel
);
258 protected String
getMessage() {
262 protected void setMessage(String message
){
263 this.message
= message
;
266 public Text
getSearchField() {
271 public void setSearchField(Text searchField
) {
272 this.searchField
= searchField
;
275 private ItemsListLabelProvider
getItemsListLabelProvider() {
276 if (itemsListLabelProvider
== null) {
277 itemsListLabelProvider
= new ItemsListLabelProvider(
278 new LabelProvider());
280 return itemsListLabelProvider
;
284 public TableViewer
getList() {
288 public void setList(TableViewer list
) {
290 Table table
= list
.getTable();
291 GridData gd_table
= new GridData(SWT
.CENTER
, SWT
.CENTER
, true, true, 2, 1);
292 gd_table
.heightHint
= 231;
293 gd_table
.widthHint
= 543;
294 table
.setLayoutData(gd_table
);
297 public Button
getNewButton1() {
302 public void setNewButton1(Button newButton1
) {
303 this.newButton1
= newButton1
;
307 public Button
getNewButton2() {
312 public void setNewButton2(Button newButton2
) {
313 this.newButton2
= newButton2
;
317 public Button
getFilterButton() {
322 public void setFilterButton(Button filterButton
) {
323 this.filterButton
= filterButton
;
327 * Sets a new label provider for items in the list. If the label provider
328 * also implements {@link
329 * org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider
330 * .IStyledLabelProvider}, the style text labels provided by it will be used
331 * provided that the corresponding preference is set.
333 * @see IWorkbenchPreferenceConstants#USE_COLORED_LABELS
335 * @param listLabelProvider
336 * the label provider for items in the list
338 public void setListLabelProvider(ILabelProvider listLabelProvider
) {
339 getItemsListLabelProvider().setProvider(listLabelProvider
);
341 protected Comparator
getItemsComparator() {
342 return new Comparator
<UuidAndTitleCache
>() {
344 public int compare(UuidAndTitleCache entity1
,
345 UuidAndTitleCache entity2
) {
346 Collator collator
= Collator
.getInstance();
347 if (entity1
.getUuid().equals(entity2
.getUuid())){
350 int result
= collator
.compare(entity1
.getTitleCache(), entity2
.getTitleCache());
352 result
= entity1
.getUuid().compareTo(entity2
.getUuid());
360 class ContentProvider
implements
361 IStructuredContentProvider
{
366 * Creates new instance of <code>ContentProvider</code>.
368 public ContentProvider() {
369 this.items
= Collections
.synchronizedList(new ArrayList(2048));
373 * Removes all content items and resets progress message.
375 public void reset() {
380 public void add(Object item
) {
381 this.items
.add(item
);
387 public void refresh() {
392 * Schedule refresh job.
394 public void scheduleRefresh() {
395 refreshCacheJob
.cancelAll();
396 refreshCacheJob
.schedule();
402 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
405 public Object
[] getElements(Object inputElement
) {
406 return items
.toArray();
409 public int getNumberOfElements() {
416 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
419 public void dispose() {
425 * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
426 * java.lang.Object, java.lang.Object)
429 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
437 public StructuredSelection
getCurrentSelection() {
438 return currentSelection
;
442 * Fills the content provider with matching items.
444 * @param progressMonitor
445 * must be used to report search progress. The state of this
446 * progress monitor reflects the state of the filtering process.
447 * @throws CoreException
449 protected abstract void fillContentProvider(IProgressMonitor progressMonitor
) ;
453 * Refreshes the dialog - has to be called in UI thread.
455 public void refresh() {
456 if (getList() != null && !getList().getTable().isDisposed()) {
458 List lastRefreshSelection
= ((StructuredSelection
) getList()
459 .getSelection()).toList();
460 getList().getTable().deselectAll();
462 getList().setItemCount(contentProvider
.getNumberOfElements());
465 if (getList().getTable().getItemCount() > 0) {
466 // preserve previous selection
467 if ( lastRefreshSelection
!= null
468 && lastRefreshSelection
.size() > 0) {
469 getList().setSelection(new StructuredSelection(
470 lastRefreshSelection
));
473 getList().getTable().setSelection(0);
474 getList().getTable().notifyListeners(SWT
.Selection
, new Event());
477 getList().setSelection(StructuredSelection
.EMPTY
);
484 * A job responsible for computing filtered items list presented using
485 * <code>RefreshJob</code>.
487 * @see FilteredItemsSelectionDialog.RefreshJob
490 private class RefreshCacheJob
extends Job
{
492 public RefreshCacheJob() {
494 WorkbenchMessages
.FilteredItemsSelectionDialog_cacheRefreshJob
);
499 * Stops the job and all sub-jobs.
501 public void cancelAll() {
508 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
511 protected IStatus
run(IProgressMonitor monitor
) {
512 if (monitor
.isCanceled()) {
513 return new Status(IStatus
.CANCEL
, WorkbenchPlugin
.PI_WORKBENCH
,
514 IStatus
.CANCEL
, EMPTY_STRING
, null);
517 if (SearchDialog
.this != null) {
518 SearchDialog
.this.fillContentProvider(monitor
);
521 return new Status(IStatus
.OK
, PlatformUI
.PLUGIN_ID
, IStatus
.OK
,
529 * @see org.eclipse.core.runtime.jobs.Job#canceling()
532 protected void canceling() {
538 private class ItemsListLabelProvider
extends StyledCellLabelProvider
539 implements ILabelProviderListener
{
540 private ILabelProvider provider
;
543 * Creates a new instance of the class.
546 * the label provider for all items, not <code>null</code>
547 * @param selectionDecorator
548 * the decorator for selected items, can be <code>null</code>
550 public ItemsListLabelProvider(ILabelProvider provider
) {
551 Assert
.isNotNull(provider
);
552 this.provider
= provider
;
553 this.provider
.addListener(this);
557 * Sets new label provider.
560 * new label provider for items in the list, not
563 public void setProvider(ILabelProvider newProvider
) {
564 Assert
.isNotNull(newProvider
);
565 provider
.removeListener(this);
567 provider
= newProvider
;
569 if (provider
!= null) {
570 provider
.addListener(this);
576 private boolean isSelected(Object element
) {
577 if (element
!= null && getCurrentSelection() != null) {
578 if (element
.equals(getCurrentSelection())) {
588 * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
590 private String
getText(Object element
) {
591 if (element
instanceof ItemsListSeparator
) {
592 return getSeparatorLabel(((ItemsListSeparator
) element
)
595 String str
= provider
.getText(element
);
599 private StyledString
getStyledText(Object element
,
600 IStyledLabelProvider provider
) {
601 StyledString string
= provider
.getStyledText(element
);
607 public void update(ViewerCell cell
) {
608 Object element
= cell
.getElement();
610 if (!(element
instanceof ItemsListSeparator
)
611 && provider
instanceof IStyledLabelProvider
) {
612 IStyledLabelProvider styledLabelProvider
= (IStyledLabelProvider
) provider
;
613 StyledString styledString
= getStyledText(element
,
614 styledLabelProvider
);
616 cell
.setText(styledString
.getString());
617 cell
.setStyleRanges(styledString
.getStyleRanges());
618 cell
.setImage(styledLabelProvider
.getImage(element
));
620 cell
.setText(getText(element
));
623 cell
.setFont(getFont(element
));
624 cell
.setForeground(getForeground(element
));
625 cell
.setBackground(getBackground(element
));
630 private String
getSeparatorLabel(String separatorLabel
) {
631 Rectangle rect
= getList().getTable().getBounds();
633 int borderWidth
= getList().getTable().computeTrim(0, 0, 0, 0).width
;
635 int imageWidth
= WorkbenchImages
.getImage(
636 IWorkbenchGraphicConstants
.IMG_OBJ_SEPARATOR
).getBounds().width
;
638 int width
= rect
.width
- borderWidth
- imageWidth
;
640 GC gc
= new GC(getList().getTable());
641 gc
.setFont(getList().getTable().getFont());
643 int fSeparatorWidth
= gc
.getAdvanceWidth('-');
644 int fMessageLength
= gc
.textExtent(separatorLabel
).x
;
648 StringBuffer dashes
= new StringBuffer();
649 int chars
= (((width
- fMessageLength
) / fSeparatorWidth
) / 2) - 2;
650 for (int i
= 0; i
< chars
; i
++) {
654 StringBuffer result
= new StringBuffer();
655 result
.append(dashes
);
656 result
.append(" " + separatorLabel
+ " "); //$NON-NLS-1$//$NON-NLS-2$
657 result
.append(dashes
);
658 return result
.toString().trim();
664 * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
667 public void addListener(ILabelProviderListener listener
) {
668 listeners
.add(listener
);
674 * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
677 public void dispose() {
678 provider
.removeListener(this);
686 * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object,
690 public boolean isLabelProperty(Object element
, String property
) {
691 if (provider
.isLabelProperty(element
, property
)) {
700 * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
703 public void removeListener(ILabelProviderListener listener
) {
704 listeners
.remove(listener
);
707 private Color
getBackground(Object element
) {
708 if (element
instanceof ItemsListSeparator
) {
711 if (provider
instanceof IColorProvider
) {
712 return ((IColorProvider
) provider
).getBackground(element
);
717 private Color
getForeground(Object element
) {
718 if (element
instanceof ItemsListSeparator
) {
719 return Display
.getCurrent().getSystemColor(
720 SWT
.COLOR_WIDGET_NORMAL_SHADOW
);
722 if (provider
instanceof IColorProvider
) {
723 return ((IColorProvider
) provider
).getForeground(element
);
728 private Font
getFont(Object element
) {
729 if (element
instanceof ItemsListSeparator
) {
732 if (provider
instanceof IFontProvider
) {
733 return ((IFontProvider
) provider
).getFont(element
);
741 * @see org.eclipse.jface.viewers.ILabelProviderListener#labelProviderChanged(org.eclipse.jface.viewers.LabelProviderChangedEvent)
744 public void labelProviderChanged(LabelProviderChangedEvent event
) {
745 Object
[] l
= listeners
.getListeners();
746 for (int i
= 0; i
< listeners
.size(); i
++) {
747 ((ILabelProviderListener
) l
[i
]).labelProviderChanged(event
);
753 protected Point
getInitialSize() {
754 return new Point(593, 399);