content: package aliview.sequencelist;
  
  import java.awt.Component;
  import java.awt.Dimension;
  import java.awt.Font;
  import java.awt.FontMetrics;
  import java.awt.Graphics;
  import java.awt.Graphics2D;
  import java.awt.Insets;
  import java.awt.Point;
  import java.awt.Rectangle;
  import java.awt.RenderingHints;
  import java.awt.datatransfer.FlavorMap;
  import java.awt.dnd.Autoscroll;
  import java.awt.dnd.DropTarget;
  import java.awt.dnd.DropTargetListener;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  import java.util.TooManyListenersException;
  
  import javax.swing.BoundedRangeModel;
  import javax.swing.DefaultBoundedRangeModel;
  import javax.swing.DefaultListCellRenderer;
  import javax.swing.DefaultListModel;
  import javax.swing.DropMode;
  import javax.swing.InputMap;
  import javax.swing.JPanel;
  import javax.swing.JScrollBar;
  import javax.swing.JScrollPane;
  import javax.swing.JViewport;
  import javax.swing.ListCellRenderer;
  import javax.swing.ListModel;
  import javax.swing.ListSelectionModel;
  import javax.swing.SwingUtilities;
  import javax.swing.border.EmptyBorder;
  import javax.swing.event.ChangeListener;
  import javax.swing.plaf.basic.BasicListUI;
  
  import org.apache.log4j.Logger;
  
  import utils.OSNativeUtils;
  import aliview.AliView;
  import aliview.AliViewWindow;
  import aliview.UndoControler;
  import aliview.gui.pane.NotUsed_AlignmentPane_Orig;
  import aliview.sequences.Sequence;
  import aliview.sequences.SequenceSelectionModel;
  import aliview.settings.Settings;
  import aliview.undo.UndoSavedStateSequenceOrder;
  
  
  public class SequenceJList extends javax.swing.JList implements Autoscroll{
  	private static final Logger logger = Logger.getLogger(SequenceJList.class);
  	// todo These two constants should be synchronized in one class (AlignmentPane & this)
  	private static final int MIN_CHAR_SIZE = 2;
  	private static final int MAX_CHAR_SIZE = 100;
  	private double charHeight;
  	private ListCellRenderer storedCellRenderer;
  	private BasicListUI builist;
  	//private DefaultListModel<String> notUsed;
  	private JScrollPane alignmentScrollPane;
  	private JScrollPane listScrollPane;
  
  
  	public SequenceJList(AlignmentListModel model, double charHeight, AliViewWindow aliWindow) {
  		super(model);
  		//this.addMouseMotionListener(new SequenceListMouseListener());
  		//this.getParent().addMouseMotionListener(new SequenceListMouseListener());
  
  		/*
  		DropTarget old = this.getDropTarget();
  		DropTarget newDT = new MyOtherDropTarget();	
  		newDT.setComponent(old.getComponent());
  		newDT.setFlavorMap(old.getFlavorMap());
  		newDT.setDefaultActions(old.getDefaultActions());
  		this.setDropTarget(newDT);
  		 */
  
  		//jComponent.setTransferHandler(new MyTransferHandler());
  		this.setDropMode(DropMode.INSERT);
  		this.setTransferHandler(new SequenceTransferHandler(aliWindow));
  
  		// Add modified drop target due to otherwise erratic drag-scrolling
  		DropTarget original = this.getDropTarget();// the Swing DropTarget
  		MyDropTarget myDropTarget = new MyDropTarget();
  		try {
  			myDropTarget.addDropTargetListener(original);
  		} catch (TooManyListenersException e) {
  			// TODO Auto-generated catch block
  			e.printStackTrace();
  		}// delegate for original behavior
  		this.setDropTarget(myDropTarget);
  
  		this.setDragEnabled(true);
  
  
  		this.setSelectionModel(model.getAlignmentSelectionModel().getSequenceListSelectionModel());
  		//this.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
  
  
  		this.setCharSize(charHeight);
  
  
  		// int width = model.getLongestSequenceName();
  		// int fixedWidth = 300;
  
  		this.setCellRenderer(new FasterTextCellRenderer()); 	
  
  
  		this.setBorder(new EmptyBorder(0,0,0,0));
  
  		// Remove default ctrl-C action (because it only copys names in list and not sequence)
  		InputMap map = this.getInputMap();
  
  		// remove from input map is not working so I am replacing one with nothing
  		map.put(OSNativeUtils.getPasteKeyAccelerator(),"null");
  		map.put(OSNativeUtils.getCopyKeyAccelerator(),"null");
  		map.put(OSNativeUtils.getCopySelectionAsFastaKeyAccelerator(),"null");
  		map.put(OSNativeUtils.getMoveSelectionUpKeyAccelerator(),"null");
  		map.put(OSNativeUtils.getMoveSelectionDownKeyAccelerator(),"null");
  		map.put(OSNativeUtils.getIncreaseFontSizeKeyAccelerator(),"null");
  		map.put(OSNativeUtils.getDecreaseFontSizeKeyAccelerator(),"null");
  
  	}
  
  	@Override
  	public AlignmentListModel getModel() {
  		// TODO Auto-generated method stub
  		return (AlignmentListModel) super.getModel();
  	}
  
  	public void setModel(AlignmentListModel model) {
  		super.setModel(model);
  	}
  
  
  	public void paintComponent(Graphics g){
  		long startTime = System.currentTimeMillis();
  		Graphics2D g2 = (Graphics2D) g;
  		super.paintComponent(g);
  		long endTime = System.currentTimeMillis();
  		logger.info("Draw JList took " + (endTime - startTime) + " milliseconds");	
  	}
  
  	@Override
  	public void validate() {
  		long startTime = System.currentTimeMillis();
  		super.validate();
  		long endTime = System.currentTimeMillis();
  		synchAlignmentScrollPane();
  		logger.info("Validate JList took " + (endTime - startTime) + " milliseconds");	
  	}
  
  
  	private void synchAlignmentScrollPane(){
  		logger.info("synch ScrollPanes");
  		JScrollPane source = listScrollPane;
  		JScrollPane dest = alignmentScrollPane;
  		Point viewPos = new Point(dest.getViewport().getViewPosition().x, source.getViewport().getViewPosition().y );
  		dest.getViewport().setViewPosition(viewPos);	
  	}
  
  	@Override
  	public Dimension getPreferredScrollableViewportSize() {
  		//logger.info("super.getPreferredScrollableViewportSize();" + super.getPreferredScrollableViewportSize());
  		return super.getPreferredScrollableViewportSize();
  	}
  
  	public void setCharSize(double charHeight) {
  		this.charHeight = charHeight;
  
  		// And now check font size
  		float listFontSize = (int)(charHeight -1);
  		if(listFontSize > 13 && !Settings.getUseCustomFontSize().getBooleanValue()){	
  			listFontSize = 13;
  		}	
  		updateCharSize(listFontSize);
  	}
  
  	@Override
  	public void revalidate(){
  		super.revalidate();
  	}
  
  	@Override
  	public Dimension getPreferredSize() {
  		//logger.info(super.getPreferredSize());
  		return super.getPreferredSize();
  	}
  
  	private void updateCharSize(float listFontSize) {
  
  
  		// Fixed cell height is needed or otherwise all items are loaded
  		this.setFixedCellHeight((int)charHeight);
  		this.setFixedCellWidth(this.getModel().getLongestSequenceName()*(int)(charHeight));
  
  		this.setFont(this.getFont().deriveFont(listFontSize));
  
  
  		// Remove List cell renderer att small sizes (saves a lot of drawing speed)
  		if(charHeight < 3 && this.getCellRenderer() != null){
  			this.storedCellRenderer = this.getCellRenderer();
  			this.setCellRenderer(null);
  		}else if(charHeight >= 3 && this.getCellRenderer() == null){
  			this.setCellRenderer(this.storedCellRenderer);
  		}
  
  	}
  
  
  	/*
  	 * This is for drop support from SequenceTransferHandler
  	 */
  	public void moveSelectedSequencesTo(int index) {
  		getModel().moveSelectedSequencesTo(index);
  	}
  
  	public void addSynchPanes(JScrollPane listScrollPane, JScrollPane alignmentScrollPane) {
  		this.listScrollPane = listScrollPane;
  		this.alignmentScrollPane = alignmentScrollPane;	
  	}
  
  	/*
  	 * 
  	 * Drop target Autoscroll interface
  	 * 
  	 */
  
  	public Insets getAutoscrollInsets(){
  		//return autoscrollInsets;
  		return new Insets(this.HEIGHT, 100, this.HEIGHT, 100);
  		//return getInsets();
  	}
  
  
  	public void autoscroll(Point cursor) {
  		//	logger.info("autoscroll loc=" + cursor);
  		Rectangle visiRect = this.getVisibleRect();
  		//	logger.info("visiRect=" + visiRect);
  
  
  		// depending on how close pointer is to border the more indexex get visible at a time
  
  		int topDist = cursor.y - visiRect.y;
  		int bottomDist = (visiRect.y + visiRect.height) - cursor.y;
  
  		int scrollSpeed = 0;
  		if(topDist < 20){
  			scrollSpeed = -1;
  		}
  		if(topDist < 15){
  			scrollSpeed = -2;
  		}
  		if(topDist < 10){
  			scrollSpeed = -3;
  		}
  		if(topDist < 5){
  			scrollSpeed = -4;
  		}
  		if(topDist < 2){
  			scrollSpeed = -5;
  		}
  
  		if(bottomDist < 20){
  			scrollSpeed = 1;
  		}
  		if(bottomDist < 15){
  			scrollSpeed = 2;
  		}
  		if(bottomDist < 10){
  			scrollSpeed = 3;
  		}
  		if(bottomDist < 5){
  			scrollSpeed = 4;
  		}
  		if(bottomDist < 2){
  			scrollSpeed = 5;
  		}
  
  		if(scrollSpeed > 0){
  			int lastVisible = this.getLastVisibleIndex();
  			ensureIndexIsVisible(lastVisible + scrollSpeed);
  		}
  
  		if(scrollSpeed < 0){
  			int firstVisible = this.getFirstVisibleIndex();
  			ensureIndexIsVisible(firstVisible + scrollSpeed);
  		}
  
  	}
  
  	public Point getFirstSelectedCellPos(){
  		int index = getSelectedIndex();
  		if(index < 0){
  			return new Point(0,0);
  		}
  		Point pos = indexToLocation(index);
  		SwingUtilities.convertPointToScreen(pos, this);
  		return pos;
  	}
  
  
  }
  