/*******************************************************************************
* Copyright (c) 2009 STMicroelectronics.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Marzia Maugeri <marzia.maugeri@st.com> - initial API and implementation
*******************************************************************************/
package org.eclipse.linuxtools.dataviewers.abstractviewers;
import java.util.Comparator;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.linuxtools.dataviewers.STDataViewersActivator;
import org.eclipse.swt.widgets.Item;
/**
* This comparator is used to reorder the elements provided by the content provider.
*/
public class STDataViewersComparator extends ViewerComparator implements Comparator<Object> {
/** Maximum number of sorters */
public static final int MAX_DEPTH = 4;
/** Tag for ascending direction when sorting */
public static final int ASCENDING = 1;
/** Tag for reverse direction when sorting */
public static final int DESCENDING = -1;
protected final Item[] columns;
protected int[] priorities;
protected int[] directions;
/**
* Copy Constructor
*
* @param other The comparator to initialize from.
*/
public STDataViewersComparator(STDataViewersComparator other) {
this(other.getColumns(), other.getPriorities(), other.getDirections());
}
/**
* Constructor
*
* @param columns The columns properties of the viewer.
*/
public STDataViewersComparator(Item[] columns) {
this(columns, null, null);
}
/**
* Constructor
*
* @param columns
* @param priorities
* @param directions
*/
private STDataViewersComparator(Item[] columns, int[] priorities, int[] directions) {
this.columns = columns;
if (priorities == null || directions == null) {
this.priorities = new int[columns.length];
this.directions = new int[columns.length];
resetState();
} else {
if (priorities.length == columns.length && directions.length == columns.length) {
this.priorities = priorities;
this.directions = directions;
} else {
STDataViewersActivator
.getDefault()
.getLog()
.log(new Status(IStatus.WARNING, STDataViewersActivator.PLUGIN_ID, "Invalid parameters:"
+ " priorities and/or directions number don't match with"
+ " viewer's columns count. Applying defaults settings."));
resetState();
}
}
}
/**
* Reset the priorities to the default ones
*/
private void resetPriorites() {
for (int i = 0; i < this.priorities.length; i++) {
this.priorities[i] = i;
}
}
/**
* Reset the directions to the default ones
*/
private void resetDirections() {
for (int i = 0; i < this.directions.length; i++) {
this.directions[i] = getField(this.columns[i]).getDefaultDirection();
}
}
/**
* Resets the directions and priorities of the sorters
*/
public void resetState() {
resetDirections();
resetPriorites();
}
/**
* Change the direction of the first sorter
*/
public void reverseTopPriority() {
directions[priorities[0]] *= -1;
}
/**
* Sets the top-level sorter.
*
* @param column The column to make top priority.
* @param field The field to set priority for.
*/
public void setTopPriority(final Item column, final ISTDataViewersField field) {
for (int i = 0; i < columns.length; i++) {
if (columns[i].equals(column)) {
setTopPriority(i, field);
}
}
}
/**
* Sets the top-level sorter.
*
* @param priority The new top priority.
* @param field The field to set priority for.
*/
private void setTopPriority(final int priority, final ISTDataViewersField field) {
if (priority < 0 || priority >= priorities.length) {
return;
}
int index = -1;
for (int i = 0; i < priorities.length; i++) {
if (priorities[i] == priority) {
index = i;
}
}
if (index == -1) {
resetState();
return;
}
// shift the array
for (int i = index; i > 0; i--) {
priorities[i] = priorities[i - 1];
}
priorities[0] = priority;
directions[priority] = field.getDefaultDirection();
}
/**
* Changes the direction of the top-priority sorter.
*
* @param direction The direction of sorting - ascending or descending.
*/
public void setTopPriorityDirection(int direction) {
if (direction == ASCENDING || direction == DESCENDING) {
directions[priorities[0]] = direction;
}
}
/**
* @return the direction of the top-level sorter
*/
public int getTopPriorityDirection() {
return directions[priorities[0]];
}
/**
* Return the field at the top priority.
*
* @return IField
*/
public Item getTopColumn() {
return columns[priorities[0]];
}
/**
* NOTE: defensive programming: return a copy of the array
*
* @return the current priorities
*/
public int[] getPriorities() {
int[] copy = new int[priorities.length];
System.arraycopy(priorities, 0, copy, 0, copy.length);
return copy;
}
/**
* NOTE: defensive programming: return a copy of the array
*
* @return the current directions
*/
public int[] getDirections() {
int[] copy = new int[directions.length];
System.arraycopy(directions, 0, copy, 0, copy.length);
return copy;
}
@Override
public int compare(Object o1, Object o2) {
return compare(o1, o2, 0, true);
}
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
return compare(e1, e2, 0, true);
}
/**
* Compare obj1 and obj2 at depth. If continueSearching continue searching below depth to continue the comparison.
*
* @param obj1
* @param obj2
* @param depth
* @param continueSearching
* @return int
*/
private int compare(Object obj1, Object obj2, int depth, boolean continueSearching) {
if (depth >= priorities.length) {
return 0;
}
int column = priorities[depth];
ISTDataViewersField property = getField(columns[column]);
int result;
if (directions[column] >= 0) {
result = property.compare(obj1, obj2);
} else {
result = property.compare(obj2, obj1);
}
if (result == 0 && continueSearching) {
return compare(obj1, obj2, depth + 1, continueSearching);
}
return result;
}
protected ISTDataViewersField getField(Item column) {
return (ISTDataViewersField) column.getData();
}
/**
* @return IField[] an array of fields
*/
public Item[] getColumns() {
return columns;
}
/**
* Saves the sort order preferences of the user in the given {@link IDialogSettings}
*
* @param dialogSettings The setting to save into.
*/
public void saveState(IDialogSettings dialogSettings) {
if (dialogSettings == null) {
return;
}
IDialogSettings settings = dialogSettings.getSection(STDataViewersSettings.TAG_SECTION_SORTER);
if (settings == null) {
settings = dialogSettings.addNewSection(STDataViewersSettings.TAG_SECTION_SORTER);
}
for (int i = 0; i < priorities.length; i++) {
settings.put(STDataViewersSettings.TAG_SORTER_PRIORITY_ + i, priorities[i]);
settings.put(STDataViewersSettings.TAG_SORTER_DIRECTION_ + i, directions[i]);
}
}
/**
* Restore the sort order preferences of the user from the given {@link IDialogSettings}
*
* @param dialogSettings The settings to restore from.
*/
public void restoreState(IDialogSettings dialogSettings) {
if (dialogSettings == null) {
// no settings section
resetState();
return;
}
IDialogSettings settings = dialogSettings.getSection(STDataViewersSettings.TAG_SECTION_SORTER);
if (settings == null) {
// no settings saved
resetState();
return;
}
try {
for (int i = 0; i < priorities.length; i++) {
String priority = settings.get(STDataViewersSettings.TAG_SORTER_PRIORITY_ + i);
if (priority == null) {
// no priority data
resetState();
return;
}
int colIndex = Integer.parseInt(priority);
// Make sure it is not old data from a different sized array
if (colIndex < columns.length) {
priorities[i] = colIndex;
} else {
// data from a different sized array
resetState();
return;
}
String direction = settings.get(STDataViewersSettings.TAG_SORTER_DIRECTION_ + i);
if (direction == null) {
// no direction data
resetState();
return;
}
directions[i] = Integer.parseInt(direction);
}
} catch (NumberFormatException e) {
// invalid entry
resetState();
return;
}
}
}