package jp.ac.kyutech.mns.ist; import java.awt.Dimension; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Collection; import java.util.Timer; import java.util.TimerTask; import java.util.TreeMap; import javax.swing.JPopupMenu; import jp.ac.kyutech.mns.ist.plugin.DefaultPlugin; import jp.ac.kyutech.mns.ist.plugin.WindowManagerPlugin; import jp.ac.kyutech.mns.ist.util.BUtil; import jp.ac.kyutech.mns.ist.util.MyAction; import jp.ac.kyutech.mns.ist.util.WheelRotationHandler; import edu.umd.cs.piccolo.PCamera; import edu.umd.cs.piccolo.PCanvas; import edu.umd.cs.piccolo.PNode; import edu.umd.cs.piccolo.event.PInputEventFilter; import edu.umd.cs.piccolo.event.PPanEventHandler; import edu.umd.cs.piccolo.util.PBounds; import edu.umd.cs.piccolo.util.PDimension; import edu.umd.cs.piccolox.PFrame; public class FocusFrame extends PFrame implements Runnable, LayoutTarget { private static final long serialVersionUID = 2276191088134378532L; transient SimpleATN satn; transient PCanvas satncanvas; // Rectangle2D region; Rectangle2D sheetb; transient Sheet targetsheet; ZoomRegionHandler zrh;//Event_onSheetが参照するため Event_onFF event_onff; // ArrayList<FocusRectangle> rects; transient TreeMap<Integer,FocusRectangle> rects_bysid; // transient ArrayList<FocusRectangle> rects_sorted = new ArrayList<FocusRectangle>(); int layoutcols = 0; PBounds tempAfterLayoutBounds = null; LayoutAbstract layoutActive = null; int sorttype = 1; // 1: bysid, 2: byamount, 3: byseat LayoutBySeat layoutseat; LayoutByIDHorizontal layoutH; LayoutByAmountHorizontal layoutA; LayoutByTeinei layoutT; //あとでNoteが追加された場合に,適用するために履歴をとっておく transient public static ArrayList<FocusFrame> frames = new ArrayList<FocusFrame>(); ArrayList<DefaultPlugin> plugins; InsideToolbar_FocusFrame insideToolbar; WindowManagerPlugin windowmanager; public PCamera getCamera(){ return getCanvas().getCamera(); } public static void updateFocusReference(int sid){ for(FocusFrame ff: frames){ if (ff.isFocusReferenceMode){ if (ff.rects_bysid!=null) if (ff.rects_bysid.get(sid)!=null) ff.rects_bysid.get(sid).focusReference(); } } } public void applyToNote(Note n, boolean doLayout){ // Sheet s = n.sheets.get(targetsheet.num); Sheet s = n.getSheet(targetsheet.num); if (s==null) { System.out.println("Trying to apply note, but sheet is null "+n.penid); return; } // Rectangle2D sheetb = targetsheet.globalToLocal(region); // System.out.println("region1 "+region.toString()); // Rectangle2D sheetb = s.globalToLocal(region);//こ,これは破壊的メソッド(なぜかregionが壊れる)だったのか... 危険だ〜TODO: // System.out.println("sheetb "+sheetb.toString()); // PAffineTransform at = new PAffineTransform(); // s.getLocalToGlobalTransform(at); // System.out.println("at "+at.toString()); // s.getGlobalToLocalTransform(at); // Rectangle2D sgb = new Rectangle2D.Double(); // at.transform(region, sgb); // layer2.addChild(new FocusRectangle(gdim, s, sgb)); // PDimension gdim = new PDimension(region.getWidth(), region.getHeight()); PDimension gdim = new PDimension(sheetb.getWidth(), sheetb.getHeight()); // System.out.println("sgb "+sgb.toString()); // FocusRectangle fr = new FocusRectangle(gdim, s, sgb, getCanvas()); FocusRectangle fr = new FocusRectangle(gdim, s, sheetb, getCanvas()); rects_bysid.put(n.penid, fr); // System.out.println("region2 "+region.toString()); // FocusSrc fs = new FocusSrc(region, fr, this); FocusSrc fs = new FocusSrc(sheetb, fr, this, n); s.addChild(fs); fr.setFocusSrc(fs); getCanvas().getLayer().addChild(fr); // if (sorttype==1) sortByPenID(); // else if (sorttype==2) sortByDrawingAmount(); // else if (sorttype==3) sortBySeat(); if (doLayout) { relayout(); zoomToBounds(tempAfterLayoutBounds); } } public void setTitle(String base, Rectangle2D _r){ StringBuffer sb = new StringBuffer(); sb.append(base); sb.append((int)(_r.getWidth())); sb.append(" x "); sb.append((int)(_r.getHeight())); sb.append(" @ "); sb.append((int)(_r.getX())); sb.append(" , "); sb.append((int)(_r.getY())); setTitle(sb.toString()); } // public static FocusFrame createNew(String title, SimpleATN _satn, Rectangle2D _r, Sheet _ts){ // FocusFrame ff = new FocusFrame( title, _satn, _r, _ts); // return ff; // } public FocusFrame(String title, SimpleATN _satn, Rectangle2D _r, Sheet _ts, boolean isReference, boolean isFullScreen){ super(title, false, null); // region = _r; targetsheet = _ts; satn = _satn; satncanvas = satn.canvas; rects_bysid = new TreeMap<Integer, FocusRectangle>(); frames.add(this); setFullScreenMode(false); sheetb = _r; setTitle(title, sheetb); for(Note n: SimpleATN.theapp.notes.values()){ applyToNote(n,false); } setDefaultCloseOperation(javax.swing.WindowConstants.HIDE_ON_CLOSE); //remove default zoom event hander getCanvas().removeInputEventListener(getCanvas().getZoomEventHandler()); getCanvas().removeInputEventListener(getCanvas().getPanEventHandler()); // Button1 - Pan PPanEventHandler panEventHandler = new PPanEventHandler(); panEventHandler.setEventFilter(new PInputEventFilter(InputEvent.BUTTON1_MASK)); getCanvas().addInputEventListener(panEventHandler); // Button2 Wheel Rotation - Zoom WheelRotationHandler wrHandler = new WheelRotationHandler(getCanvas(), getCanvas().getCamera()); wrHandler.setEventFilter(new PInputEventFilter(InputEvent.BUTTON2_MASK)); getCanvas().addInputEventListener(wrHandler); // Button3 Drag - Zoom Region zrh = new ZoomRegionHandler(this.getCanvas()); getCanvas().addInputEventListener(zrh); zrh.setEventFilter(new PInputEventFilter(InputEvent.BUTTON3_MASK)); getCanvas().getPanEventHandler().setEventFilter(new PInputEventFilter(InputEvent.BUTTON3_MASK)); //プラグインとして,インスペクタを追加 plugins = new ArrayList<DefaultPlugin>(); plugins.add(windowmanager = new WindowManagerPlugin(getCanvas(), this)); plugins.add(new InspectorPlugin(getCanvas(), this)); event_onff = new Event_onFF(this); getCanvas().getCamera().addInputEventListener(event_onff); //キー入力(ESCキーで画面全体表示) getCanvas().addKeyListener(new KeyListener() { @Override public void keyTyped(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { System.out.println("keyCode=" + e.getKeyCode() + " keyChar ["+ e.getKeyChar() + "]"); if (e.getKeyCode() == 27) {// ESC upview(); } if (e.getKeyCode() == 34) {// PageDown + 59 PCamera pc = getCanvas().getCamera(); PBounds pb = pc.getViewBounds(); pb = BUtil.zoomBounds(pb, 0.9); pc.animateViewToCenterBounds(pb, true, 0); } if (e.getKeyCode() == 33) {// PageUp - PCamera pc = getCanvas().getCamera(); PBounds pb = pc.getViewBounds(); pb = BUtil.zoomBounds(pb, 1.1); pc.animateViewToCenterBounds(pb, true, 0); } if (37 <= e.getKeyCode() && e.getKeyCode() <= 40){ processCursorKey(e.getKeyCode()); } if (e.getKeyCode() == KeyEvent.VK_F11){ } // if (e.getKeyCode() == KeyEvent.VK_Z){ // System.out.println("FocusFrame zoomLevel = "+getZoomLevel()); // } } }); getCanvas().requestFocus(); insideToolbar = new InsideToolbar_FocusFrame(this); getCamera().addChild(insideToolbar); //初期レイアウト sorttype = 1; if (satn.menutoolbar != null){ MyAction seatmap = satn.menutoolbar.getAction("SheetMap"); if (seatmap != null && seatmap.isSelected()){ if (ConfigWindow.configWin.seatmap.active_smap != null){ sorttype = 3; } } } relayout(); zoomToBounds(tempAfterLayoutBounds); validate(); if (isReference){ toggleFocusReference(); } else { if (isFullScreen) windowMaximize(); else windowmanager.relativefit(tempAfterLayoutBounds); } Thread t = new Thread(this); t.start(); } @Override public void run() { setVisible(true); try { Thread.sleep(1200); } catch (InterruptedException e) { e.printStackTrace(); } validate(); relayout(); zoomToBounds(tempAfterLayoutBounds); } public void sortByToolbarButtonStatus() { //ツールバーのSeatmapレイアウトボタンの状況 boolean isSeatmap = satn.menutoolbar.getAction("SheetMap").isSelected(); if (isSeatmap) sortBySeat(); else sortByPenID(); } //TODO: 書き込み量に応じた並べ替え public void sortByDrawingAmount(){ if (layoutA == null) layoutA = new LayoutByAmountHorizontal(getCanvas().getCamera()); layoutActive = layoutA; layoutActive.layout(0, this); tempAfterLayoutBounds = layoutActive.contentregion(this); zoomToBounds(tempAfterLayoutBounds); sorttype = 2; } //TODO: 丁寧度に応じた並べ替え public void sortByTeinei(){ if (layoutT == null) layoutT = new LayoutByTeinei(getCanvas().getCamera()); layoutActive = layoutT; layoutActive.layout(0, this); tempAfterLayoutBounds = layoutActive.contentregion(this); zoomToBounds(tempAfterLayoutBounds); sorttype = 4; } public void sortBySeat() { //筆跡マップが有効か? MyAction seatmap; if (satn.menutoolbar != null){ seatmap = satn.menutoolbar.getAction("SheetMap"); if (seatmap != null && seatmap.isSelected()){ if (ConfigWindow.configWin.seatmap.active_smap != null){ if (layoutseat == null){ layoutseat = new LayoutBySeat(getCanvas().getCamera(), ConfigWindow.configWin.seatmap.active_smap); } layoutseat.layout(0, this); tempAfterLayoutBounds = layoutseat.contentregion(this); } } } if (layoutseat != null) { layoutActive = layoutseat; layoutActive.layout(0, this); tempAfterLayoutBounds = layoutActive.contentregion(this); zoomToBounds(tempAfterLayoutBounds); sorttype = 3; } } public void sortByPenID(){ if (layoutH == null){ layoutH = new LayoutByIDHorizontal(getCanvas().getCamera()); } layoutActive = layoutH; layoutActive.layout(0, this); tempAfterLayoutBounds = layoutActive.contentregion(this); zoomToBounds(tempAfterLayoutBounds); sorttype = 1; } public void relayout(){ if (sorttype == 1){ sortByPenID(); } else if (sorttype == 2){ sortByDrawingAmount(); } else if (sorttype == 3){ sortBySeat(); } else if (sorttype == 4){ sortByTeinei(); } updateCameraView(); } public void updateCameraView(){ for(FocusRectangle fr: rects_bysid.values()){ fr.updateCameraView(); } } public FocusRectangle findFocusRectAtGlobalPoint(Point2D p){ @SuppressWarnings("unchecked") Collection<PNode> c = getCanvas().getLayer().getAllNodes(); for(PNode n: c){ if (n instanceof FocusRectangle){ FocusRectangle s = (FocusRectangle)n; if (s.getGlobalBounds().contains(p)){ return s; } } } return null; } public int getZoomLevel(){ double h = getCanvas().getCamera().getViewBounds().getHeight(); double w = getCanvas().getCamera().getViewBounds().getWidth(); PBounds pb = rects_bysid.get(rects_bysid.firstKey()).getGlobalFullBounds(); PBounds gfb = getCanvas().getLayer().getGlobalFullBounds(); // System.out.println("diffw "+Math.abs(gfb.getWidth()-w)+ " w "+w); // System.out.println("diffh "+Math.abs(gfb.getHeight()-h)+ " h "+h); if (Math.abs(gfb.getWidth()-w)<w*0.01 || Math.abs(gfb.getHeight()-h)<h*0.01) return -1; //もうレイアウト済み if (h > pb.getHeight() * 1.30){ // System.out.println("W "+w + " w "+pb.getWidth()+" "+Math.abs(w-pb.getWidth())+" "+w*0.1); if (Math.abs(w-pb.getWidth())<w*0.1 ) { return 1; } return 0; } else if (h < pb.getHeight() * 0.50){ return 2; } return 1; } public void upview(){ upview(getZoomLevel()); } public void upview(int zoomLevel){ if (zoomLevel == 2){ Point2D centerP = getCanvas().getCamera().getViewBounds().getCenter2D(); centerP = getCanvas().getCamera().localToGlobal(centerP); //中心点がふくまれる,Sheetを検索する.複数あったら最初のものを採用. FocusRectangle sheet = findFocusRectAtGlobalPoint(centerP); if (sheet != null){ Rectangle2D globalb = sheet.getGlobalBounds(); sheet.canvas.getCamera().animateViewToCenterBounds(globalb, true, 1000); } else { zoomHome(1000); } // getCanvas().getCamera().animateViewToCenterBounds(BUtil.zoomBounds(getCanvas().getCamera().getViewBounds(), 3.0),false,1000); } else if (zoomLevel == -1){ relayout(); zoomToBounds(tempAfterLayoutBounds); } else { zoomHome(1000); } } //全体画面を表示 public void zoomHome(int msec){ getCanvas().getCamera().animateViewToCenterBounds(getCanvas().getLayer().getGlobalFullBounds(),true, msec);//msecミリ秒かけてアニメーション } //TODO: public Dimension availableScreenSize(){ Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); return new Dimension((int)(dim.getWidth()-60)/2, (int)(dim.getHeight()-40)); } public Dimension availableMaxScreenSize(){ Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); return new Dimension((int)(dim.getWidth()-60), (int)(dim.getHeight()-40)); } public void windowMaximize(){ if (satn.menutoolbar.getAction("Secondary Display").isSelected()){ satn.showFrameOnSecondaryDisplay(this); } else { setSize(availableMaxScreenSize()); setLocation(0, 0); } } public void windowNormalize(){ setSize(availableScreenSize()); setLocation(550, 0); } public void processCursorKey(int keyCode) { int zL = getZoomLevel(); if (zL == 1){ Point2D centerP = getCanvas().getCamera().getViewBounds().getCenter2D(); centerP = getCanvas().getCamera().localToGlobal(centerP); //中心点がふくまれる,Sheetを検索する.複数あったら最初のものを採用. FocusRectangle sheet = findFocusRectAtGlobalPoint(centerP); if (sheet != null){ LayoutContent nextFR = layoutActive.getUDLR(keyCode, sheet); // int pos = rects_sorted.indexOf(sheet); // int offset = 0; // if (keyCode == KeyEvent.VK_UP) offset = -layoutcols; // if (keyCode == KeyEvent.VK_DOWN) offset = layoutcols; // if (keyCode == KeyEvent.VK_LEFT) offset = -1; // if (keyCode == KeyEvent.VK_RIGHT) offset = 1; // FocusRectangle nextFR = getNext(pos, offset); if (nextFR == null) { zoomHome(1000); } else { nextFR.focus(); } } } else if (zL == 2){ PBounds pb = getCanvas().getCamera().getViewBounds(); if (keyCode == 38) {// 上 pb.moveBy(0, -pb.getHeight()*0.8); zoomToBounds(pb); } if (keyCode == 37) {// 左 pb.moveBy(-pb.getWidth()*0.8,0); zoomToBounds(pb); } if (keyCode == 39) {// 右 pb.moveBy(pb.getWidth()*0.8,0); zoomToBounds(pb); } if (keyCode == 40) {// 下 pb.moveBy(0,pb.getHeight()*0.8); zoomToBounds(pb); } } else { if (keyCode == 38) {// 上 getCanvas().getCamera().translateView(0,10); getCanvas().repaint(); } if (keyCode == 37) {// 左 getCanvas().getCamera().translateView(10,0); getCanvas().repaint(); } if (keyCode == 39) {// 右 getCanvas().getCamera().translateView(-10,0); getCanvas().repaint(); } if (keyCode == 40) {// 下 getCanvas().getCamera().translateView(0,-10); getCanvas().repaint(); } } } public void zoomToBoundsWithWait(PBounds pb, int msec){ class ZoomToBoundsTask extends TimerTask{ public void run(){ zoomToBounds(tempAfterLayoutBounds); } } Timer t = new Timer(); t.schedule(new ZoomToBoundsTask(), msec); } public void zoomToBounds(PBounds pb) { zoomToBounds(pb, SimpleATN.zoommsec); } public void zoomToBounds(PBounds pb, int msec) { getCanvas().getCamera().animateViewToCenterBounds(pb, true, msec); } //フォーカスリファレンス Dimension fsize; Point floc; public boolean isFocusReferenceMode = false; public void toggleFocusReference() { isFocusReferenceMode = !isFocusReferenceMode; if (isFocusReferenceMode){ fsize = getSize(); floc = getLocation(); setSize((int)(sheetb.getWidth()*1.4), (int)(sheetb.getHeight()*1.4)); setLocation((int)SimpleATN.theapp.getLocation().getX(), (int)(SimpleATN.theapp.getLocation().getY()+SimpleATN.theapp.getSize().getHeight()+1)); } else { setSize(fsize); setLocation(floc); } } public void delete(){ dispose(); FocusFrame.frames.remove(this); for(FocusRectangle fr: rects_bysid.values()){ fr.focussrc.removeFromParent(); } } //追加機能分のメニュー public void addPluginMenuTo(JPopupMenu menu) { for(DefaultPlugin dp: plugins){ dp.addMenu(menu); } } //フォーカス from LayerSeatmapButton public void focus(int penid) { FocusRectangle fr = rects_bysid.get(penid); if (fr != null) zoomToBounds(fr.getGlobalBounds()); } public void layoutBySeatmap() { if (layoutseat == null){ if (ConfigWindow.configWin.seatmap.active_smap != null){ layoutseat = new LayoutBySeat(getCanvas().getCamera(), ConfigWindow.configWin.seatmap.active_smap); } } layoutseat.layout(0, this); tempAfterLayoutBounds = layoutseat.contentregion(this); } @Override public ArrayList<LayoutContent> getLayoutContents() { ArrayList<LayoutContent> cnt = new ArrayList<LayoutContent>(); cnt.addAll(rects_bysid.values()); return cnt; } }