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;
}
}