/*******************************************************************************
* Copyright (c) 2012 Google, Inc.
* 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:
* Google, Inc. - initial API and implementation
*******************************************************************************/
package com.windowtester.swt.util;
import org.eclipse.swt.SWT;
/**
* A helper class that determines what index to select given sets of before and after
* indicies. This service is used to identify list and table items to select in
* constructing selection events.
*/
public class SelectionDeltaParser {
/**
* Find the index to select in order to match before and after index states.
* @param before - the indices selected before a selection event
* @param after - the indices selected after a selection event
* @param type - the type (SWT.CTRL, SWT.SHIFT) of selection
* @return the index to select
*/
public static int indexToSelect(int[] before, int[] after, int type) {
if (type == 0)
return stdSelect(before, after);
if (type == SWT.CTRL)
return ctrlSelect(before, after);
if (type == SWT.SHIFT)
return shiftSelect(before, after);
throw new IllegalArgumentException("invalid selection type: " + type);
}
//////////////////////////////////////////////////////////////////////////////
//
// Selection implementations.
//
//////////////////////////////////////////////////////////////////////////////
/**
* Do a standard select.
*/
private static int stdSelect(int[] before, int[] after) {
int current;
for (int i = 0; i < after.length; i++) {
current = after[i];
if (!isContainedIn(current, before))
return current;
}
if (after.length == 0 && before.length == 1)
return before[0];
if (after.length == 1)
return after[0];
throw new IllegalStateException();
}
/**
* Do a shift select.
*/
private static int shiftSelect(int[] before, int[] after) {
//self select
if ((before.length == 1) && (after.length == 1))
return before[0];
//single-deselect
if (after.length == 0 && before.length == 1)
return before[0];
//single-select
if (after.length == 1)
return after[0];
//multi-select cases
//-> up:
if (first(after) == first(before))
return last(after);
if (first(after) == last(before))
return last(after);
//-> down:
return first(after);
}
/**
* Do a control select.
*/
private static int ctrlSelect(int[] before, int[] after) {
//self select
if ((before.length == 1) && (after.length == 1))
return before[0];
//single-deselect
if (after.length == 0 && before.length == 1)
return before[0];
//general select
if (after.length > before.length)
return last(after);
//general deselect
if (after.length < before.length)
return findFirstNotContainedIn(before, after);
//if arrays are of the same size (but not == 1), we have an internal error...
throw new IllegalStateException();
}
//////////////////////////////////////////////////////////////////////////////
//
// Helpers
//
//////////////////////////////////////////////////////////////////////////////
/**
* Find the first element in an array not contained in the other.
*/
private static int findFirstNotContainedIn(int[] items1, int[] items2) {
int current;
for (int i = 0; i < items1.length; i++) {
current = items1[i];
if (!isContainedIn(current, items2))
return current;
}
throw new IllegalStateException();
}
/**
* Get the first item in this array.
*/
private static int first(int[] items) {
return items[0];
}
/**
* Get the last item in this array.
*/
private static int last(int[] items) {
return items[items.length-1];
}
public static int indexToSelect(int[] before, int[] after) {
return indexToSelect(before, after, 0);
}
/**
* Check to see if the given item is in an array.
*/
private static boolean isContainedIn(int item, int[] items) {
for (int i = 0; i < items.length; ++i) {
if (items[i] == item)
return true;
}
return false;
}
}