1 /*******************************************************************************
2  * Copyright (c) 2014, 2019 TwelveTone LLC and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  * Steven Spungin <steven@spungin.tv> - initial API and implementation, ongoing maintenance
13  *******************************************************************************/
14 
15 package org.eclipse.e4.tools.emf.ui.internal.common.component.tabs;
16 
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 
20 import org.eclipse.jface.viewers.ColumnLabelProvider;
21 import org.eclipse.jface.viewers.TableViewer;
22 import org.eclipse.jface.viewers.TableViewerColumn;
23 import org.eclipse.jface.viewers.Viewer;
24 import org.eclipse.jface.viewers.ViewerCell;
25 import org.eclipse.jface.viewers.ViewerComparator;
26 import org.eclipse.swt.SWT;
27 import org.eclipse.swt.events.MouseEvent;
28 import org.eclipse.swt.events.SelectionEvent;
29 import org.eclipse.swt.events.SelectionListener;
30 import org.eclipse.swt.graphics.Point;
31 import org.eclipse.swt.widgets.TableColumn;
32 
33 public class TableViewerUtil {
34 
35 	// Sorts the column by the provider's text value
36 	static class ColumnLabelSorter extends TableViewerUtil.AbstractInvertableTableSorter {
37 		private final TableColumn col;
38 
ColumnLabelSorter(TableColumn col)39 		ColumnLabelSorter(TableColumn col) {
40 			this.col = col;
41 		}
42 
43 		@Override
compare(Viewer viewer, Object e1, Object e2)44 		public int compare(Viewer viewer, Object e1, Object e2) {
45 			final TableViewer tableViewer = (TableViewer) viewer;
46 			final ColumnLabelProvider labelProvider = (ColumnLabelProvider) tableViewer.getLabelProvider(Arrays.asList(
47 					tableViewer.getTable().getColumns()).indexOf(col));
48 			return labelProvider.getText(e1).compareTo(labelProvider.getText(e2));
49 		}
50 	}
51 
52 	static abstract class InvertableSorter extends ViewerComparator {
53 		@Override
compare(Viewer viewer, Object e1, Object e2)54 		public abstract int compare(Viewer viewer, Object e1, Object e2);
55 
getInverseSorter()56 		abstract InvertableSorter getInverseSorter();
57 
getSortDirection()58 		public abstract int getSortDirection();
59 	}
60 
61 	static public abstract class AbstractInvertableTableSorter extends InvertableSorter {
62 		private final InvertableSorter inverse = new InvertableSorter() {
63 
64 			@Override
65 			public int compare(Viewer viewer, Object e1, Object e2) {
66 				return -1 * AbstractInvertableTableSorter.this.compare(viewer, e1, e2);
67 			}
68 
69 			@Override
70 			InvertableSorter getInverseSorter() {
71 				return AbstractInvertableTableSorter.this;
72 			}
73 
74 			@Override
75 			public int getSortDirection() {
76 				return SWT.DOWN;
77 			}
78 		};
79 
80 		@Override
getInverseSorter()81 		InvertableSorter getInverseSorter() {
82 			return inverse;
83 		}
84 
85 		@Override
getSortDirection()86 		public int getSortDirection() {
87 			return SWT.UP;
88 		}
89 	}
90 
91 	static public class TableSortSelectionListener implements SelectionListener {
92 		private final TableViewer viewer;
93 		private final TableColumn column;
94 		private final InvertableSorter sorter;
95 		private final boolean keepDirection;
96 		private InvertableSorter currentSorter;
97 
98 		/**
99 		 * The constructor of this listener.
100 		 *
101 		 * @param viewer           the tableviewer this listener belongs to
102 		 * @param column           the column this listener is responsible for
103 		 * @param sorter           the sorter this listener uses
104 		 * @param defaultDirection the default sorting direction of this Listener.
105 		 *                         Possible values are {@link SWT#UP} and
106 		 *                         {@link SWT#DOWN}
107 		 * @param keepDirection    if true, the listener will remember the last sorting
108 		 *                         direction of the associated column and restore it
109 		 *                         when the column is reselected. If false, the listener
110 		 *                         will use the default sorting direction
111 		 */
TableSortSelectionListener(TableViewer viewer, TableColumn column, AbstractInvertableTableSorter sorter, int defaultDirection, boolean keepDirection)112 		public TableSortSelectionListener(TableViewer viewer, TableColumn column, AbstractInvertableTableSorter sorter,
113 				int defaultDirection, boolean keepDirection) {
114 			this.viewer = viewer;
115 			this.column = column;
116 			this.keepDirection = keepDirection;
117 			this.sorter = defaultDirection == SWT.UP ? sorter : sorter.getInverseSorter();
118 			currentSorter = this.sorter;
119 
120 			this.column.addSelectionListener(this);
121 		}
122 
123 		/**
124 		 * Chooses the column of this listener for sorting of the table. Mainly
125 		 * used when first initializing the table.
126 		 */
chooseColumnForSorting()127 		public void chooseColumnForSorting() {
128 			viewer.getTable().setSortColumn(column);
129 			viewer.getTable().setSortDirection(currentSorter.getSortDirection());
130 			viewer.setComparator(currentSorter);
131 		}
132 
133 		@Override
widgetSelected(SelectionEvent e)134 		public void widgetSelected(SelectionEvent e) {
135 			InvertableSorter newSorter;
136 			if (viewer.getTable().getSortColumn() == column) {
137 				newSorter = ((InvertableSorter) viewer.getComparator()).getInverseSorter();
138 			} else {
139 				if (keepDirection) {
140 					newSorter = currentSorter;
141 				} else {
142 					newSorter = sorter;
143 				}
144 			}
145 
146 			currentSorter = newSorter;
147 			chooseColumnForSorting();
148 		}
149 
150 		@Override
widgetDefaultSelected(SelectionEvent e)151 		public void widgetDefaultSelected(SelectionEvent e) {
152 			widgetSelected(e);
153 		}
154 	}
155 
refreshAndPack(TableViewer viewer)156 	static public void refreshAndPack(TableViewer viewer) {
157 		viewer.refresh();
158 		packAllColumns(viewer);
159 	}
160 
updateAndPack(TableViewer viewer, Object object)161 	static public void updateAndPack(TableViewer viewer, Object object) {
162 		viewer.update(object, null);
163 		packAllColumns(viewer);
164 	}
165 
isColumnClicked(TableViewer viewer, MouseEvent e, TableViewerColumn tvColumn)166 	public static boolean isColumnClicked(TableViewer viewer, MouseEvent e, TableViewerColumn tvColumn) {
167 		boolean ret;
168 		final ViewerCell cell = viewer.getCell(new Point(e.x, e.y));
169 		if (cell == null) {
170 			ret = false;
171 		} else {
172 			final int index = Arrays.asList(viewer.getTable().getColumns()).indexOf(tvColumn.getColumn());
173 			if (index == -1) {
174 				ret = false;
175 			} else {
176 				ret = index == cell.getColumnIndex();
177 			}
178 		}
179 		return ret;
180 	}
181 
getData(TableViewer viewer, MouseEvent e)182 	public static Object getData(TableViewer viewer, MouseEvent e) {
183 		final ViewerCell cell = viewer.getCell(new Point(e.x, e.y));
184 		if (cell == null) {
185 			return null;
186 		}
187 		return cell.getElement();
188 	}
189 
packAllColumns(TableViewer viewer)190 	public static void packAllColumns(TableViewer viewer) {
191 		for (final TableColumn col : viewer.getTable().getColumns()) {
192 			col.pack();
193 		}
194 	}
195 
resetColumnOrder(TableViewer tvResults)196 	static public void resetColumnOrder(TableViewer tvResults) {
197 		final int[] order = tvResults.getTable().getColumnOrder();
198 		for (int i = 0; i < order.length; i++) {
199 			order[i] = i;
200 		}
201 		tvResults.getTable().setColumnOrder(order);
202 	}
203 
getColumnsInDisplayOrder(TableViewer viewer)204 	static public ArrayList<TableColumn> getColumnsInDisplayOrder(TableViewer viewer) {
205 		final ArrayList<TableColumn> allCols = new ArrayList<>(Arrays.asList(viewer.getTable().getColumns()));
206 		final int[] order = viewer.getTable().getColumnOrder();
207 		allCols.sort((o1, o2) -> order[allCols.indexOf(o1)] - order[allCols.indexOf(o2)]);
208 		return allCols;
209 	}
210 
getVisibleColumnIndex(TableViewer tvResults2, TableColumn col)211 	static public int getVisibleColumnIndex(TableViewer tvResults2, TableColumn col) {
212 		final int createOrder = Arrays.asList(tvResults2.getTable().getColumns()).indexOf(col);
213 		if (createOrder == -1) {
214 			return -1;
215 		}
216 		return tvResults2.getTable().getColumnOrder()[createOrder];
217 	}
218 }