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
.dialogs
.IDialogConstants
;
30 import org
.eclipse
.jface
.viewers
.DelegatingStyledCellLabelProvider
.IStyledLabelProvider
;
31 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
32 import org
.eclipse
.jface
.viewers
.IColorProvider
;
33 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
34 import org
.eclipse
.jface
.viewers
.IFontProvider
;
35 import org
.eclipse
.jface
.viewers
.ILabelProvider
;
36 import org
.eclipse
.jface
.viewers
.ILabelProviderListener
;
37 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
38 import org
.eclipse
.jface
.viewers
.IStructuredContentProvider
;
39 import org
.eclipse
.jface
.viewers
.LabelProvider
;
40 import org
.eclipse
.jface
.viewers
.LabelProviderChangedEvent
;
41 import org
.eclipse
.jface
.viewers
.SelectionChangedEvent
;
42 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
43 import org
.eclipse
.jface
.viewers
.StyledCellLabelProvider
;
44 import org
.eclipse
.jface
.viewers
.StyledString
;
45 import org
.eclipse
.jface
.viewers
.TableViewer
;
46 import org
.eclipse
.jface
.viewers
.Viewer
;
47 import org
.eclipse
.jface
.viewers
.ViewerCell
;
48 import org
.eclipse
.swt
.SWT
;
49 import org
.eclipse
.swt
.accessibility
.AccessibleAdapter
;
50 import org
.eclipse
.swt
.accessibility
.AccessibleEvent
;
51 import org
.eclipse
.swt
.events
.KeyAdapter
;
52 import org
.eclipse
.swt
.events
.KeyEvent
;
53 import org
.eclipse
.swt
.events
.ModifyEvent
;
54 import org
.eclipse
.swt
.events
.ModifyListener
;
55 import org
.eclipse
.swt
.events
.TraverseEvent
;
56 import org
.eclipse
.swt
.events
.TraverseListener
;
57 import org
.eclipse
.swt
.graphics
.Color
;
58 import org
.eclipse
.swt
.graphics
.Font
;
59 import org
.eclipse
.swt
.graphics
.GC
;
60 import org
.eclipse
.swt
.graphics
.Point
;
61 import org
.eclipse
.swt
.graphics
.Rectangle
;
62 import org
.eclipse
.swt
.layout
.GridData
;
63 import org
.eclipse
.swt
.layout
.GridLayout
;
64 import org
.eclipse
.swt
.widgets
.Button
;
65 import org
.eclipse
.swt
.widgets
.Composite
;
66 import org
.eclipse
.swt
.widgets
.Control
;
67 import org
.eclipse
.swt
.widgets
.Display
;
68 import org
.eclipse
.swt
.widgets
.Event
;
69 import org
.eclipse
.swt
.widgets
.Label
;
70 import org
.eclipse
.swt
.widgets
.Shell
;
71 import org
.eclipse
.swt
.widgets
.Table
;
72 import org
.eclipse
.swt
.widgets
.Text
;
73 import org
.eclipse
.ui
.IWorkbenchPreferenceConstants
;
74 import org
.eclipse
.ui
.PlatformUI
;
75 import org
.eclipse
.ui
.dialogs
.FilteredItemsSelectionDialog
;
76 import org
.eclipse
.ui
.internal
.IWorkbenchGraphicConstants
;
77 import org
.eclipse
.ui
.internal
.WorkbenchImages
;
78 import org
.eclipse
.ui
.internal
.WorkbenchMessages
;
79 import org
.eclipse
.ui
.internal
.WorkbenchPlugin
;
81 import eu
.etaxonomy
.cdm
.model
.common
.ICdmBase
;
82 import eu
.etaxonomy
.cdm
.persistence
.dto
.UuidAndTitleCache
;
83 import eu
.etaxonomy
.taxeditor
.l10n
.Messages
;
84 import eu
.etaxonomy
.taxeditor
.ui
.dialog
.selection
.CdmFilteredItemsSelectionDialog
.ItemsListSeparator
;
91 public abstract class SearchDialog
<T
extends ICdmBase
> extends Dialog
{// implements IConversationEnabled{
93 private TableViewer list
;
94 private Text searchField
;
96 protected Button newButton1
;
99 protected Button newButton2
;
100 protected Button filterButton
;
101 protected Button btnCheckButton
;
102 private StructuredSelection currentSelection
;
104 // message to show user
105 private String message
= ""; //$NON-NLS-1$
107 protected final ContentProvider contentProvider
;
108 ItemsListLabelProvider itemsListLabelProvider
;
110 private final RefreshCacheJob refreshCacheJob
;
112 protected Object preferenceID
;
114 protected final int new_id
= 4;
115 protected final int new_id2
= 5;
116 protected final int space_id
= 6;
117 // Need to keep our own list of listeners
118 private final ListenerList listeners
= new ListenerList();
121 private static final String EMPTY_STRING
= ""; //$NON-NLS-1$
122 private GridData gd_1
;
123 protected boolean useIdentifier
;
125 public SearchDialog(Shell parent
, String title
) {
128 contentProvider
= new ContentProvider();
129 refreshCacheJob
= new RefreshCacheJob();
134 protected void configureShell(Shell shell
) {
135 super.configureShell(shell
);
136 shell
.setText(title
);
140 protected Control
createDialogArea(Composite parent
) {
141 Composite container
= (Composite
) super.createDialogArea(parent
);
143 GridData gd
= new GridData(GridData
.FILL_BOTH
);
144 container
.setLayoutData(gd
);
146 GridLayout layout
= new GridLayout();
147 layout
.numColumns
= 1;
148 layout
.marginWidth
= 0;
149 layout
.marginHeight
= 0;
150 container
.setLayout(layout
);
152 final Label headerLabel
= createHeader(container
);
154 Composite searchAndFilter
= new Composite(container
, container
.getStyle());
156 searchAndFilter
.setLayoutData(new GridData(GridData
.GRAB_HORIZONTAL
| GridData
.HORIZONTAL_ALIGN_FILL
));
157 GridLayout searchAndFilterLayout
= new GridLayout();
158 searchAndFilterLayout
.numColumns
= 2;
159 searchAndFilter
.setLayout(searchAndFilterLayout
);
160 searchField
= new Text(searchAndFilter
, SWT
.SINGLE
| SWT
.BORDER
| SWT
.SEARCH
| SWT
.ICON_CANCEL
);
161 searchField
.getAccessible().addAccessibleListener(new AccessibleAdapter() {
163 public void getName(AccessibleEvent e
) {
164 e
.result
= LegacyActionTools
.removeMnemonics(headerLabel
168 searchField
.addModifyListener(new ModifyListener() {
170 public void modifyText(ModifyEvent e
) {
172 // fillContentProvider(null);
176 gd_1
= new GridData(GridData
.GRAB_HORIZONTAL
| GridData
.HORIZONTAL_ALIGN_FILL
);
177 gd_1
.horizontalIndent
= 7;
179 searchField
.setLayoutData(gd_1
);
181 createFilterButton(searchAndFilter
);
183 addIdentifierCheckButton(searchAndFilter
);
184 // new Label(searchAndFilter, SWT.NONE);
185 setList(new TableViewer(container
, SWT
.SINGLE
186 | SWT
.BORDER
| SWT
.V_SCROLL
| SWT
.VIRTUAL
));
188 getList().setContentProvider(contentProvider
);
189 getList().setLabelProvider(getItemsListLabelProvider());
190 getList().setInput(new Object
[0]);
191 getList().setItemCount(contentProvider
.getNumberOfElements());
192 getList().addSelectionChangedListener(new ISelectionChangedListener() {
194 public void selectionChanged(SelectionChangedEvent event
) {
195 StructuredSelection selection
= (StructuredSelection
) event
197 currentSelection
= selection
;
200 getList().addDoubleClickListener(new IDoubleClickListener() {
202 public void doubleClick(DoubleClickEvent event
) {
206 searchField
.addKeyListener(new KeyAdapter() {
208 public void keyPressed(KeyEvent e
) {
209 if (e
.keyCode
== SWT
.ARROW_DOWN
) {
210 if (getList().getTable().getItemCount() > 0) {
211 getList().getTable().setFocus();
217 // createExtendedContentArea(container);
218 new Label(container
, SWT
.NONE
);
225 protected void addIdentifierCheckButton(Composite searchAndFilter
) {
226 //as default do nothing
230 abstract void createFilterButton(Composite searchAndFilter
) ;
232 protected abstract void search();
236 * Create a new header which is labelled by headerLabel.
239 * @return Label the label of the header
241 private Label
createHeader(Composite parent
) {
242 Composite header
= new Composite(parent
, SWT
.NONE
);
243 GridData gd_header
= new GridData(SWT
.CENTER
, SWT
.CENTER
, false, false, 2, 1);
244 gd_header
.horizontalIndent
= 5;
245 gd_header
.widthHint
= 575;
246 header
.setLayoutData(gd_header
);
248 GridLayout layout
= new GridLayout();
249 layout
.marginLeft
= 5;
250 layout
.horizontalSpacing
= 0;
251 layout
.verticalSpacing
= 1;
252 layout
.marginWidth
= 0;
253 layout
.marginHeight
= 0;
254 header
.setLayout(layout
);
255 new Label(header
, SWT
.NONE
);
256 Label headerLabel
= new Label(header
, SWT
.NONE
);
257 headerLabel
.setText((getMessage() != null && getMessage().trim()
258 .length() > 0) ?
getMessage()
259 : Messages
.SearchDialog_patternLabel
);
260 headerLabel
.addTraverseListener(new TraverseListener() {
262 public void keyTraversed(TraverseEvent e
) {
263 if (e
.detail
== SWT
.TRAVERSE_MNEMONIC
&& e
.doit
) {
264 e
.detail
= SWT
.TRAVERSE_NONE
;
265 searchField
.setFocus();
269 GridData gd_headerLabel
= new GridData(GridData
.FILL_HORIZONTAL
);
270 gd_headerLabel
.horizontalAlignment
= SWT
.LEFT
;
271 gd_headerLabel
.grabExcessHorizontalSpace
= false;
272 gd_headerLabel
.verticalAlignment
= SWT
.BOTTOM
;
273 gd_headerLabel
.minimumHeight
= 10;
274 headerLabel
.setLayoutData(gd_headerLabel
);
278 protected String
getMessage() {
282 protected void setMessage(String message
){
283 this.message
= message
;
286 public Text
getSearchField() {
291 public void setSearchField(Text searchField
) {
292 this.searchField
= searchField
;
295 private ItemsListLabelProvider
getItemsListLabelProvider() {
296 if (itemsListLabelProvider
== null) {
297 itemsListLabelProvider
= new ItemsListLabelProvider(
298 new LabelProvider());
300 return itemsListLabelProvider
;
304 public TableViewer
getList() {
308 public void setList(TableViewer list
) {
310 Table table
= list
.getTable();
311 GridData gd_table
= new GridData(SWT
.CENTER
, SWT
.CENTER
, true, true, 2, 1);
312 gd_table
.heightHint
= 231;
313 gd_table
.widthHint
= 543;
314 table
.setLayoutData(gd_table
);
317 public Button
getNewButton1() {
322 public void setNewButton1(Button newButton1
) {
323 this.newButton1
= newButton1
;
327 public Button
getNewButton2() {
332 public void setNewButton2(Button newButton2
) {
333 this.newButton2
= newButton2
;
337 public Button
getFilterButton() {
342 public void setFilterButton(Button filterButton
) {
343 this.filterButton
= filterButton
;
347 * Sets a new label provider for items in the list. If the label provider
348 * also implements {@link
349 * org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider
350 * .IStyledLabelProvider}, the style text labels provided by it will be used
351 * provided that the corresponding preference is set.
353 * @see IWorkbenchPreferenceConstants#USE_COLORED_LABELS
355 * @param listLabelProvider
356 * the label provider for items in the list
358 public void setListLabelProvider(ILabelProvider listLabelProvider
) {
359 getItemsListLabelProvider().setProvider(listLabelProvider
);
361 protected Comparator
getItemsComparator() {
362 return new Comparator
<UuidAndTitleCache
>() {
364 public int compare(UuidAndTitleCache entity1
,
365 UuidAndTitleCache entity2
) {
366 Collator collator
= Collator
.getInstance();
367 if (entity1
.getUuid().equals(entity2
.getUuid())){
370 int result
= collator
.compare(entity1
.getTitleCache(), entity2
.getTitleCache());
372 result
= entity1
.getUuid().compareTo(entity2
.getUuid());
380 class ContentProvider
implements
381 IStructuredContentProvider
{
386 * Creates new instance of <code>ContentProvider</code>.
388 public ContentProvider() {
389 this.items
= Collections
.synchronizedList(new ArrayList(2048));
393 * Removes all content items and resets progress message.
395 public void reset() {
400 public void add(Object item
) {
401 this.items
.add(item
);
407 public void refresh() {
412 * Schedule refresh job.
414 public void scheduleRefresh() {
415 refreshCacheJob
.cancelAll();
416 refreshCacheJob
.schedule();
422 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
425 public Object
[] getElements(Object inputElement
) {
426 return items
.toArray();
429 public int getNumberOfElements() {
436 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
439 public void dispose() {
445 * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
446 * java.lang.Object, java.lang.Object)
449 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
456 public boolean isUseIdentifier() {
457 return useIdentifier
;
461 public StructuredSelection
getCurrentSelection() {
462 return currentSelection
;
466 * Fills the content provider with matching items.
468 * @param progressMonitor
469 * must be used to report search progress. The state of this
470 * progress monitor reflects the state of the filtering process.
471 * @throws CoreException
473 protected abstract void fillContentProvider(IProgressMonitor progressMonitor
) ;
477 * Refreshes the dialog - has to be called in UI thread.
479 public void refresh() {
480 if (getList() != null && !getList().getTable().isDisposed()) {
482 List lastRefreshSelection
= ((StructuredSelection
) getList()
483 .getSelection()).toList();
484 getList().getTable().deselectAll();
486 getList().setItemCount(contentProvider
.getNumberOfElements());
489 if (getList().getTable().getItemCount() > 0) {
490 // preserve previous selection
491 if ( lastRefreshSelection
!= null
492 && lastRefreshSelection
.size() > 0) {
493 getList().setSelection(new StructuredSelection(
494 lastRefreshSelection
));
497 getList().getTable().setSelection(0);
498 getList().getTable().notifyListeners(SWT
.Selection
, new Event());
500 if ( super.getButton(IDialogConstants
.OK_ID
) != null){
501 super.getButton(IDialogConstants
.OK_ID
).setEnabled(true);
504 getList().setSelection(StructuredSelection
.EMPTY
);
511 * A job responsible for computing filtered items list presented using
512 * <code>RefreshJob</code>.
514 * @see FilteredItemsSelectionDialog.RefreshJob
517 private class RefreshCacheJob
extends Job
{
519 public RefreshCacheJob() {
521 WorkbenchMessages
.FilteredItemsSelectionDialog_cacheRefreshJob
);
526 * Stops the job and all sub-jobs.
528 public void cancelAll() {
535 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
538 protected IStatus
run(IProgressMonitor monitor
) {
539 if (monitor
.isCanceled()) {
540 return new Status(IStatus
.CANCEL
, WorkbenchPlugin
.PI_WORKBENCH
,
541 IStatus
.CANCEL
, EMPTY_STRING
, null);
544 if (SearchDialog
.this != null) {
545 SearchDialog
.this.fillContentProvider(monitor
);
548 return new Status(IStatus
.OK
, PlatformUI
.PLUGIN_ID
, IStatus
.OK
,
556 * @see org.eclipse.core.runtime.jobs.Job#canceling()
559 protected void canceling() {
565 private class ItemsListLabelProvider
extends StyledCellLabelProvider
566 implements ILabelProviderListener
{
567 private ILabelProvider provider
;
570 * Creates a new instance of the class.
573 * the label provider for all items, not <code>null</code>
574 * @param selectionDecorator
575 * the decorator for selected items, can be <code>null</code>
577 public ItemsListLabelProvider(ILabelProvider provider
) {
578 Assert
.isNotNull(provider
);
579 this.provider
= provider
;
580 this.provider
.addListener(this);
584 * Sets new label provider.
587 * new label provider for items in the list, not
590 public void setProvider(ILabelProvider newProvider
) {
591 Assert
.isNotNull(newProvider
);
592 provider
.removeListener(this);
594 provider
= newProvider
;
596 if (provider
!= null) {
597 provider
.addListener(this);
603 private boolean isSelected(Object element
) {
604 if (element
!= null && getCurrentSelection() != null) {
605 if (element
.equals(getCurrentSelection())) {
615 * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
617 private String
getText(Object element
) {
618 if (element
instanceof ItemsListSeparator
) {
619 return getSeparatorLabel(((ItemsListSeparator
) element
)
622 String str
= provider
.getText(element
);
626 private StyledString
getStyledText(Object element
,
627 IStyledLabelProvider provider
) {
628 StyledString string
= provider
.getStyledText(element
);
634 public void update(ViewerCell cell
) {
635 Object element
= cell
.getElement();
637 if (!(element
instanceof ItemsListSeparator
)
638 && provider
instanceof IStyledLabelProvider
) {
639 IStyledLabelProvider styledLabelProvider
= (IStyledLabelProvider
) provider
;
640 StyledString styledString
= getStyledText(element
,
641 styledLabelProvider
);
643 cell
.setText(styledString
.getString());
644 cell
.setStyleRanges(styledString
.getStyleRanges());
645 cell
.setImage(styledLabelProvider
.getImage(element
));
647 cell
.setText(getText(element
));
650 cell
.setFont(getFont(element
));
651 cell
.setForeground(getForeground(element
));
652 cell
.setBackground(getBackground(element
));
657 private String
getSeparatorLabel(String separatorLabel
) {
658 Rectangle rect
= getList().getTable().getBounds();
660 int borderWidth
= getList().getTable().computeTrim(0, 0, 0, 0).width
;
662 int imageWidth
= WorkbenchImages
.getImage(
663 IWorkbenchGraphicConstants
.IMG_OBJ_SEPARATOR
).getBounds().width
;
665 int width
= rect
.width
- borderWidth
- imageWidth
;
667 GC gc
= new GC(getList().getTable());
668 gc
.setFont(getList().getTable().getFont());
670 int fSeparatorWidth
= gc
.getAdvanceWidth('-');
671 int fMessageLength
= gc
.textExtent(separatorLabel
).x
;
675 StringBuffer dashes
= new StringBuffer();
676 int chars
= (((width
- fMessageLength
) / fSeparatorWidth
) / 2) - 2;
677 for (int i
= 0; i
< chars
; i
++) {
681 StringBuffer result
= new StringBuffer();
682 result
.append(dashes
);
683 result
.append(" " + separatorLabel
+ " "); //$NON-NLS-1$//$NON-NLS-2$
684 result
.append(dashes
);
685 return result
.toString().trim();
691 * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
694 public void addListener(ILabelProviderListener listener
) {
695 listeners
.add(listener
);
701 * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
704 public void dispose() {
705 provider
.removeListener(this);
713 * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object,
717 public boolean isLabelProperty(Object element
, String property
) {
718 if (provider
.isLabelProperty(element
, property
)) {
727 * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
730 public void removeListener(ILabelProviderListener listener
) {
731 listeners
.remove(listener
);
734 private Color
getBackground(Object element
) {
735 if (element
instanceof ItemsListSeparator
) {
738 if (provider
instanceof IColorProvider
) {
739 return ((IColorProvider
) provider
).getBackground(element
);
744 private Color
getForeground(Object element
) {
745 if (element
instanceof ItemsListSeparator
) {
746 return Display
.getCurrent().getSystemColor(
747 SWT
.COLOR_WIDGET_NORMAL_SHADOW
);
749 if (provider
instanceof IColorProvider
) {
750 return ((IColorProvider
) provider
).getForeground(element
);
755 private Font
getFont(Object element
) {
756 if (element
instanceof ItemsListSeparator
) {
759 if (provider
instanceof IFontProvider
) {
760 return ((IFontProvider
) provider
).getFont(element
);
768 * @see org.eclipse.jface.viewers.ILabelProviderListener#labelProviderChanged(org.eclipse.jface.viewers.LabelProviderChangedEvent)
771 public void labelProviderChanged(LabelProviderChangedEvent event
) {
772 Object
[] l
= listeners
.getListeners();
773 for (int i
= 0; i
< listeners
.size(); i
++) {
774 ((ILabelProviderListener
) l
[i
]).labelProviderChanged(event
);
780 protected Point
getInitialSize() {
781 return new Point(593, 399);