package jp.sourceforge.acerola3d.a3editor;

import javax.media.j3d.BoundingSphere;
import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;
import javax.vecmath.Point3d;
import javax.vecmath.Quat4d;
import javax.vecmath.Vector3d;

import java.awt.*;
import java.awt.event.*;
import java.util.*;

import jp.sourceforge.acerola3d.a3.*;
import jp.sourceforge.acerola3d.a3panels.*;

class A3eActionEditorGUI extends JPanel implements ActionListener {
    private static final long serialVersionUID = 1L;
    A3Editor a3editor;
    A3eActionEditor actionEditor;
    JToggleButton viewMode; //めんどうなのでJToggleButtonにしちゃった
    double canvasWidthInPWorld = 1.0;
    MyExamController myExamController;
    Skeleton skeleton;
    HashMap<String,CenteredVRML> vrmls = new HashMap<String,CenteredVRML>();
    ArrayList<Edit> editSequence = new ArrayList<Edit>();
    int editSequenceIndex = -1;

    ////GUI
    //leftBox
    JComboBox actionCB;
    JButton deleteActionB;
    JButton renameActionB;
    JButton newActionB;
    NewActionInputPanel newActionInputPanel;
    JComboBox bvhCB;
    JCheckBox loopCB;
    JButton segnoB;
    JLabel segnoL;
    JButton dalsegnoB;
    JLabel dalsegnoL;
    JComboBox soundFileCB;
    JComboBox soundTypeCB;
    JCheckBox soundLoopCB;
    JButton soundGainB;
    JLabel soundGainL;
    JCheckBox soundContinueCB;
    //centerBox
    JToggleButton camB;
    JToggleButton topB;
    JToggleButton frontB;
    JToggleButton sideB;
    JButton adjustB;
    JButton bigB;
    JButton smallB;
    JButton upB;
    JButton downB;
    JButton rightB;
    JButton leftB;
    A3Canvas canvas;
    //rightBox
    JComboBox editModeCB;
    JCheckBox measureCB;
    JComboBox boneCB;
    JLabel vrmlL;
    JComboBox vrmlCB;
    JButton undoB;
    JButton redoB;

    Action3D measure;
    Action3D empty;
    Action3D speaker;

    A3eActionEditorGUI(A3eActionEditor ae,A3Editor editor) {
        a3editor = editor;
        actionEditor = ae;

        setLayout(new BorderLayout());
        MyHBox baseBox = new MyHBox();
        add(baseBox,BorderLayout.CENTER);

        //全体構成
        MyVBox leftBox = new MyVBox();
        baseBox.myAdd(leftBox,0);
        MyVBox centerBox = new MyVBox();
        baseBox.myAdd(centerBox,1);
        MyVBox rightBox = new MyVBox();
        baseBox.myAdd(rightBox,0);

        //****leftBox****
        MyVBox vBox = null;
        MyHBox hBox = null;

        vBox = new MyVBox();
        LineBorder lb = new LineBorder(Color.BLUE,2);
        TitledBorder tb = new TitledBorder(lb,"アクション");
        vBox.setBorder(tb);
        leftBox.myAdd(vBox,0);
        vBox.myAdd(new JLabel("アクション名:"),0);
        actionCB = new JComboBox();
        actionCB.addActionListener(this);
        actionCB.setMaximumSize(new Dimension(10000,actionCB.getPreferredSize().height));
        //actionCB.setEditable(true);
        vBox.myAdd(actionCB,0);

        deleteActionB = new JButton("このアクションを削除");
        deleteActionB.addActionListener(this);
        vBox.myAdd(deleteActionB,0);
        renameActionB = new JButton("アクション名の変更");
        renameActionB.addActionListener(this);
        vBox.myAdd(renameActionB,0);
        newActionB = new JButton("新しいアクションを追加");
        newActionB.addActionListener(this);
        vBox.myAdd(newActionB,0);
        newActionInputPanel = new NewActionInputPanel();

        vBox = new MyVBox();
        lb = new LineBorder(Color.BLUE,2);
        tb = new TitledBorder(lb,"モーション");
        vBox.setBorder(tb);
        leftBox.myAdd(vBox,0);
        //BVH
        vBox.myAdd(new JLabel("BVH File"),0);
        bvhCB = new JComboBox();
        bvhCB.addActionListener(this);
        vBox.myAdd(bvhCB,1);
        //ループ
        loopCB = new JCheckBox("ループする");
        loopCB.addActionListener(this);
        vBox.myAdd(loopCB,0);
        //segno
        vBox.myAdd(new JLabel("segno:"),0);
        hBox = new MyHBox();
        vBox.myAdd(hBox,0);
        segnoB = new JButton("変更");
        segnoB.addActionListener(this);
        hBox.myAdd(segnoB,0);
        segnoL = new JLabel("0.0");
        hBox.myAdd(segnoL,1);
        //dalsegno
        vBox.myAdd(new JLabel("dalsegno:"),0);
        hBox = new MyHBox();
        vBox.myAdd(hBox,0);
        dalsegnoB = new JButton("変更");
        dalsegnoB.addActionListener(this);
        hBox.myAdd(dalsegnoB,0);
        dalsegnoL = new JLabel("-1.0");
        hBox.myAdd(dalsegnoL,1);

        vBox = new MyVBox();
        lb = new LineBorder(Color.BLUE,2);
        tb = new TitledBorder(lb,"サウンド");
        vBox.setBorder(tb);
        leftBox.myAdd(vBox,0);
        vBox.myAdd(new JLabel("ファイル:"),0);
        soundFileCB = new JComboBox();
        soundFileCB.addActionListener(this);
        vBox.myAdd(soundFileCB,0);
        vBox.myAdd(new JLabel("タイプ:"),0);
        soundTypeCB = new JComboBox();
        soundTypeCB.addItem("PointSound");
        soundTypeCB.addItem("Background");
        soundTypeCB.addItem("ConeSound");
        soundTypeCB.addActionListener(this);
        vBox.myAdd(soundTypeCB,0);
        soundLoopCB = new JCheckBox("ループ");
        soundLoopCB.addActionListener(this);
        vBox.myAdd(soundLoopCB,0);
        vBox.myAdd(new JLabel("ゲイン"),0);
        hBox = new MyHBox();
        vBox.myAdd(hBox,0);
        soundGainB = new JButton("変更");
        soundGainB.addActionListener(this);
        hBox.myAdd(soundGainB,0);
        soundGainL = new JLabel("1.0");
        hBox.myAdd(soundGainL,1);
        soundContinueCB = new JCheckBox("継続");
        soundContinueCB.addActionListener(this);
        soundContinueCB.setSelected(true);
        vBox.myAdd(soundContinueCB,0);

        //Glue
        leftBox.myAdd(Box.createVerticalGlue(),1);

        //****centerBox****
        //centerBoxの構成
        MyHBox topBox = new MyHBox();
        centerBox.myAdd(topBox,0);
        MyVBox topLBox = new MyVBox();
        topBox.myAdd(topLBox,1);
        MyVBox topCBox = new MyVBox();
        topBox.myAdd(topCBox,1);
        MyVBox topRBox = new MyVBox();
        topBox.myAdd(topRBox,1);
        canvas = A3Canvas.createA3Canvas(300,300);
        MyMouseListener ml = new MyMouseListener(this);
        canvas.addA3Listener(ml);
        canvas.addMouseMotionListener(ml);
        centerBox.myAdd(canvas,1);
        //topLBox
        MyHBox topLUBox = new MyHBox();
        topLBox.myAdd(topLUBox,0);
        topB = new JToggleButton("top");
        topB.addActionListener(this);
        topLUBox.myAdd(topB,1);
        camB = new JToggleButton("cam");
        camB.addActionListener(this);
        topLUBox.myAdd(camB,1);
        MyHBox topLDBox = new MyHBox();
        topLBox.myAdd(topLDBox,0);
        frontB = new JToggleButton("front");
        frontB.addActionListener(this);
        topLDBox.myAdd(frontB,1);
        sideB = new JToggleButton("side");
        sideB.addActionListener(this);
        topLDBox.myAdd(sideB,1);
        ButtonGroup bg = new ButtonGroup();
        bg.add(topB);
        bg.add(camB);
        bg.add(frontB);
        bg.add(sideB);
        frontB.setSelected(true);
        //topCBox
        adjustB = new JButton("adjust");
        adjustB.addActionListener(this);
        topCBox.myAdd(adjustB,0);
        MyHBox topCCBox = new MyHBox();
        topCBox.myAdd(topCCBox,0);
        bigB = new JButton("+");
        bigB.addActionListener(this);
        topCCBox.myAdd(bigB,1);
        smallB = new JButton("-");
        smallB.addActionListener(this);
        topCCBox.myAdd(smallB,1);
        //topRBox
        upB = new JButton("^");
        upB.addActionListener(this);
        topRBox.myAdd(upB,0);
        MyHBox topRCBox = new MyHBox();
        topRBox.myAdd(topRCBox,1);
        leftB = new JButton("<");
        leftB.addActionListener(this);
        topRCBox.myAdd(leftB,0);
        topRCBox.myAdd(Box.createGlue(),1);
        rightB = new JButton(">");
        rightB.addActionListener(this);
        topRCBox.myAdd(rightB,0);
        downB = new JButton("v");
        downB.addActionListener(this);
        topRBox.myAdd(downB,0);

        //****rightBox****
        //editModeBox
        MyVBox editModeBox = new MyVBox();
        lb = new LineBorder(Color.BLUE,2);
        tb = new TitledBorder(lb,"編集モード");
        editModeBox.setBorder(tb);
        rightBox.myAdd(editModeBox,0);
        editModeCB = new JComboBox();
        editModeCB.addItem("全部");
        editModeCB.addItem("骨だけ");
        editModeCB.addItem("形すべて");
        editModeCB.addItem("一つの形");
        editModeCB.addItem("上吹き出し");
        editModeCB.addItem("下吹き出し");
        editModeCB.addItem("右吹き出し");
        editModeCB.addItem("左吹き出し");
        editModeCB.addItem("ラベル");
        editModeCB.addItem("サウンド");
        editModeCB.addActionListener(this);
        editModeBox.myAdd(editModeCB,0);
        editModeBox.myAdd(new JSeparator(),0);
        measureCB = new JCheckBox("メジャー");
        measureCB.addActionListener(this);
        editModeBox.myAdd(measureCB,0);

        //relationBox
        MyVBox relationBox = new MyVBox();
        lb = new LineBorder(Color.BLUE,2);
        tb = new TitledBorder(lb,"対応付け");
        relationBox.setBorder(tb);
        rightBox.myAdd(relationBox,0);
        relationBox.myAdd(new JLabel("bone:"),0);
        boneCB = new JComboBox();
        boneCB.addActionListener(this);
        relationBox.myAdd(boneCB,0);
        vrmlL = new JLabel("[????]のvrml:");
        relationBox.myAdd(vrmlL,0);
        vrmlCB = new JComboBox();
        vrmlCB.addActionListener(this);
        relationBox.myAdd(vrmlCB,0);

        rightBox.myAdd(Box.createVerticalGlue(),1);

        MyHBox undoRedoBox = new MyHBox();
        rightBox.myAdd(undoRedoBox,0);
        undoB = new JButton("undo");
        undoB.addActionListener(this);
        undoRedoBox.myAdd(undoB,1);
        redoB = new JButton("redo");
        redoB.addActionListener(this);
        undoRedoBox.myAdd(redoB,1);

        try {
            Action3D.clearCash("x-res:///jp/sourceforge/acerola3d/a3panels/resources/measure.a3");
            measure = new Action3D("x-res:///jp/sourceforge/acerola3d/a3panels/resources/measure.a3");
            measure.setPickable(false);
            empty = new Action3D("x-res:///jp/sourceforge/acerola3d/a3editor/resources/empty.a3");
            empty.setPickable(false);
            speaker = new Action3D("x-res:///jp/sourceforge/acerola3d/a3editor/resources/speaker2.a3");
        } catch (Exception e1) {
            e1.printStackTrace();
        }

        myExamController = new MyExamController();

        keyboardShotcutInit();
        //init();
    }
    void keyboardShotcutInit() {
        ActionMap am = getActionMap();
        InputMap im = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

        AbstractAction topViewAction = new AbstractAction() {
            private static final long serialVersionUID = 1L;
            public void actionPerformed(ActionEvent event) {
                canvas.setProjectionMode(ProjectionMode.PARALLEL);
                canvas.setNavigationMode(A3CanvasInterface.NaviMode.EDIT);
                adjustTop();
                viewMode = topB;
            }
        };
        am.put("topViewAction",topViewAction);
        im.put(KeyStroke.getKeyStroke('7'),"topViewAction");

        AbstractAction camViewAction = new AbstractAction() {
            private static final long serialVersionUID = 1L;
            public void actionPerformed(ActionEvent event) {
                canvas.setProjectionMode(ProjectionMode.PERSPECTIVE);
                canvas.setA3Controller(myExamController);
                adjustCam();
                viewMode = camB;
            }
        };
        am.put("camViewAction",camViewAction);
        im.put(KeyStroke.getKeyStroke('9'),"camViewAction");

        AbstractAction frontViewAction = new AbstractAction() {
            private static final long serialVersionUID = 1L;
            public void actionPerformed(ActionEvent event) {
                canvas.setProjectionMode(ProjectionMode.PARALLEL);
                canvas.setNavigationMode(A3CanvasInterface.NaviMode.EDIT);
                adjustFront();
                viewMode = frontB;
            }
        };
        am.put("frontViewAction",frontViewAction);
        im.put(KeyStroke.getKeyStroke('1'),"frontViewAction");

        AbstractAction sideViewAction = new AbstractAction() {
            private static final long serialVersionUID = 1L;
            public void actionPerformed(ActionEvent event) {
                canvas.setProjectionMode(ProjectionMode.PARALLEL);
                canvas.setNavigationMode(A3CanvasInterface.NaviMode.EDIT);
                adjustSide();
                viewMode = sideB;
            }
        };
        am.put("sideViewAction",sideViewAction);
        im.put(KeyStroke.getKeyStroke('3'),"sideViewAction");

        AbstractAction undoAction = new AbstractAction() {
            private static final long serialVersionUID = 1L;
            public void actionPerformed(ActionEvent event) {
                if (editSequenceIndex<0)
                    return;
                Edit e = editSequence.get(editSequenceIndex);
                e.undo();
                editSequenceIndex--;
            }
        };
        am.put("undoAction",undoAction);
        im.put(KeyStroke.getKeyStroke("ctrl Z"),"undoAction");

        AbstractAction redoAction = new AbstractAction() {
            private static final long serialVersionUID = 1L;
            public void actionPerformed(ActionEvent event) {
                if (editSequenceIndex>=(editSequence.size()-1))
                    return;
                editSequenceIndex++;
                Edit e = editSequence.get(editSequenceIndex);
                e.redo();
            }
        };
        am.put("redoAction",redoAction);
        im.put(KeyStroke.getKeyStroke("ctrl Y"),"redoAction");
    }
    void doEdit(Edit e) {
        e.edit();
        while ((editSequence.size()-1)>editSequenceIndex) {
            editSequence.remove(editSequence.size()-1);
        }
        editSequence.add(e);
        editSequenceIndex++;
    }
    void init() {
        editSequence.clear();
        editSequenceIndex=-1;
        //==================================
        try {
            String bvhPath = actionEditor.getBVHPath();
            String bvhUrl = actionEditor.getBVHURL();
            if (bvhUrl!=null && !bvhPath.equals("none"))
                skeleton = new Skeleton(bvhUrl);
            else
                skeleton = null;
            Vector3d actionOffset = actionEditor.getOffset();
            Quat4d actionQuat = actionEditor.getQuat();
            double actionScale = actionEditor.getScale();
            if (skeleton!=null) {
                skeleton.setScale(actionScale);
                skeleton.setQuat(actionQuat);
                skeleton.setLoc(actionOffset);
            }
            //VRML.clearCash();
            vrmls.clear();
            for (String bn : actionEditor.getUsedBones()) {
                String vrmlURL = actionEditor.getVRMLFile(bn).getURLString();
                CenteredVRML vrml = new CenteredVRML(vrmlURL);
                T t = actionEditor.getPartData(bn);
                t = catalog2CenteredVRML(bn,t);
                vrml.setScale(t.scale);
                vrml.setQuat(t.quat);
                vrml.setLoc2(t.offset);
                vrmls.put(bn,vrml);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //==================================
        actionCB.removeActionListener(this);
        actionCB.removeAllItems();
        for (String an : actionEditor.getActionNames()) {
            actionCB.addItem(an);
        }
        actionCB.setSelectedItem(actionEditor.getCurrentActionName());
        actionCB.addActionListener(this);
        newActionInputPanel.init();
        bvhCB.removeActionListener(this);
        bvhCB.removeAllItems();
        bvhCB.addItem(A3eFile.noneFile);
        for (A3eFile bvh : a3editor.fileManager.listA3eFile(A3eFileType.BVH)) {
            bvhCB.addItem(bvh);
        }
        A3eFile bvh = actionEditor.getBVHFile();
        if (bvh==null) {
            bvhCB.setSelectedItem(A3eFile.noneFile);
        } else {
            bvhCB.setSelectedItem(bvh);
        }
        bvhCB.addActionListener(this);
        loopCB.setSelected(actionEditor.getLoop());
        segnoL.setText(""+actionEditor.getSegno());
        dalsegnoL.setText(""+actionEditor.getDalsegno());
        soundFileCB.removeActionListener(this);
        soundTypeCB.removeActionListener(this);
        soundFileCB.removeAllItems();
        soundFileCB.addItem(A3eFile.noneFile);
        for (A3eFile sf : a3editor.fileManager.listA3eFile(A3eFileType.SOUND)) {
            soundFileCB.addItem(sf);
        }
        A3eFile soundFile = actionEditor.getSoundFile();
        if (!soundFile.equals(A3eFile.noneFile)) {
            soundFileCB.setSelectedItem(soundFile);
            soundTypeCB.setEnabled(true);
            soundLoopCB.setEnabled(true);
            soundGainB.setEnabled(true);
            soundContinueCB.setEnabled(true);
            soundTypeCB.setSelectedItem(actionEditor.getSoundType());
            soundLoopCB.setSelected(actionEditor.getSoundLoop());
            soundGainL.setText(""+actionEditor.getSoundGain());
            soundContinueCB.setSelected(actionEditor.getSoundContinue());
            Vector3d v = actionEditor.getSoundOffset();
            speaker.setLoc(v);
            v = actionEditor.getSoundDirection();
            Quat4d q = Util.a2bQuat(new Vector3d(0.0,0.0,1.0),v);
            speaker.setQuat(q);
        } else {
            soundFileCB.setSelectedItem(A3eFile.noneFile);
            soundTypeCB.setEnabled(false);
            soundLoopCB.setEnabled(false);
            soundGainB.setEnabled(false);
            soundContinueCB.setEnabled(false);
            soundTypeCB.setSelectedItem("PointSound");
            soundLoopCB.setSelected(false);
            soundGainL.setText("1.0");
            soundContinueCB.setSelected(true);
            speaker.setLoc(0.0,0.0,0.0);
            speaker.setRot(0.0,0.0,0.0);
        }
        soundFileCB.addActionListener(this);
        soundTypeCB.addActionListener(this);
        editModeCB.setSelectedItem("全部");
        measureCB.setSelected(false);
        boneCB.removeAllItems();
        boneCB.addItem("[none]");
        if (skeleton!=null) {
            for (String bn : skeleton.getBones()) {
                boneCB.addItem(bn);
            }
        }
        vrmlL.setText("[none]のvrml:");
        vrmlCB.removeActionListener(this);
        vrmlCB.removeAllItems();
        vrmlCB.addItem(A3eFile.noneFile);
        for (A3eFile vrml : a3editor.fileManager.listA3eFile(A3eFileType.VRML)) {
            vrmlCB.addItem(vrml);
        }
        vrmlCB.setSelectedItem(actionEditor.getVRMLFile("[none]"));
        vrmlCB.addActionListener(this);

        //==================================
        canvas.delAll();
        viewMode = frontB;
        frontB.setSelected(true);
        canvas.setProjectionMode(ProjectionMode.PARALLEL);
        canvas.setNavigationMode(A3CanvasInterface.NaviMode.EDIT);
        if (skeleton!=null)
            canvas.add(skeleton);
        for (CenteredVRML vrml : vrmls.values()) {
            canvas.add(vrml);
        }
        double xy[];
        xy = actionEditor.getRightBalloonOffset();
        empty.setBalloonLoc(A3Object.BalloonDir.RIGHT, xy[0], xy[1]);
        xy = actionEditor.getLeftBalloonOffset();
        empty.setBalloonLoc(A3Object.BalloonDir.LEFT, xy[0], xy[1]);
        xy = actionEditor.getTopBalloonOffset();
        empty.setBalloonLoc(A3Object.BalloonDir.TOP, xy[0], xy[1]);
        xy = actionEditor.getBottomBalloonOffset();
        empty.setBalloonLoc(A3Object.BalloonDir.BOTTOM, xy[0], xy[1]);
        xy = actionEditor.getLabelOffset();
        empty.setLabelLoc(xy[0], xy[1]);
        adjustFront();
        this.requestFocus();
    }
    BoundingSphere getAllBound() {
        BoundingSphere ret = null;
        for (CenteredVRML v : vrmls.values()) {
            if (ret==null)
                ret = new BoundingSphere(v.getNode().getBounds());
            else
                ret.combine(v.getNode().getBounds());
        }
        if (skeleton!=null) {
            if (ret==null)
                ret = new BoundingSphere(skeleton.getNode().getBounds());
            else
                ret.combine(skeleton.getNode().getBounds());
        }
        if (ret==null)
            ret = new BoundingSphere();
        return ret;
    }
    void adjustCam() {
        BoundingSphere bs = getAllBound();
        myExamController.adjust(bs);
        speaker.setScale(0.1*bs.getRadius());
        canvas.del(measure);
        camB.setSelected(true);
    }
    void adjustTop() {
        BoundingSphere bs = getAllBound();
        double radius = bs.getRadius();
        Point3d center = new Point3d();
        bs.getCenter(center);
        canvasWidthInPWorld = 3.0*radius;
        canvas.setCanvasWidthInPWorld(canvasWidthInPWorld);
        canvas.setCameraLocImmediately(center.x,center.y+1.5*radius,center.z);
        canvas.setCameraRotImmediately(-Math.PI/2.0,0.0,0.0);
        canvas.setCameraScaleImmediately(1.0);//TODO どう計算すべきだろう?
        speaker.setScale(0.1*bs.getRadius());
        if (measureCB.isSelected()) {
            measure.setRot(-Math.PI/2.0,0.0,0.0);
            canvas.add(measure);
        }
        topB.setSelected(true);
    }
    void adjustFront() {
        BoundingSphere bs = getAllBound();
        double radius = bs.getRadius();
        Point3d center = new Point3d();
        bs.getCenter(center);
        canvasWidthInPWorld = 3.0*radius;
        canvas.setCanvasWidthInPWorld(canvasWidthInPWorld);
        canvas.setCameraLocImmediately(center.x,center.y,center.z+1.5*radius);
        canvas.setCameraRotImmediately(0.0,0.0,0.0);
        canvas.setCameraScaleImmediately(1.0);//TODO どう計算すべきだろう?
        speaker.setScale(0.1*bs.getRadius());
        if (measureCB.isSelected()) {
            measure.setRot(0.0,0.0,0.0);
            canvas.add(measure);
        }
        frontB.setSelected(true);
    }
    void adjustSide() {
        BoundingSphere bs = getAllBound();
        double radius = bs.getRadius();
        Point3d center = new Point3d();
        bs.getCenter(center);
        canvasWidthInPWorld = 3.0*radius;
        canvas.setCanvasWidthInPWorld(canvasWidthInPWorld);
        canvas.setCameraLocImmediately(center.x+1.5*radius,center.y,center.z);
        canvas.setCameraRotImmediately(0.0,Math.PI/2.0,0.0);
        canvas.setCameraScaleImmediately(1.0);//TODO どう計算すべきだろう?
        speaker.setScale(0.1*bs.getRadius());
        if (measureCB.isSelected()) {
            measure.setRot(0.0,Math.PI/2.0,0.0);
            canvas.add(measure);
        }
        sideB.setSelected(true);
    }
    public void actionPerformed(ActionEvent ae) {
        Object s = ae.getSource();
        if (s==actionCB) {
            if (ae.getActionCommand().equals("comboBoxChanged")) {
                actionEditor.changeCurrentAction((String)actionCB.getSelectedItem());
                init();
            } else if (ae.getActionCommand().equals("comboBoxEdited")) {
                //actionEditor.setActionName((String)actionCB.getSelectedItem());
                System.out.println("gaha2");
            } else {
                System.out.println("gaha3");
            }
        } else if (s==deleteActionB) {
            if (actionCB.getItemCount()==1) {
                JOptionPane.showMessageDialog(this,"最後のアクションは削除できません。");
                return;
            }
            String an = (String)actionCB.getSelectedItem();
            int ret = JOptionPane.showConfirmDialog(this,"アクション["+an+"]の情報が全て削除されます。よろしいですか？","削除確認",JOptionPane.YES_NO_OPTION);
            if (ret==JOptionPane.NO_OPTION)
                return;
            actionEditor.deleteAction(an);
            init();
        } else if (s==renameActionB) {
            String an = (String)actionCB.getSelectedItem();
            String newName = JOptionPane.showInputDialog(this,"Input new ActionName",an);
            if (!newName.equals("")) {
                if (actionEditor.checkActionNameDuplication(newName)) {
                    JOptionPane.showMessageDialog(this,"アクション名が重複しています。");
                } else {
                    actionEditor.setActionName(newName);
                    int i = actionCB.getSelectedIndex();
                    actionCB.removeActionListener(this);
                    actionCB.removeItemAt(i);
                    actionCB.insertItemAt(newName,i);
                    actionCB.setSelectedItem(newName);
                    actionCB.addActionListener(this);
                }
            }
        } else if (s==newActionB) {
            newActionInputPanel.clear();
            int ret = JOptionPane.showConfirmDialog(this,newActionInputPanel,"New Action",JOptionPane.OK_CANCEL_OPTION);
            if (ret==JOptionPane.OK_OPTION) {
                String newName = newActionInputPanel.actionNameTF.getText();
                if (!newName.equals("")) {
                    if (actionEditor.checkActionNameDuplication(newName)) {
                        JOptionPane.showMessageDialog(this,"アクション名が重複しています。");
                    } else {
                        String baseActionName = (String)newActionInputPanel.baseActionCB.getSelectedItem();
                        A3eFile bvh = (A3eFile)newActionInputPanel.bvhCB.getSelectedItem();
                        if (!actionEditor.checkCompatibility(baseActionName,bvh)) {
                            JOptionPane.showMessageDialog(this,"ベースとなるアクションとBVHファイルに互換性がありません");
                        } else {
                            actionEditor.createNewAction2(newName,baseActionName,bvh);
                            init();
                        }
                    }
                }
            }
        } else if (s==bvhCB) {
            int ret = JOptionPane.showConfirmDialog(this,"BVHを変更するとアクションの全ての情報がクリアされます。よろしいですか?","変更確認",JOptionPane.YES_NO_OPTION);
            if (ret==JOptionPane.NO_OPTION) {
                String bvh = actionEditor.getBVH();
                //bvhCB.removeActionListener(this);
                bvhCB.setSelectedItem(bvh);
                //bvhCB.addActionListener(this);
            } else {
                actionEditor.setBVH((A3eFile)bvhCB.getSelectedItem());
                init();
            }
        } else if (s==loopCB) {
            actionEditor.setLoop(loopCB.isSelected());
        } else if (s==segnoB) {
            try {
                String input = JOptionPane.showInputDialog(this,"Input segno value",segnoL.getText());
                double d = Double.parseDouble(input);
                actionEditor.setSegno(d);
                segnoL.setText(""+d);
            } catch (NumberFormatException e) {
                ;
            }
        } else if (s==dalsegnoB) {
            try {
                String input = JOptionPane.showInputDialog(this,"Input dalsegno value",dalsegnoL.getText());
                double d = Double.parseDouble(input);
                actionEditor.setDalsegno(d);
                dalsegnoL.setText(""+d);
            } catch (NumberFormatException e) {
                ;
            }
        } else if (s==soundFileCB) {
            if (soundFileCB.getSelectedItem().equals("[none]")) {
                actionEditor.removeSoundDate();
                soundTypeCB.setEnabled(false);
                soundLoopCB.setEnabled(false);
                soundGainB.setEnabled(false);
                soundContinueCB.setEnabled(false);
                soundTypeCB.removeActionListener(this);
                soundTypeCB.setSelectedItem("PointSound");
                soundTypeCB.addActionListener(this);
                soundLoopCB.setSelected(false);
                soundGainL.setText("1.0");
                soundContinueCB.setSelected(true);
            } else {
                actionEditor.setSoundFile((A3eFile)soundFileCB.getSelectedItem());
                soundTypeCB.setEnabled(true);
                soundLoopCB.setEnabled(true);
                soundGainB.setEnabled(true);
                soundContinueCB.setEnabled(true);
                soundTypeCB.setSelectedItem(actionEditor.getSoundType());
                soundLoopCB.setSelected(actionEditor.getSoundLoop());
                soundGainL.setText(""+actionEditor.getSoundGain());
                soundContinueCB.setSelected(actionEditor.getSoundContinue());
            }
        } else if (s==soundTypeCB) {
            actionEditor.setSoundType((String)soundTypeCB.getSelectedItem());
        } else if (s==soundLoopCB) {
            actionEditor.setSoundLoop(soundLoopCB.isSelected());
        } else if (s==soundGainB) {
            try {
                String input = JOptionPane.showInputDialog(this,"Input Sound Gain",soundGainL.getText());
                double d = Double.parseDouble(input);
                actionEditor.setSoundGain(d);
                soundGainL.setText(""+d);
            } catch (NumberFormatException e) {
                ;
            }
        } else if (s==soundContinueCB) {
            actionEditor.setSoundContinue(soundContinueCB.isSelected());
        } else if (s==camB) {
            canvas.setProjectionMode(ProjectionMode.PERSPECTIVE);
            canvas.setA3Controller(myExamController);
            adjustCam();
            viewMode = camB;
        } else if (s==topB) {
            canvas.setProjectionMode(ProjectionMode.PARALLEL);
            canvas.setNavigationMode(A3CanvasInterface.NaviMode.EDIT);
            adjustTop();
            viewMode = topB;
        } else if (s==frontB) {
            canvas.setProjectionMode(ProjectionMode.PARALLEL);
            canvas.setNavigationMode(A3CanvasInterface.NaviMode.EDIT);
            adjustFront();
            viewMode = frontB;
        } else if (s==sideB) {
            canvas.setProjectionMode(ProjectionMode.PARALLEL);
            canvas.setNavigationMode(A3CanvasInterface.NaviMode.EDIT);
            adjustSide();
            viewMode = sideB;
        } else if (s==adjustB) {
            if (viewMode==camB)
                adjustCam();
            else if (viewMode==topB)
                adjustTop();
            else if (viewMode==frontB)
                adjustFront();
            else if (viewMode==sideB)
                adjustSide();
        } else if (s==bigB) {
            if (viewMode==camB) {
                myExamController.big();
            } else {
                canvasWidthInPWorld = 3.0/4.0*canvasWidthInPWorld;
                canvas.setCanvasWidthInPWorld(canvasWidthInPWorld);
                canvas.setCameraScaleImmediately(1.0);//TODO どう計算すべきだろう?
            }
        } else if (s==smallB) {
            if (viewMode==camB) {
                myExamController.small();
            } else {
                canvasWidthInPWorld = 4.0/3.0*canvasWidthInPWorld;
                canvas.setCanvasWidthInPWorld(canvasWidthInPWorld);
                canvas.setCameraScaleImmediately(1.0);//TODO どう計算すべきだろう?
            }
        } else if (s==upB) {
            if (viewMode==camB) {
                myExamController.up();
            } else {
                Vector3d v = canvas.getCameraLoc();
                double d = 0.1 * canvasWidthInPWorld;
                if (viewMode==topB)
                    v.z += d;
                else if (viewMode==frontB)
                    v.y -= d;
                else if (viewMode==sideB)
                    v.y -= d;
                canvas.setCameraLocImmediately(v);
            }
        } else if (s==downB) {
            if (viewMode==camB) {
                myExamController.down();
            } else {
                Vector3d v = canvas.getCameraLoc();
                double d = 0.1 * canvasWidthInPWorld;
                if (viewMode==topB)
                    v.z -= d;
                else if (viewMode==frontB)
                    v.y += d;
                else if (viewMode==sideB)
                    v.y += d;
                canvas.setCameraLocImmediately(v);
            }
        } else if (s==rightB) {
            if (viewMode==camB) {
                myExamController.right();
            } else {
                Vector3d v = canvas.getCameraLoc();
                double d = 0.1 * canvasWidthInPWorld;
                if (viewMode==topB)
                    v.x -= d;
                else if (viewMode==frontB)
                    v.x -= d;
                else if (viewMode==sideB)
                    v.z += d;
                canvas.setCameraLocImmediately(v);
            }
        } else if (s==leftB) {
            if (viewMode==camB) {
                myExamController.left();
            } else {
                Vector3d v = canvas.getCameraLoc();
                double d = 0.1 * canvasWidthInPWorld;
                if (viewMode==topB)
                    v.x += d;
                else if (viewMode==frontB)
                    v.x += d;
                else if (viewMode==sideB)
                    v.z -= d;
                canvas.setCameraLocImmediately(v);
            }
        } else if (s==editModeCB) {
            String m = (String)editModeCB.getSelectedItem();
            if (m.equals("全部")) {
                canvas.delAll();
                if (skeleton!=null) {
                    canvas.add(skeleton);
                    skeleton.setPickable(true);
                    //skeleton.unpolygonize();
                }
                for (CenteredVRML vrml : vrmls.values()) {
                    canvas.add(vrml);
                    vrml.setPickable(true);
                    //vrml.unpolygonize();
                }
            } else if (m.equals("骨だけ")) {
                canvas.delAll();
                if (skeleton!=null) {
                    canvas.add(skeleton);
                    skeleton.setPickable(true);
                    //skeleton.unpolygonize();
                }
            } else if (m.equals("形すべて")) {
                canvas.delAll();
                if (skeleton!=null) {
                    canvas.add(skeleton);
                    skeleton.setPickable(false);
                    //skeleton.unpolygonize();
                }
                for (CenteredVRML vrml : vrmls.values()) {
                    canvas.add(vrml);
                    vrml.setPickable(true);
                    //vrml.polygonize();
                }
            } else if (m.equals("一つの形")) {
                canvas.delAll();
                if (skeleton!=null) {
                    canvas.add(skeleton);
                    skeleton.setPickable(false);
                    //skeleton.unpolygonize();
                }
                String bn = (String)boneCB.getSelectedItem();
                CenteredVRML vrml = vrmls.get(bn);
                if (vrml!=null) {
                    canvas.add(vrml);
                    vrml.setPickable(true);
                    //vrml.unpolygonize();
                }
            } else if (m.equals("上吹き出し")) {
                canvas.delAll();
                if (skeleton!=null) {
                    canvas.add(skeleton);
                    skeleton.setPickable(false);
                    //skeleton.unpolygonize();
                }
                for (CenteredVRML vrml : vrmls.values()) {
                    canvas.add(vrml);
                    vrml.setPickable(false);
                    //vrml.unpolygonize();
                }
                canvas.add(empty);
                empty.setBalloonDir(A3Object.BalloonDir.TOP);
                empty.setBalloon("吹き出し");
                empty.setLabel(null);
            } else if (m.equals("下吹き出し")) {
                canvas.delAll();
                if (skeleton!=null) {
                    canvas.add(skeleton);
                    skeleton.setPickable(false);
                    //skeleton.unpolygonize();
                }
                for (CenteredVRML vrml : vrmls.values()) {
                    canvas.add(vrml);
                    vrml.setPickable(false);
                    //vrml.unpolygonize();
                }
                canvas.add(empty);
                empty.setBalloonDir(A3Object.BalloonDir.BOTTOM);
                empty.setBalloon("吹き出し");
                empty.setLabel(null);
            } else if (m.equals("右吹き出し")) {
                canvas.delAll();
                if (skeleton!=null) {
                    canvas.add(skeleton);
                    skeleton.setPickable(false);
                    //skeleton.unpolygonize();
                }
                for (CenteredVRML vrml : vrmls.values()) {
                    canvas.add(vrml);
                    vrml.setPickable(false);
                    //vrml.unpolygonize();
                }
                canvas.add(empty);
                empty.setBalloonDir(A3Object.BalloonDir.RIGHT);
                empty.setBalloon("吹き出し");
                empty.setLabel(null);
            } else if (m.equals("左吹き出し")) {
                canvas.delAll();
                if (skeleton!=null) {
                    canvas.add(skeleton);
                    skeleton.setPickable(false);
                    //skeleton.unpolygonize();
                }
                for (CenteredVRML vrml : vrmls.values()) {
                    canvas.add(vrml);
                    vrml.setPickable(false);
                    //vrml.unpolygonize();
                }
                canvas.add(empty);
                empty.setBalloonDir(A3Object.BalloonDir.LEFT);
                empty.setBalloon("吹き出し");
                empty.setLabel(null);
            } else if (m.equals("ラベル")) {
                canvas.delAll();
                if (skeleton!=null) {
                    canvas.add(skeleton);
                    skeleton.setPickable(false);
                    //skeleton.unpolygonize();
                }
                for (CenteredVRML vrml : vrmls.values()) {
                    canvas.add(vrml);
                    vrml.setPickable(false);
                    //vrml.unpolygonize();
                }
                canvas.add(empty);
                empty.setBalloon(null);
                empty.setLabel("ラベル");
            } else if (m.equals("サウンド")) {
                canvas.delAll();
                if (skeleton!=null) {
                    canvas.add(skeleton);
                    skeleton.setPickable(false);
                    //skeleton.unpolygonize();
                }
                canvas.add(speaker);
            }
        } else if (s==measureCB) {
            if (measureCB.isSelected()) {
                if (viewMode!=camB) {
                    if (viewMode==topB)
                        measure.setRot(-Math.PI/2.0,0.0,0.0);
                    else if (viewMode==frontB)
                        measure.setRot(0.0,0.0,0.0);
                    else if (viewMode==sideB)
                        measure.setRot(0.0,Math.PI/2.0,0.0);
                    canvas.add(measure);
                }
            } else {
                canvas.del(measure);
            }
        } else if (s==boneCB) {
            String bn = (String)boneCB.getSelectedItem();
            vrmlL.setText(bn+"のvrml:");
            vrmlCB.removeActionListener(this);
            vrmlCB.setSelectedItem(actionEditor.getVRMLFile(bn));
            vrmlCB.addActionListener(this);
            if (skeleton!=null) {
                skeleton.resetSelected();
                skeleton.setBoneSelected(bn,true);
            }
            if (editModeCB.getSelectedItem().equals("一つの形")) {
                canvas.delAll();
                if (skeleton!=null) {
                    canvas.add(skeleton);
                    skeleton.setPickable(false);
                    //skeleton.unpolygonize();
                }
                CenteredVRML vrml = vrmls.get(bn);
                if (vrml!=null) {
                    canvas.add(vrml);
                    vrml.setPickable(true);
                    //vrml.unpolygonize();
                }
            }
        } else if (s==vrmlCB) {
            doEdit(new VrmlChangeEdit());
        } else if (s==undoB) {
            if (editSequenceIndex>=0) {
                Edit e = editSequence.get(editSequenceIndex);
                e.undo();
                editSequenceIndex--;
            }
        } else if (s==redoB) {
            if (editSequenceIndex<(editSequence.size()-1)) {
                editSequenceIndex++;
                Edit e = editSequence.get(editSequenceIndex);
                e.redo();
            }
        } else {
            System.out.println("gaha?????");
        }
    }




    //CenteredVRMLの値からCATALOG.XMLに保存するための値を計算する(Offset,Rot,Scaleの全部)。
    //この計算にはカレントアクションの変換が反映される。それとSkeletonがある場合には、そのSkeleton
    //のBoneの変換も考慮する。Skeletonが無い場合などは最初の引数のbn(BoneName)は無視される。
    //それとOffsetの値はCenteredVRMLのgetLoc2,setLoc2で使う値とする。
    T centeredVRML2CATALOG(String bn,T t) {
        Vector3d actionOffset = actionEditor.getOffset();
        Quat4d actionQuatRev = actionEditor.getQuat();
        actionQuatRev.conjugate();
        double actionScale = actionEditor.getScale();
        Vector3d bvhOffset;
        if (skeleton!=null) {
            bvhOffset = skeleton.getOffset(bn);
            if (bvhOffset==null) // bnが[none]の場合(だけだと思う)
                bvhOffset = new Vector3d();
        } else {
            bvhOffset = new Vector3d();
        }
        T tt = new T();
        tt.offset = new Vector3d(t.offset);
        tt.offset.sub(actionOffset);
        tt.offset.scale(1.0/actionScale);
        tt.offset = Util.trans(actionQuatRev,tt.offset);
        tt.offset.sub(bvhOffset);

        Quat4d boneQuat = t.quat;
        boneQuat.mul(actionQuatRev,boneQuat);
        tt.quat = boneQuat;
        tt.scale = t.scale/actionScale;
        return tt;
    }

    //CATALOG.XMLに保存された値からCenteredVRMLにセットするための値を計算する(Offset,Rot,Scaleの全部)。
    //この計算にはカレントアクションの変換も考慮されている。Skeletonがある場合には
    //Boneの変換も考慮される。Skeletonが無い場合には最初の引数bn(BoneName)は無視される。
    //それと返り値のOffsetの値はCenteredVRMLのgetLoc2,setLoc2で使う値とする。
    T catalog2CenteredVRML(String bn,T t) {
        Vector3d actionOffset = actionEditor.getOffset();
        Quat4d actionQuat = actionEditor.getQuat();
        double actionScale = actionEditor.getScale();
        Vector3d bvhOffset;
        if (skeleton!=null) {
            bvhOffset = skeleton.getOffset(bn);
            if (bvhOffset==null) // bnが[none]の場合(だけだと思う)
                bvhOffset = new Vector3d();
        } else {
            bvhOffset = new Vector3d();
        }
        Vector3d boneOffset = new Vector3d(t.offset);//CATALOG.XMLから来る骨のオフセット
        Quat4d boneQuat = t.quat;//CATALOC.XMLから来る骨の回転
        double boneScale = t.scale;//CATALOG.XMLから来る骨のスケール

        T tt = new T();
        tt.offset = new Vector3d(boneOffset);
        tt.offset.add(bvhOffset);
        tt.offset.scale(actionScale);
        tt.offset = Util.trans(actionQuat,tt.offset);
        tt.offset.add(actionOffset);
        Quat4d quat = new Quat4d();
        quat.mul(actionQuat,boneQuat);
        tt.quat = quat;
        tt.scale = boneScale*actionScale;
        return tt;
    }


    String getBoneName(CenteredVRML vrml) {
        String boneName = null;
        for (String bn : vrmls.keySet()) {
            CenteredVRML v = vrmls.get(bn);
            if (v==vrml) {
                boneName = bn;
                break;
            }
        }
        return boneName;
    }

    class MyMouseListener extends A3Adapter implements MouseMotionListener {
        A3eActionEditorGUI actionEditorGUI;
        double preX;
        double preY;
        A3Object targetA3;
        MyMouseListener(A3eActionEditorGUI aeGUI) {
            actionEditorGUI = aeGUI;
        }
        @Override
        public void mousePressed(A3Event e) {
            int x = e.getMouseEvent().getX(); int y = e.getMouseEvent().getY();
            Point3d p = canvas.canvasToPhysicalCS(x,y,1.0);
            preX = p.x; preY = p.y;
            targetA3 = e.getA3Object();
        }
        @Override
        public void mouseDragged(MouseEvent e) {
            if (viewMode==camB)
                return;
            double xy[] = new double[2];
            String m = (String)editModeCB.getSelectedItem();
            if (m.equals("上吹き出し")) {
                empty.getBalloonLoc(A3Object.BalloonDir.TOP,xy);
            } else if (m.equals("下吹き出し")) {
                empty.getBalloonLoc(A3Object.BalloonDir.BOTTOM,xy);
            } else if (m.equals("右吹き出し")) {
                empty.getBalloonLoc(A3Object.BalloonDir.RIGHT,xy);
            } else if (m.equals("左吹き出し")) {
                empty.getBalloonLoc(A3Object.BalloonDir.LEFT,xy);
            } else if (m.equals("ラベル")) {
                empty.getLabelLoc(xy);
            } else {
                return;
            }

            int x = e.getX(); int y = e.getY();
            Point3d p = canvas.canvasToPhysicalCS(x,y,1.0);
            double nowX = p.x; double nowY = p.y;
            xy[0] = xy[0] + (nowX - preX);
            xy[1] = xy[1] + (nowY - preY);

            if (m.equals("上吹き出し")) {
                empty.setBalloonLoc(A3Object.BalloonDir.TOP,xy[0],xy[1]);
            } else if (m.equals("下吹き出し")) {
                empty.setBalloonLoc(A3Object.BalloonDir.BOTTOM,xy[0],xy[1]);
            } else if (m.equals("右吹き出し")) {
                empty.setBalloonLoc(A3Object.BalloonDir.RIGHT,xy[0],xy[1]);
            } else if (m.equals("左吹き出し")) {
                empty.setBalloonLoc(A3Object.BalloonDir.LEFT,xy[0],xy[1]);
            } else if (m.equals("ラベル")) {
                empty.setLabelLoc(xy[0],xy[1]);
            }

            preX = nowX; preY = nowY;
        }
        @Override
        public void mouseMoved(MouseEvent e) {;}
        @Override
        public void mouseReleased(A3Event e) {
            mouseDragged(e.getMouseEvent());
            String m = (String)editModeCB.getSelectedItem();
            double xy[] = new double[2];
            if (m.equals("全部")) {
                if (targetA3 instanceof Skeleton)
                    updateActionOffsetRotScale();
                else if (targetA3 instanceof CenteredVRML)
                    updatePartsOffsetRotScale((CenteredVRML)targetA3);
            } else if (m.equals("骨だけ")) {
                if (targetA3 instanceof Skeleton)
                    updateActionOffsetRotScale();
            } else if (m.equals("形すべて")) {
                if (targetA3 instanceof CenteredVRML)
                    updatePartsOffsetRotScale((CenteredVRML)targetA3);
            } else if (m.equals("一つの形")) {
                if (targetA3 instanceof CenteredVRML)
                    updatePartsOffsetRotScale((CenteredVRML)targetA3);
            } else if (m.equals("上吹き出し")) {
                empty.getBalloonLoc(A3Object.BalloonDir.TOP,xy);
                actionEditor.setTopBalloonOffset(xy);
            } else if (m.equals("下吹き出し")) {
                empty.getBalloonLoc(A3Object.BalloonDir.BOTTOM,xy);
                actionEditor.setBottomBalloonOffset(xy);
            } else if (m.equals("右吹き出し")) {
                empty.getBalloonLoc(A3Object.BalloonDir.RIGHT,xy);
                actionEditor.setRightBalloonOffset(xy);
            } else if (m.equals("左吹き出し")) {
                empty.getBalloonLoc(A3Object.BalloonDir.LEFT,xy);
                actionEditor.setLeftBalloonOffset(xy);
            } else if (m.equals("ラベル")) {
                empty.getLabelLoc(xy);
                actionEditor.setLabelOffset(xy);
            } else if (m.equals("サウンド")) {
                Vector3d v = speaker.getLoc();
                actionEditor.setSoundOffset(v.x,v.y,v.z);
                Quat4d q = speaker.getQuat();
                v = Util.trans(q,new Vector3d(0.0,0.0,1.0));
                actionEditor.setSoundDirection(v.x,v.y,v.z);
            } else {
                System.out.println("???????"+m);
            }
        }
        void updateActionOffsetRotScale() {
            if (skeleton!=null) {
                doEdit(new SkeletonEdit());
            }
        }
        void updatePartsOffsetRotScale(CenteredVRML vrml) {
            doEdit(new PartEdit(vrml));
        }
    }
    void clear() {
        //TODO
        actionEditor.saveCatalog();
    }
    class NewActionInputPanel extends JPanel {
        private static final long serialVersionUID = 1L;
        JTextField actionNameTF;
        JComboBox baseActionCB;
        JComboBox bvhCB;
        NewActionInputPanel() {
            MyVBox baseBox = new MyVBox();
            add(baseBox);
            MyHBox actionNameBox = new MyHBox();
            baseBox.myAdd(actionNameBox,0);
            actionNameBox.myAdd(new JLabel("ActionName:"),0);
            actionNameTF = new JTextField();
            actionNameBox.myAdd(actionNameTF,1);
            MyHBox baseActionBox = new MyHBox();
            baseBox.myAdd(baseActionBox,0);
            baseActionBox.myAdd(new JLabel("ベースとなるアクション"),0);
            baseActionCB = new JComboBox();
            baseActionBox.myAdd(baseActionCB,1);
            MyHBox bvhBox = new MyHBox();
            baseBox.myAdd(bvhBox,0);
            bvhBox.myAdd(new JLabel("BVH:"),0);
            bvhCB = new JComboBox();
            bvhBox.myAdd(bvhCB,1);
        }
        void init() {
            actionNameTF.setText("");
            baseActionCB.removeAllItems();
            baseActionCB.addItem("[none]");
            for (String an : actionEditor.getActionNames()) {
                baseActionCB.addItem(an);
            }
            baseActionCB.setSelectedItem("[none]");
            bvhCB.removeAllItems();
            bvhCB.addItem(A3eFile.noneFile);
            for (A3eFile bvh:a3editor.fileManager.listA3eFile(A3eFileType.BVH)) {
                bvhCB.addItem(bvh);
            }
            bvhCB.setSelectedItem(A3eFile.noneFile);
        }
        void clear() {
            actionNameTF.setText("");
            baseActionCB.setSelectedItem("[none]");
            bvhCB.setSelectedItem(A3eFile.noneFile);
        }
    }
    //Undo機能とかを実現するためのクラス
    abstract class Edit {
        abstract void edit();
        abstract void undo();
        void redo() {
            edit();
        }
    }

    class SkeletonEdit extends Edit {
        Vector3d oldOffset;
        Quat4d oldQuat;
        double oldScale;
        Vector3d newOffset;
        Quat4d newQuat;
        double newScale;
        SkeletonEdit() {
            oldOffset = actionEditor.getOffset();
            oldQuat = actionEditor.getQuat();
            oldScale = actionEditor.getScale();
            newOffset = skeleton.getLoc();
            newQuat = skeleton.getQuat();
            newScale = skeleton.getScale();
        }
        void edit(){
            actionEditor.setScale(newScale);
            actionEditor.setOffset(newOffset);
            actionEditor.setQuat(newQuat);
            skeleton.setScale(newScale);
            skeleton.setQuat(newQuat);
            skeleton.setLoc(newOffset);
        }
        void undo(){
            actionEditor.setScale(oldScale);
            actionEditor.setQuat(oldQuat);
            actionEditor.setOffset(oldOffset);
            skeleton.setScale(oldScale);
            skeleton.setQuat(oldQuat);
            skeleton.setLoc(oldOffset);
        }
    }
    //これに記録される値はCATALOG.XMLに記録される値ではなくCenteredVRML
    //に直接渡せる値。かつOffsetはsetLocとかgetLocでなくsetLoc2とgetLoc2
    //を使うことを前提にしている。
    class PartEdit extends Edit {
        String boneName;
        Vector3d oldOffset = new Vector3d();
        Quat4d oldQuat = new Quat4d();
        double oldScale;
        Vector3d newOffset;
        Quat4d newQuat;
        double newScale;
        PartEdit(CenteredVRML target) {
            boneName = getBoneName(target);
            T t = actionEditor.getPartData(boneName);
            t = catalog2CenteredVRML(boneName,t);
            oldOffset = t.offset;
            oldQuat = t.quat;
            oldScale = t.scale;
            newOffset = target.getLoc2();
            newQuat = target.getQuat();
            newScale = target.getScale();
        }
        void edit(){
            T t = new T();
            t.offset = newOffset;
            t.quat = newQuat;
            t.scale = newScale;
            t = centeredVRML2CATALOG(boneName,t);
            actionEditor.setPartData(boneName,t);
            CenteredVRML target = vrmls.get(boneName);
            target.setQuat(newQuat);
            target.setScale(newScale);
            target.setLoc2(newOffset);
        }
        void undo(){
            T t = new T();
            t.offset = oldOffset;
            t.quat = oldQuat;
            t.scale = oldScale;
            t = centeredVRML2CATALOG(boneName,t);
            actionEditor.setPartData(boneName,t);
            CenteredVRML target = vrmls.get(boneName);
            target.setScale(oldScale);
            target.setQuat(oldQuat);
            target.setLoc2(oldOffset);
        }
    }
    
    class VrmlChangeEdit extends Edit {
        String boneName;
        A3eFile oldFile;
        Vector3d offset;
        Vector3d rot;
        double scale;
        A3eFile newFile;
        VrmlChangeEdit() {
            boneName = (String)boneCB.getSelectedItem();
            oldFile = actionEditor.getVRMLFile(boneName);
            newFile = (A3eFile)vrmlCB.getSelectedItem();
            CenteredVRML oldVRML = vrmls.get(boneName);
            if (oldVRML!=null) {
                offset = oldVRML.getLoc2();
                rot = oldVRML.getRot();
                scale = oldVRML.getScale();
            }
        }
        void edit(){
            actionEditor.setVRML(boneName,newFile);
            CenteredVRML oldVRML = vrmls.get(boneName);
            CenteredVRML newVRML = null;
            if (newFile==A3eFile.noneFile) {
                newVRML = null;
                vrmls.remove(boneName);
            } else {
                try {
                    newVRML = new CenteredVRML(newFile.getURLString());
                    vrmls.put(boneName,newVRML);
                } catch (Exception ee) {
                    ee.printStackTrace();
                }
            }
            if (oldVRML!=null)
                canvas.del(oldVRML);
            if (newVRML!=null) {
                newVRML.setScale(scale);
                newVRML.setRot(rot);
                newVRML.setLoc2(offset);
                canvas.add(newVRML);
            }
            boneCB.removeActionListener(A3eActionEditorGUI.this);
            vrmlCB.removeActionListener(A3eActionEditorGUI.this);
            boneCB.setSelectedItem(boneName);
            vrmlCB.setSelectedItem(newFile);
            boneCB.addActionListener(A3eActionEditorGUI.this);
            vrmlCB.addActionListener(A3eActionEditorGUI.this);
        }
        void undo(){
            actionEditor.setVRML(boneName,oldFile);
            CenteredVRML newVRML = vrmls.get(boneName);
            CenteredVRML oldVRML = null;
            if (oldFile==A3eFile.noneFile) {
                oldVRML = null;
                vrmls.remove(boneName);
            } else {
                try {
                    oldVRML = new CenteredVRML(oldFile.getURLString());
                    vrmls.put(boneName,oldVRML);
                } catch (Exception ee) {
                    ee.printStackTrace();
                }
            }
            if (newVRML!=null)
                canvas.del(newVRML);
            if (oldVRML!=null) {
                oldVRML.setScale(scale);
                oldVRML.setRot(rot);
                oldVRML.setLoc2(offset);
                canvas.add(oldVRML);
            }
            boneCB.removeActionListener(A3eActionEditorGUI.this);
            vrmlCB.removeActionListener(A3eActionEditorGUI.this);
            boneCB.setSelectedItem(boneName);
            vrmlCB.setSelectedItem(oldFile);
            boneCB.addActionListener(A3eActionEditorGUI.this);
            vrmlCB.addActionListener(A3eActionEditorGUI.this);
        }
    }
}
