19f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li/*
29f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * ConnectBot: simple, powerful, open-source SSH client for Android
39f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * Copyright 2007 Kenny Root, Jeffrey Sharkey
49f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
59f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * Licensed under the Apache License, Version 2.0 (the "License");
69f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * you may not use this file except in compliance with the License.
79f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * You may obtain a copy of the License at
89f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
99f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *     http://www.apache.org/licenses/LICENSE-2.0
109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * Unless required by applicable law or agreed to in writing, software
129f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * distributed under the License is distributed on an "AS IS" BASIS,
139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
149f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * See the License for the specific language governing permissions and
159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * limitations under the License.
169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li */
179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Lipackage org.connectbot.util;
199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport de.mud.terminal.VDUBuffer;
219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li/**
239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * Keep track of a selection area for the terminal copying mechanism.
249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * If the orientation is flipped one way, swap the bottom and top or
259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * left and right to keep it in the correct orientation.
269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li */
279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Lipublic class SelectionArea {
289f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	private int top;
299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	private int bottom;
309f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	private int left;
319f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	private int right;
329f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	private int maxColumns;
339f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	private int maxRows;
349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	private boolean selectingOrigin;
359f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
369f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public SelectionArea() {
379f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		reset();
389f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
399f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public final void reset() {
419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		top = left = bottom = right = 0;
429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		selectingOrigin = true;
439f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
459f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	/**
469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	 * @param columns
479f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	 * @param rows
489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	 */
499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public void setBounds(int columns, int rows) {
509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		maxColumns = columns - 1;
519f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		maxRows = rows - 1;
529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	private int checkBounds(int value, int max) {
559f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		if (value < 0)
569f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			return 0;
579f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		else if (value > max)
589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			return max;
599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		else
609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			return value;
619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public boolean isSelectingOrigin() {
649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		return selectingOrigin;
659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public void finishSelectingOrigin() {
689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		selectingOrigin = false;
699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public void decrementRow() {
729f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		if (selectingOrigin)
739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			setTop(top - 1);
749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		else
759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			setBottom(bottom - 1);
769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
789f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public void incrementRow() {
799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		if (selectingOrigin)
809f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			setTop(top + 1);
819f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		else
829f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			setBottom(bottom + 1);
839f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public void setRow(int row) {
869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		if (selectingOrigin)
879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			setTop(row);
889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		else
899f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			setBottom(row);
909f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
919f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	private void setTop(int top) {
939f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		this.top = bottom = checkBounds(top, maxRows);
949f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
959f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public int getTop() {
979f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		return Math.min(top, bottom);
989f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	private void setBottom(int bottom) {
1019f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		this.bottom = checkBounds(bottom, maxRows);
1029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
1039f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1049f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public int getBottom() {
1059f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		return Math.max(top, bottom);
1069f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
1079f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1089f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public void decrementColumn() {
1099f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		if (selectingOrigin)
1109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			setLeft(left - 1);
1119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		else
1129f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			setRight(right - 1);
1139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
1149f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public void incrementColumn() {
1169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		if (selectingOrigin)
1179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			setLeft(left + 1);
1189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		else
1199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			setRight(right + 1);
1209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
1219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public void setColumn(int column) {
1239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		if (selectingOrigin)
1249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			setLeft(column);
1259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		else
1269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			setRight(column);
1279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
1289f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	private void setLeft(int left) {
1309f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		this.left = right = checkBounds(left, maxColumns);
1319f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
1329f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1339f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public int getLeft() {
1349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		return Math.min(left, right);
1359f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
1369f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1379f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	private void setRight(int right) {
1389f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		this.right = checkBounds(right, maxColumns);
1399f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
1409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public int getRight() {
1429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		return Math.max(left, right);
1439f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
1449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1459f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public String copyFrom(VDUBuffer vb) {
1469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		int size = (getRight() - getLeft() + 1) * (getBottom() - getTop() + 1);
1479f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		StringBuffer buffer = new StringBuffer(size);
1499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		for(int y = getTop(); y <= getBottom(); y++) {
1519f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			int lastNonSpace = buffer.length();
1529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			for (int x = getLeft(); x <= getRight(); x++) {
1549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li				// only copy printable chars
1559f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li				char c = vb.getChar(x, y);
1569f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1579f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li				if (!Character.isDefined(c) ||
1589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li						(Character.isISOControl(c) && c != '\t'))
1599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li					c = ' ';
1609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li				if (c != ' ')
1629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li					lastNonSpace = buffer.length();
1639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li				buffer.append(c);
1659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			}
1669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			// Don't leave a bunch of spaces in our copy buffer.
1689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			if (buffer.length() > lastNonSpace)
1699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li				buffer.delete(lastNonSpace + 1, buffer.length());
1709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li			if (y != bottom)
1729f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li				buffer.append("\n");
1739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		}
1749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		return buffer.toString();
1769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
1779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1789f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	@Override
1799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	public String toString() {
1809f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		StringBuilder buffer = new StringBuilder();
1819f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1829f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append("SelectionArea[top=");
1839f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append(top);
1849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append(", bottom=");
1859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append(bottom);
1869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append(", left=");
1879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append(left);
1889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append(", right=");
1899f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append(right);
1909f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append(", maxColumns=");
1919f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append(maxColumns);
1929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append(", maxRows=");
1939f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append(maxRows);
1949f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append(", isSelectingOrigin=");
1959f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append(isSelectingOrigin());
1969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		buffer.append("]");
1979f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1989f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li		return buffer.toString();
1999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li	}
2009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li}
201