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
.action
.MenuManager
;
29 import org
.eclipse
.jface
.dialogs
.Dialog
;
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
.ModifyEvent
;
52 import org
.eclipse
.swt
.events
.ModifyListener
;
53 import org
.eclipse
.swt
.events
.TraverseEvent
;
54 import org
.eclipse
.swt
.events
.TraverseListener
;
55 import org
.eclipse
.swt
.graphics
.Color
;
56 import org
.eclipse
.swt
.graphics
.Font
;
57 import org
.eclipse
.swt
.graphics
.GC
;
58 import org
.eclipse
.swt
.graphics
.Point
;
59 import org
.eclipse
.swt
.graphics
.Rectangle
;
60 import org
.eclipse
.swt
.layout
.GridData
;
61 import org
.eclipse
.swt
.layout
.GridLayout
;
62 import org
.eclipse
.swt
.widgets
.Button
;
63 import org
.eclipse
.swt
.widgets
.Composite
;
64 import org
.eclipse
.swt
.widgets
.Control
;
65 import org
.eclipse
.swt
.widgets
.Display
;
66 import org
.eclipse
.swt
.widgets
.Event
;
67 import org
.eclipse
.swt
.widgets
.Label
;
68 import org
.eclipse
.swt
.widgets
.Shell
;
69 import org
.eclipse
.swt
.widgets
.Table
;
70 import org
.eclipse
.swt
.widgets
.Text
;
71 import org
.eclipse
.swt
.widgets
.ToolBar
;
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 private StructuredSelection currentSelection
;
102 // message to show user
103 private String message
= ""; //$NON-NLS-1$
105 protected final ContentProvider contentProvider
;
106 ItemsListLabelProvider itemsListLabelProvider
;
108 private final RefreshCacheJob refreshCacheJob
;
110 private ToolBar toolBar
;
111 private MenuManager menuManager
;
113 protected Object preferenceID
;
115 protected final int new_id
= 4;
116 protected final int new_id2
= 5;
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
;
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());
149 // GridData gd_searchAndFilter = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
150 GridData gd_searchAndFilter
=new GridData(GridData
.GRAB_HORIZONTAL
| GridData
.HORIZONTAL_ALIGN_FILL
);
151 // gd_searchAndFilter.widthHint = 576;
152 searchAndFilter
.setLayoutData(gd_searchAndFilter
);
153 GridLayout searchAndFilterLayout
= new GridLayout();
154 searchAndFilterLayout
.numColumns
= 2;
155 searchAndFilter
.setLayout(searchAndFilterLayout
);
156 searchField
= new Text(searchAndFilter
, SWT
.SINGLE
| SWT
.BORDER
| SWT
.SEARCH
| SWT
.ICON_CANCEL
);
157 searchField
.getAccessible().addAccessibleListener(new AccessibleAdapter() {
159 public void getName(AccessibleEvent e
) {
160 e
.result
= LegacyActionTools
.removeMnemonics(headerLabel
164 searchField
.addModifyListener(new ModifyListener() {
166 public void modifyText(ModifyEvent e
) {
169 fillContentProvider(null);
170 } catch (CoreException coreException
) {
171 // TODO Auto-generated catch block
172 coreException
.printStackTrace();
176 gd_1
= new GridData(GridData
.GRAB_HORIZONTAL
| GridData
.HORIZONTAL_ALIGN_FILL
);
178 // gd_1.horizontalIndent = 2;
179 // gd_1.horizontalAlignment = SWT.CENTER;
180 // gd_1.grabExcessHorizontalSpace = true;
181 // gd_1.widthHint = 500;
182 searchField
.setLayoutData(gd_1
);
184 createFilterButton(searchAndFilter
);
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 // createExtendedContentArea(container);
207 new Label(container
, SWT
.NONE
);
213 abstract void createFilterButton(Composite searchAndFilter
) ;
215 protected abstract void search();
218 * Creates an extra content area, which will be located above the details.
221 * parent to create the dialog widgets in
222 * @return an extra content area
224 // protected abstract Control createExtendedContentArea(Composite parent);
227 * Sets the title for this dialog.
232 public void setTitle(String title
) {
237 * Create a new header which is labelled by headerLabel.
240 * @return Label the label of the header
242 private Label
createHeader(Composite parent
) {
243 Composite header
= new Composite(parent
, SWT
.NONE
);
244 GridData gd_header
= new GridData(SWT
.CENTER
, SWT
.CENTER
, false, false, 2, 1);
245 gd_header
.widthHint
= 575;
246 header
.setLayoutData(gd_header
);
248 GridLayout layout
= new GridLayout();
249 layout
.verticalSpacing
= 1;
250 layout
.marginWidth
= 0;
251 layout
.marginHeight
= 0;
252 header
.setLayout(layout
);
253 new Label(header
, SWT
.NONE
);
254 Label headerLabel
= new Label(header
, SWT
.NONE
);
255 headerLabel
.setText((getMessage() != null && getMessage().trim()
256 .length() > 0) ?
getMessage()
257 : Messages
.SearchDialog_patternLabel
);
258 headerLabel
.addTraverseListener(new TraverseListener() {
260 public void keyTraversed(TraverseEvent e
) {
261 if (e
.detail
== SWT
.TRAVERSE_MNEMONIC
&& e
.doit
) {
262 e
.detail
= SWT
.TRAVERSE_NONE
;
263 searchField
.setFocus();
267 GridData gd_headerLabel
= new GridData(GridData
.FILL_HORIZONTAL
);
268 gd_headerLabel
.horizontalAlignment
= SWT
.LEFT
;
269 gd_headerLabel
.grabExcessHorizontalSpace
= false;
270 gd_headerLabel
.verticalAlignment
= SWT
.BOTTOM
;
271 gd_headerLabel
.minimumHeight
= 10;
272 headerLabel
.setLayoutData(gd_headerLabel
);
276 protected String
getMessage() {
280 protected void setMessage(String message
){
281 this.message
= message
;
284 public Text
getSearchField() {
289 public void setSearchField(Text searchField
) {
290 this.searchField
= searchField
;
293 private ItemsListLabelProvider
getItemsListLabelProvider() {
294 if (itemsListLabelProvider
== null) {
295 itemsListLabelProvider
= new ItemsListLabelProvider(
296 new LabelProvider());
298 return itemsListLabelProvider
;
300 // private void createViewMenu(Composite parent) {
301 // toolBar = new ToolBar(parent, SWT.FLAT);
303 // GridData data = new GridData();
304 // data.horizontalAlignment = GridData.END;
305 // data.grabExcessHorizontalSpace = true;
306 // toolBar.setLayoutData(data);
308 // menuManager = new MenuManager();
310 // fillViewMenu(menuManager);
312 // IHandlerService service = PlatformUI.getWorkbench()
313 // .getService(IHandlerService.class);
314 // IHandler handler = new AbstractHandler() {
316 // public Object execute(ExecutionEvent event) {
324 // * Fills the menu of the dialog.
326 // * @param menuManager
327 // * the menu manager
329 // protected void fillViewMenu(IMenuManager menuManager) {
333 // private void showViewMenu() {
334 // Menu menu = menuManager.createContextMenu(getShell());
335 // Rectangle bounds = toolItem.getBounds();
336 // Point topLeft = new Point(bounds.x, bounds.y + bounds.height);
337 // topLeft = toolBar.toDisplay(topLeft);
338 // menu.setLocation(topLeft.x, topLeft.y);
339 // menu.setVisible(true);
342 public TableViewer
getList() {
346 public void setList(TableViewer list
) {
348 Table table
= list
.getTable();
349 GridData gd_table
= new GridData(SWT
.CENTER
, SWT
.CENTER
, true, true, 2, 1);
350 gd_table
.heightHint
= 231;
351 gd_table
.widthHint
= 543;
352 table
.setLayoutData(gd_table
);
355 public Button
getNewButton1() {
360 public void setNewButton1(Button newButton1
) {
361 this.newButton1
= newButton1
;
365 public Button
getNewButton2() {
370 public void setNewButton2(Button newButton2
) {
371 this.newButton2
= newButton2
;
375 public Button
getFilterButton() {
380 public void setFilterButton(Button filterButton
) {
381 this.filterButton
= filterButton
;
385 * Sets a new label provider for items in the list. If the label provider
386 * also implements {@link
387 * org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider
388 * .IStyledLabelProvider}, the style text labels provided by it will be used
389 * provided that the corresponding preference is set.
391 * @see IWorkbenchPreferenceConstants#USE_COLORED_LABELS
393 * @param listLabelProvider
394 * the label provider for items in the list
396 public void setListLabelProvider(ILabelProvider listLabelProvider
) {
397 getItemsListLabelProvider().setProvider(listLabelProvider
);
399 protected Comparator
getItemsComparator() {
400 return new Comparator
<UuidAndTitleCache
>() {
402 public int compare(UuidAndTitleCache entity1
,
403 UuidAndTitleCache entity2
) {
404 Collator collator
= Collator
.getInstance();
405 if (entity1
.getUuid().equals(entity2
.getUuid())){
408 int result
= collator
.compare(entity1
.getTitleCache(), entity2
.getTitleCache());
410 result
= entity1
.getUuid().compareTo(entity2
.getUuid());
418 class ContentProvider
implements
419 IStructuredContentProvider
{
424 * Creates new instance of <code>ContentProvider</code>.
426 public ContentProvider() {
427 this.items
= Collections
.synchronizedList(new ArrayList(2048));
431 * Removes all content items and resets progress message.
433 public void reset() {
438 public void add(Object item
) {
439 this.items
.add(item
);
445 public void refresh() {
450 * Schedule refresh job.
452 public void scheduleRefresh() {
453 refreshCacheJob
.cancelAll();
454 refreshCacheJob
.schedule();
460 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
463 public Object
[] getElements(Object inputElement
) {
464 return items
.toArray();
467 public int getNumberOfElements() {
474 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
477 public void dispose() {
483 * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
484 * java.lang.Object, java.lang.Object)
487 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
495 public StructuredSelection
getCurrentSelection() {
496 return currentSelection
;
500 * Fills the content provider with matching items.
502 * @param progressMonitor
503 * must be used to report search progress. The state of this
504 * progress monitor reflects the state of the filtering process.
505 * @throws CoreException
507 protected abstract void fillContentProvider(IProgressMonitor progressMonitor
) throws CoreException
;
511 * Refreshes the dialog - has to be called in UI thread.
513 public void refresh() {
514 if (getList() != null && !getList().getTable().isDisposed()) {
516 List lastRefreshSelection
= ((StructuredSelection
) getList()
517 .getSelection()).toList();
518 getList().getTable().deselectAll();
520 getList().setItemCount(contentProvider
.getNumberOfElements());
523 if (getList().getTable().getItemCount() > 0) {
524 // preserve previous selection
525 if ( lastRefreshSelection
!= null
526 && lastRefreshSelection
.size() > 0) {
527 getList().setSelection(new StructuredSelection(
528 lastRefreshSelection
));
531 getList().getTable().setSelection(0);
532 getList().getTable().notifyListeners(SWT
.Selection
, new Event());
535 getList().setSelection(StructuredSelection
.EMPTY
);
542 * A job responsible for computing filtered items list presented using
543 * <code>RefreshJob</code>.
545 * @see FilteredItemsSelectionDialog.RefreshJob
548 private class RefreshCacheJob
extends Job
{
550 public RefreshCacheJob() {
552 WorkbenchMessages
.FilteredItemsSelectionDialog_cacheRefreshJob
);
557 * Stops the job and all sub-jobs.
559 public void cancelAll() {
566 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
569 protected IStatus
run(IProgressMonitor monitor
) {
570 if (monitor
.isCanceled()) {
571 return new Status(IStatus
.CANCEL
, WorkbenchPlugin
.PI_WORKBENCH
,
572 IStatus
.CANCEL
, EMPTY_STRING
, null);
575 if (SearchDialog
.this != null) {
578 SearchDialog
.this.fillContentProvider(monitor
);
579 } catch (CoreException e
) {
580 // TODO Auto-generated catch block
585 return new Status(IStatus
.OK
, PlatformUI
.PLUGIN_ID
, IStatus
.OK
,
593 * @see org.eclipse.core.runtime.jobs.Job#canceling()
596 protected void canceling() {
602 private class ItemsListLabelProvider
extends StyledCellLabelProvider
603 implements ILabelProviderListener
{
604 private ILabelProvider provider
;
607 * Creates a new instance of the class.
610 * the label provider for all items, not <code>null</code>
611 * @param selectionDecorator
612 * the decorator for selected items, can be <code>null</code>
614 public ItemsListLabelProvider(ILabelProvider provider
) {
615 Assert
.isNotNull(provider
);
616 this.provider
= provider
;
617 this.provider
.addListener(this);
621 * Sets new label provider.
624 * new label provider for items in the list, not
627 public void setProvider(ILabelProvider newProvider
) {
628 Assert
.isNotNull(newProvider
);
629 provider
.removeListener(this);
631 provider
= newProvider
;
633 if (provider
!= null) {
634 provider
.addListener(this);
640 private boolean isSelected(Object element
) {
641 if (element
!= null && getCurrentSelection() != null) {
642 if (element
.equals(getCurrentSelection())) {
652 * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
654 private String
getText(Object element
) {
655 if (element
instanceof ItemsListSeparator
) {
656 return getSeparatorLabel(((ItemsListSeparator
) element
)
659 String str
= provider
.getText(element
);
663 private StyledString
getStyledText(Object element
,
664 IStyledLabelProvider provider
) {
665 StyledString string
= provider
.getStyledText(element
);
671 public void update(ViewerCell cell
) {
672 Object element
= cell
.getElement();
674 if (!(element
instanceof ItemsListSeparator
)
675 && provider
instanceof IStyledLabelProvider
) {
676 IStyledLabelProvider styledLabelProvider
= (IStyledLabelProvider
) provider
;
677 StyledString styledString
= getStyledText(element
,
678 styledLabelProvider
);
680 cell
.setText(styledString
.getString());
681 cell
.setStyleRanges(styledString
.getStyleRanges());
682 cell
.setImage(styledLabelProvider
.getImage(element
));
684 cell
.setText(getText(element
));
687 cell
.setFont(getFont(element
));
688 cell
.setForeground(getForeground(element
));
689 cell
.setBackground(getBackground(element
));
694 private String
getSeparatorLabel(String separatorLabel
) {
695 Rectangle rect
= getList().getTable().getBounds();
697 int borderWidth
= getList().getTable().computeTrim(0, 0, 0, 0).width
;
699 int imageWidth
= WorkbenchImages
.getImage(
700 IWorkbenchGraphicConstants
.IMG_OBJ_SEPARATOR
).getBounds().width
;
702 int width
= rect
.width
- borderWidth
- imageWidth
;
704 GC gc
= new GC(getList().getTable());
705 gc
.setFont(getList().getTable().getFont());
707 int fSeparatorWidth
= gc
.getAdvanceWidth('-');
708 int fMessageLength
= gc
.textExtent(separatorLabel
).x
;
712 StringBuffer dashes
= new StringBuffer();
713 int chars
= (((width
- fMessageLength
) / fSeparatorWidth
) / 2) - 2;
714 for (int i
= 0; i
< chars
; i
++) {
718 StringBuffer result
= new StringBuffer();
719 result
.append(dashes
);
720 result
.append(" " + separatorLabel
+ " "); //$NON-NLS-1$//$NON-NLS-2$
721 result
.append(dashes
);
722 return result
.toString().trim();
728 * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
731 public void addListener(ILabelProviderListener listener
) {
732 listeners
.add(listener
);
738 * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
741 public void dispose() {
742 provider
.removeListener(this);
750 * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object,
754 public boolean isLabelProperty(Object element
, String property
) {
755 if (provider
.isLabelProperty(element
, property
)) {
764 * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
767 public void removeListener(ILabelProviderListener listener
) {
768 listeners
.remove(listener
);
771 private Color
getBackground(Object element
) {
772 if (element
instanceof ItemsListSeparator
) {
775 if (provider
instanceof IColorProvider
) {
776 return ((IColorProvider
) provider
).getBackground(element
);
781 private Color
getForeground(Object element
) {
782 if (element
instanceof ItemsListSeparator
) {
783 return Display
.getCurrent().getSystemColor(
784 SWT
.COLOR_WIDGET_NORMAL_SHADOW
);
786 if (provider
instanceof IColorProvider
) {
787 return ((IColorProvider
) provider
).getForeground(element
);
792 private Font
getFont(Object element
) {
793 if (element
instanceof ItemsListSeparator
) {
796 if (provider
instanceof IFontProvider
) {
797 return ((IFontProvider
) provider
).getFont(element
);
805 * @see org.eclipse.jface.viewers.ILabelProviderListener#labelProviderChanged(org.eclipse.jface.viewers.LabelProviderChangedEvent)
808 public void labelProviderChanged(LabelProviderChangedEvent event
) {
809 Object
[] l
= listeners
.getListeners();
810 for (int i
= 0; i
< listeners
.size(); i
++) {
811 ((ILabelProviderListener
) l
[i
]).labelProviderChanged(event
);
817 protected Point
getInitialSize() {
818 return new Point(593, 399);