/* * ConcreteSplitViewer program for analazing splits. * Copyright (C) 2006-2007 Mytinski Leonid (Leonid.Mytinski@gmail.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ /* * StandardSplitViewer.java * * Created on 28 �?юнь 2006 г., 13:07 */ package ru.concretesoft.concretesplitviewer; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.LinkedList; import java.util.List; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import ru.spb.ConcreteSoft.tipWindow.MouseMoveQueue; import ru.spb.ConcreteSoft.tipWindow.TipWindow; /** * * @author Mytinski Leonid * * Panel for viewing splits in standatd way * Панель для отображения сплитов в стандартном виде */ public class StandardSplitViewer extends javax.swing.JPanel implements SplitViewer,ListDataListener,ListSelectionListener, MouseListener, MouseMotionListener{ private AthleteListModel aModel; private int[] xCoord; private int otst=5; private TipWindow tipWindow; private TipThreadSplitViewer tipThread; private List<XCoordinatesListener> listeners; private GlassStandartSplitViewerPanel glassPane; private int editingCPNumber; private AthleteIcon editingAthlete; private int yLocationOfStartDrag; /** * Creates new form StandardSplitViewer */ public StandardSplitViewer() { tipWindow = new TipWindow(); initComponents(); addMouseMotionListener(MouseMoveQueue.getInstance()); addMouseListener(this); addMouseMotionListener(this); listeners = new LinkedList<XCoordinatesListener>(); glassPane = new GlassStandartSplitViewerPanel(); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents private void initComponents() { setLayout(new java.awt.GridBagLayout()); }// </editor-fold>//GEN-END:initComponents @Override public void paint(Graphics g){ Graphics2D g2 = (Graphics2D)g; Dimension d = getSize(); g2.setPaint(Color.WHITE); g2.fillRect(0,0,d.width,d.height); FontMetrics fM = g2.getFontMetrics(); otst = fM.stringWidth("-000:00")+5; int width = d.width-otst; int height = d.height;//-heightStr-2; AthleteIcon[] athletes = (AthleteIcon[])(aModel.getSelectedValues()); int[] spl = aModel.getViewingSplits(); Distance dist = aModel.getDistance(); int size = athletes.length; if((spl!=null)&&(size>0)){ // Calculating CP's x coordinates xCoord = new int[spl.length]; if(dist!=null){ int totDist = Tools.calculateTotalLength(dist, spl); int curDist=otst; for(int i=0;i<spl.length;i++){ xCoord[i]=curDist + (int)((dist.getLengthOfDist(spl[i])/(double)totDist)*width); curDist = xCoord[i]; } } else { int sizeLap = width/spl.length; for(int i=0;i<spl.length;i++) xCoord[i] = sizeLap*(i+1); } // Draw vertical black line for each viewing CP g2.setPaint(Color.BLACK); for(int i=0;i<spl.length;i++){ g2.drawLine(xCoord[i],0,xCoord[i],height); } // Calculate and draw horizontal lines with time int yMax = athletes[size-1].getTotalTime().getTimeInSeconds(); int hTime = fM.getHeight(); double stepTime = 30.0; int nT =(int) (yMax/stepTime); while((height/nT)<(hTime+10)){ stepTime*=2; nT = (int) (yMax/stepTime); } Time tmp = new Time(0,2); String s = tmp.getTimeString(); g2.setPaint(Color.BLACK); g2.drawString(s,otst-fM.stringWidth(s),height-1); float dash1[] = {10.0f}; BasicStroke dashed = new BasicStroke(1.0f, java.awt.BasicStroke.CAP_BUTT, java.awt.BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f); g2.setStroke(dashed); for(int i=1;i<nT;i++){ int timeCur = Math.abs((int)(stepTime*i)); tmp.setTimeInSeconds(timeCur); s = tmp.getTimeString(); int yH = height - (int)((stepTime*i / yMax)*height); g2.setPaint(Color.BLACK); g2.drawString(s,otst-fM.stringWidth(s),yH); g2.setPaint(Color.LIGHT_GRAY); g2.drawLine(otst,yH,otst + width,yH); } tmp.setTimeInSeconds((int)(stepTime*nT)); s = tmp.getTimeString(); g2.setPaint(Color.BLACK); g2.drawString(s,otst-fM.stringWidth(s),hTime+1); int yH = height - (int)((stepTime*nT / yMax)*height); g2.setPaint(Color.LIGHT_GRAY); g2.drawLine(otst,yH,otst + width,yH); // Draw charts g2.setStroke(new BasicStroke(1.0f)); for(int j=0;j<size;j++){ g2.setPaint(athletes[j].getColor()); Athlete tmpA = athletes[j].getAthlete(); int x = xCoord[0]; int y = height - (int)((tmpA.getLap(spl[0]).getTimeInSeconds() / (double)yMax)*height); int totTime = tmpA.getLap(spl[0]).getTimeInSeconds(); g2.drawLine(otst,height,x,y); for(int i=1;i<spl.length;i++){ int x1 = xCoord[i]; if (tmpA.getLap(spl[i]).getTimeInSeconds()==0) break; totTime += tmpA.getLap(spl[i]).getTimeInSeconds(); int y1 = height - (int)(( totTime / (double)yMax)*height); g2.drawLine(x,y,x1,y1); x=x1; y=y1; } } }else{ xCoord=null; } // Notify listeners about changing of x coordinates for(XCoordinatesListener e: listeners){ e.xCoordinatesChanged(this); } } @Override public String toString(){ return java.util.ResourceBundle.getBundle("ru/concretesoft/concretesplitviewer/i18on").getString("Standart_View"); } // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables public void removeSplit(int x) { if(xCoord!=null){ for(int i=0;i<xCoord.length;i++){ if(x<xCoord[i]){ aModel.removeSplitsForN(aModel.getViewingSplits()[i]); break; } } } } public void setModel(AthleteListModel aM){ aModel = aM; aM.addListDataListener(this); aM.addListSelectionListener(this); } public AthleteListModel getModel(){ return aModel; } public int getSplit(Point p){ if(xCoord!=null){ for(int i=0;i<xCoord.length; i++){ if(p.getX()<xCoord[i]){ return aModel.getViewingSplits()[i]; }else; } }else{ return -1; } return -1; } public void intervalAdded(ListDataEvent e) { contentsChanged(e); } public void intervalRemoved(ListDataEvent e) { contentsChanged(e); } public void contentsChanged(ListDataEvent e) { repaint(); } public void valueChanged(ListSelectionEvent e) { repaint(); } public void mouseClicked(MouseEvent evt) { if((evt.getButton()==MouseEvent.BUTTON2)||(MouseEvent.getMouseModifiersText(evt.getModifiers()).equals("Shift+Button1"))){ aModel.restoreAllSplits(); } else if(evt.getButton()==MouseEvent.BUTTON1){ removeSplit(evt.getX()); } } public void mousePressed(MouseEvent e) { //Find near node int x = e.getX(); int y = e.getY(); for(int i = 0; i < xCoord.length; i++){ // System.out.println(x+" "+xCoord[i]); if(Math.abs(xCoord[i]-x) < 5){// 5 horizontal points on both sides editingCPNumber = i;//index(only from viewing) of control point which would be edited AthleteIcon[] selectedAthletes = (AthleteIcon[]) aModel.getSelectedValues(); int yMax = selectedAthletes[selectedAthletes.length-1].getTotalTime().getTimeInSeconds(); double scale = yMax / (double)getSize().height; for(int j = 0; j < selectedAthletes.length; j++){ int yA = 0; for(int k=0;k<=editingCPNumber;k++){ yA += selectedAthletes[j].getAthlete().getLap(aModel.getViewingSplits()[k]).getTimeInSeconds(); } yA = getSize().height - (int)(yA/scale); // System.out.println(y+" "+yA); if(Math.abs(y-yA)<2){// 2 vertical points on both sides yLocationOfStartDrag = yA;// Store y coordinate(of node) of start dragging editingAthlete = selectedAthletes[j];// set editing athlete // put all needed parameters to glass panel glassPane.setAthlete(editingAthlete); glassPane.setViewingSplits(aModel.getViewingSplits()); glassPane.setCPsNumber(editingCPNumber); glassPane.setScale(scale); glassPane.setXCoord(xCoord); glassPane.setYMax(yMax); glassPane.setOtst(otst); glassPane.setLocationOnScreen(this.getLocationOnScreen()); glassPane.setVisible(true); glassPane.setYLocation(y); // System.out.println(editingAthlete.getAthlete().getFamilyName()); break; } } break; } else if(x < xCoord[i]){ break; } } } public void mouseReleased(MouseEvent e) { glassPane.setVisible(false); glassPane.setAthlete(null); if(editingAthlete == null){ return ; } AthleteIcon[] selectedAthletes = (AthleteIcon[]) aModel.getSelectedValues(); int yMax = selectedAthletes[selectedAthletes.length-1].getTotalTime().getTimeInSeconds(); double scale = yMax / (double)getSize().height; editingCPNumber = aModel.getViewingSplits()[editingCPNumber]; Time oldTime = editingAthlete.getAthlete().getLap(editingCPNumber); int diff = e.getY()-yLocationOfStartDrag; int diffInSec = (int)(diff*scale); Time newTime = new Time(0, 2); newTime.setTimeInSeconds(oldTime.getTimeInSeconds()-diffInSec); editingAthlete.getAthlete().setTimeOnLap(newTime, editingCPNumber); editingAthlete = null; editingCPNumber = 0; } public void mouseEntered(MouseEvent e) { tipThread = new TipThreadSplitViewer(tipWindow, this); tipThread.start(); } public void mouseExited(MouseEvent e) { tipThread.finish(); } public int[] getXCoordinatesOfLaps() { return xCoord; } public void addXCoordinatesListener(XCoordinatesListener listener) { listeners.add(listener); } public void removeXCoordinatesListener(XCoordinatesListener listener) { listeners.remove(listener); } public GlassStandartSplitViewerPanel getGlassPane() { return glassPane; } public void mouseDragged(MouseEvent e) { if (editingAthlete == null){ return ; } glassPane.setYLocation(e.getY()); } public void mouseMoved(MouseEvent e) { } }