gt: 		if (firstRowTouched<row){ // we've gone down;
context: /* Mesquite source code.  Copyright 1997 and onward, W. Maddison and D. Maddison. 
  
  
  Disclaimer:  The Mesquite source code is lengthy and we are few.  There are no doubt inefficiencies and goofs in this code. 
  The commenting leaves much to be desired. Please approach this source code with the spirit of helping out.
  Perhaps with your help we can be more than a few, and make Mesquite better.
  
  Mesquite is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY.
  Mesquite's web site is http://mesquiteproject.org
  
  This source code and its compiled class files are free and modifiable under the terms of 
  GNU Lesser General Public License.  (http://www.gnu.org/copyleft/lesser.html)
   */
  package mesquite.align.MultiBlockSplitter;
  
  
  import java.util.*;
  import java.awt.*;
  import java.awt.image.*;
  import mesquite.lib.*;
  import mesquite.lib.characters.*;
  import mesquite.lib.duties.*;
  import mesquite.lib.table.*;
  import mesquite.categ.lib.*;
  import mesquite.align.lib.*;
  
  /* ======================================================================== */
  public  class MultiBlockSplitter extends MultiBlockMoveBase {
  	protected MultiBlockTool moveTool;
  	CellBlock leftCellBlock =null;
  	CellBlock rightCellBlock =null;
  
  	boolean defaultMoveWholeSequenceOnOneSide = false;
  	MesquiteBoolean moveWholeSequenceOnOneSide =new MesquiteBoolean(defaultMoveWholeSequenceOnOneSide);
  
  	protected int endOfLeftBlockAtTouch = 0;
  	protected int startOfRightBlockAtTouch = 0;
  
  
  	public Class getDutyClass() {
  		return MultiBlockSplitter.class;
  	}
  	public String getDutyName() {
  		return "Multi Block Splitter";
  	}
  
  	/*.................................................................................................................*/
  	public boolean startJob(String arguments, Object condition, boolean hiredByName) {
  		if (containerOfModule() instanceof MesquiteWindow) {
  			MesquiteCommand touchCommand = MesquiteModule.makeCommand("moveTouchCell",  this);
  			touchCommand.setSuppressLogging(true);
  			MesquiteCommand dragCommand = MesquiteModule.makeCommand("moveDragCell",  this);
  			dragCommand.setSuppressLogging(true);
  			MesquiteCommand dropCommand = MesquiteModule.makeCommand("moveDropCell",  this);
  			dropCommand.setSuppressLogging(true);
  			moveTool = new MultiBlockTool(this, "multiBlockSplitter", getPath(), "MultiBlockSplitter.gif", 8,8,"CrossHair.gif",8,8,"Splits multiple sequences","This tool splits and moves blocks of sequences for manual alignment.", touchCommand, dragCommand, dropCommand);
  			setOptionTools();
  			moveTool.setDeselectIfOutsideOfCells(false);
  			moveTool.setAcceptsOutsideDrops(true);
  			moveTool.setOptionImageFileName( "multiBlockSplitterOption.gif", 8, 8);
  
  			((MesquiteWindow)containerOfModule()).addTool(moveTool);
  			moveTool.setPopUpOwner(this);
  			setUseMenubar(false); //menu available by touching on button
  		}
  		else return sorry(getName() + " couldn't start because the window with which it would be associated is not a tool container.");
  		addBasicMultiSequenceMenuItems();
  		addCheckMenuItem(null, "Move full sequences on each side", makeCommand("toggleAllOnSide",  this), moveWholeSequenceOnOneSide);
  		return true;
  	}
  	/*.................................................................................................................*/
  	public void addExtraSnapshotItems(Snapshot temp) {
  		if (moveWholeSequenceOnOneSide.getValue()!=defaultMoveWholeSequenceOnOneSide)
  			temp.addLine("toggleAllOnSide " + moveWholeSequenceOnOneSide.toOffOnString());
  	}
  	/*.................................................................................................................*/
  	public void setOptionTools(){
  	}
  	/* ................................................................................................................. */
  	public void inhibitionChanged(){
  		if (moveTool!=null && data!=null)
  			moveTool.setEnabled(!data.isEditInhibited());
  	}
  
  	/*.................................................................................................................*/
  	public boolean canMoveLeft(){
  		if (leftCellBlock==null || rightCellBlock==null)
  			return false;
  		return (!leftCellBlock.isLocked()&&leftCellBlock.getCurrentLeftMovement()<leftCellBlock.getMaxLeftMovement());
  	}
  	/*.................................................................................................................*/
  	public boolean canMoveRight(){
  		if (leftCellBlock==null || rightCellBlock==null)
  			return false;
  		return (!rightCellBlock.isLocked()&&rightCellBlock.getCurrentRightMovement()<rightCellBlock.getMaxRightMovement());
  	}
  	public void clearBetweenSelection() {
  		table.clearBetweenColumnSelection();
  		table.clearBetweenRowSelection();
  		table.repaintAll();
  	}
  	/*.................................................................................................................*/
  	public boolean wholeSelectedBlock(){
  		return false;
  	}
  	/*.................................................................................................................*/
  	public boolean wholeSequenceToLeft(){
  		return moveWholeSequenceOnOneSide.getValue();
  	}
  	/*.................................................................................................................*/
  	public boolean wholeSequenceToRight(){
  		return moveWholeSequenceOnOneSide.getValue();
  	}
  	/*.................................................................................................................*
  	/** Returns CompatibilityTest so other modules know if this is compatible with some object. */
  	public CompatibilityTest getCompatibilityTest(){
  		return new RequiresAnyMolecularData();
  	}
  	public void initialize(MesquiteTable table, CharacterData data) {
  		leftCellBlock = new CellBlock((CategoricalData)data, table);
  		leftCellBlock.setLeft(true);
  		leftCellBlock.setRight(false);
  		rightCellBlock = new CellBlock((CategoricalData)data, table);
  		rightCellBlock.setRight(true);
  		rightCellBlock.setLeft(false);
  		data.addListener(this);
  		inhibitionChanged();
  
  	}
  	/*.................................................................................................................*/
  	protected void stopMoving() {
  		table.clearBetweenColumnSelection();
  		super.stopMoving();
  	}
  	/*.................................................................................................................*/
  	void switchBlocks(boolean switchToRight) {
  		if (switchToRight) {
  			if (!rightCellBlock.isLocked()) {
  				leftCellBlock.restoreCharBlock(dataChanged);
  				currentBlock = rightCellBlock;
  				if (leftEdge)
  					effectiveFirstColumnTouched = firstColumnTouched;
  				else
  					effectiveFirstColumnTouched = firstColumnTouched+1;
  				currentlyMovingRight = true;
  			}
  		} else {
  			if (!leftCellBlock.isLocked()) {
  				rightCellBlock.restoreCharBlock(dataChanged);
  				currentBlock = leftCellBlock;
  				if (leftEdge)
  					effectiveFirstColumnTouched = firstColumnTouched-1;
  				else
  					effectiveFirstColumnTouched = firstColumnTouched;
  				currentlyMovingRight = false;
  			}
  		}
  		currentMoveFromOriginal = 0;
  
  	}
  	/*.................................................................................................................*/
  	public void checkSwitchBlocks(int moveFromOriginal) {
  
  		if (canMoveRight() && moveFromOriginal>0 &&  !currentlyMovingRight) {  //was dragging left, now switch to dragging right
  			switchBlocks(true);
  		}
  		else if (canMoveLeft() && moveFromOriginal<0 && currentlyMovingRight) {  //was dragging right, now switch to dragging left
  			switchBlocks(false);
  		}
  
  	}
  	/*.................................................................................................................*/
  	public void addCharactersToBlocks(int added, boolean toStart) {
  		leftCellBlock.addCharacters(Math.abs(added),toStart);
  		rightCellBlock.addCharacters(Math.abs(added),toStart);
  	}
  
  	/*.................................................................................................................*/
  	protected void redrawTable() {
  		table.redrawOldAndNewBlocks(currentBlock.getPreviousFirstCharInBlock(), currentBlock.getPreviousLastCharInBlock(), currentBlock.getCurrentFirstCharInBlock(), currentBlock.getCurrentLastCharInBlock(), currentBlock.getWhichTaxa(),false);
  	}
  	/*.................................................................................................................*/
  	public void resetBlocks() {
  		leftCellBlock.reset();
  		rightCellBlock.reset();
  	}
  	public  void getFirstAndLastSequences(boolean optionDown){
  		if (!optionDown) {
  			firstSequenceInBlock = table.getStartBetweenRowSelection();
  			lastSequenceInBlock = table.getEndBetweenRowSelection();
  		}
  		else {
  			firstSequenceInBlock = 0;
  			lastSequenceInBlock = data.getNumTaxa()-1;
  		}
  	}
  	public  Bits getWhichTaxa(boolean optionDown){
  		Bits whichTaxa = new Bits(data.getNumTaxa());
  		for (int it=table.getStartBetweenRowSelection(); it<=table.getEndBetweenRowSelection(); it++)
  			whichTaxa.setBit(it);
  		if (optionDown) 
  			whichTaxa.invertAllBits();
  		return whichTaxa;
  
  	}
  
  	/*.................................................................................................................*/
  	public boolean findBlocks(boolean optionDown) {
  		MesquiteInteger firstInBlock= new MesquiteInteger();
  		MesquiteInteger lastInBlock= new MesquiteInteger();
  		MesquiteBoolean cellHasInapplicable = new MesquiteBoolean(false);
  		MesquiteBoolean leftIsInapplicable = new MesquiteBoolean(false);
  		MesquiteBoolean rightIsInapplicable = new MesquiteBoolean(false);
  		int startOfBlock = table.numColumnsTotal;
  		int endOfBlock = 0;
  
  		leftCellBlock.setWhichTaxa(table.getStartBetweenRowSelection(), table.getEndBetweenRowSelection());
  		if (optionDown)
  			leftCellBlock.reverseWhichTaxa();
  		leftCellBlock.getCellBlock(endOfLeftBlockAtTouch, endOfLeftBlockAtTouch, leftCellBlock.getWhichTaxa(), firstInBlock, lastInBlock,  wholeSelectedBlock(), wholeSequenceToLeft(), wholeSequenceToRight(), cellHasInapplicable, leftIsInapplicable, rightIsInapplicable);
  		startOfBlock = MesquiteInteger.minimum(startOfBlock,firstInBlock.getValue());
  		rightCellBlock.setWhichTaxa(table.getStartBetweenRowSelection(), table.getEndBetweenRowSelection());
  		if (optionDown)
  			rightCellBlock.reverseWhichTaxa();
  		rightCellBlock.getCellBlock(startOfRightBlockAtTouch,startOfRightBlockAtTouch, rightCellBlock.getWhichTaxa(), firstInBlock, lastInBlock,  wholeSelectedBlock(), wholeSequenceToLeft(), wholeSequenceToRight(), cellHasInapplicable, leftIsInapplicable, rightIsInapplicable);
  		endOfBlock = MesquiteInteger.maximum(endOfBlock,lastInBlock.getValue());
  
  		if (rightIsInapplicable.getValue()&& leftIsInapplicable.getValue()) {
  			firstColumnTouched = -1;
  			return false;
  		}
  		if (leftIsInapplicable.getValue()){
  			leftCellBlock.setLocked(true);
  			currentlyMovingRight=true;
  		}
  		if (rightIsInapplicable.getValue()) {
  			rightCellBlock.setLocked(true);
  			currentlyMovingRight=false;
  		}
  
  		leftCellBlock.setAllBlocks(startOfBlock, firstColumnTouched, firstSequenceInBlock, lastSequenceInBlock);
  		rightCellBlock.setAllBlocks(firstColumnTouched+1, endOfBlock, firstSequenceInBlock, lastSequenceInBlock);
  		leftCellBlock.setMaximumMovements();
  		rightCellBlock.setMaximumMovements();
  
  		if (currentlyMovingRight)
  			currentBlock=rightCellBlock;
  		else
  			currentBlock = leftCellBlock;
  		return true;
  	}
  	/*.................................................................................................................*/
  
  	public void getSplitRows(MesquiteInteger top, MesquiteInteger bottom, int row, int percentVertical, boolean onDrop) {
  		if (row == table.getMatrixPanel().BEYONDMATRIX) row = table.numRowsTotal-1;
  		if (row<0) row=0;
  		int topRow = firstRowTouched;
  		int bottomRow = row;
  