package jp.ac.kyutech.mns.ist; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDropEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Hashtable; import java.util.TooManyListenersException; import java.util.TreeMap; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import javax.swing.Timer; import jp.ac.kyutech.mns.ist.filter.RegionSSFilter; import jp.ac.kyutech.mns.ist.plugin.DefaultPlugin; import jp.ac.kyutech.mns.ist.plugin.WindowManagerPlugin; import jp.ac.kyutech.mns.ist.sheetmap.SeatmapController; import jp.ac.kyutech.mns.ist.util.FileReadWriter; import jp.ac.kyutech.mns.ist.util.MemoryMonitor; import jp.ac.kyutech.mns.ist.util.MultiDisplay; import jp.ac.kyutech.mns.ist.util.MyAction; import jp.ac.kyutech.mns.ist.util.MyPImage; import jp.ac.kyutech.mns.ist.util.NetUtil; import jp.ac.kyutech.mns.ist.util.NullFileFilter; import jp.ac.kyutech.mns.ist.util.PrintPrintable; import jp.ac.kyutech.mns.ist.util.SingleTableSelector; 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.PLayer; import edu.umd.cs.piccolo.PNode; import edu.umd.cs.piccolo.event.PBasicInputEventHandler; import edu.umd.cs.piccolo.event.PInputEvent; import edu.umd.cs.piccolo.event.PInputEventFilter; import edu.umd.cs.piccolo.event.PPanEventHandler; import edu.umd.cs.piccolo.nodes.PText; import edu.umd.cs.piccolo.util.PBounds; import edu.umd.cs.piccolo.util.PObjectOutputStream; import edu.umd.cs.piccolo.util.PPaintContext; // TODO // FocusFrameをぴったりのサイズにする.とくに集約表示.先に推奨比率を調べる // レイアウトのリファクタリング // Macでもうごくように,なるべく同一のコードをつかう /** * SimpleなAirTransNote.筆記を表示するだけ. * 右ドラッグ範囲にズーム,マウスホイールでズーム, * @author miuramo */ public class SimpleATN extends FullScreenableJFrame implements Runnable, PathDropActionListener, LayoutTarget { private static final long serialVersionUID = -8183529835329375441L; public static SimpleATN theapp; public static int zoommsec = 1000; public SimpleATN_MenuToolbarAction menutoolbar; public PLayer layer; public ATN_Mysql_DB mysqldb; public ATN_Mysql_DB mysqldb_root; boolean isNoDB = false; public DB_Lecture openingLecture; public String openingLectureid; ZoomRegionHandler zrh;//Event_onSheetが参照するため PPanEventHandler panEventHandler; DrawPenToolbar drawToolbar; public String dbuser="atnuser", dbpass="atnuser", dbname="atnrepos"; int layoutcols = 0; PBounds tempAfterLayoutBounds = null; int filedialogopennum = 0; DropTarget dropTarget = null; public static boolean isMACOSX = false; static { String lcOSName = System.getProperty("os.name").toLowerCase(); isMACOSX = lcOSName.startsWith("mac os x"); } public TreeMap<Integer,Note> notes; public String pimagePath;//画像があるフォルダのパス.カレントディレクトリから探索し,複数あったら選択する. // public ConfigPanel_PImageFinder pimagePathFinder; public Hashtable<Integer,MyPImage> pimages; // public Hashtable<Integer,MyPImage> oldpimages; int current_cursornum = Cursor.DEFAULT_CURSOR; int sheetVisibleMode[] = new int[7];//{2,2,2,2,2,2,2,2}; //0:all hide, 1: only data, 2: all show SimpleATN_UDPNoticeReceiver updator; InsideToolbar_SheetVisible sheetVisibleToolbuttons; PText toolTipPText = null; ArrayList<DefaultPlugin> plugins; InspectorPlugin inspector; Event_onSATN event_onsatn; LayoutAbstract layoutabst; LayoutBySeat layoutseat; public String initArgFile; public String openingFile; public SimpleATN() { this(null,null); } public SimpleATN(String arg, int count){ this(null,arg); } public void changeTitle(String file){ openingFile = file; setTitle("SimpleATN ver "+SimpleATN.class.getPackage().getImplementationVersion() + " "+file); } public SimpleATN(final PCanvas aCanvas, final String file) { super("SimpleATN ver "+SimpleATN.class.getPackage().getImplementationVersion() + " "+file);//TODO:satnファイル読み込み時に修正する theapp = this; initArgFile = file; setBackground(null); setBounds(getDefaultFrameBounds()); for(int i=1;i<7;i++) sheetVisibleMode[i] = 1; sheetVisibleMode[0]=2; try { setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); } catch (final SecurityException e) { System.out.println("Ignoring security exception. Assuming Applet Context."); } addWindowListener(new WindowListener(){ public void windowActivated(WindowEvent arg0) { } public void windowClosed(WindowEvent arg0) { } public void windowClosing(WindowEvent arg0) { ConfigWindow.configWin.filter.saveBeforeExit(); System.exit(0); } public void windowDeactivated(WindowEvent arg0) { } public void windowDeiconified(WindowEvent arg0) { } public void windowIconified(WindowEvent arg0) { } public void windowOpened(WindowEvent arg0) { } }); if (canvas == null) { this.canvas = new PCanvas(); //マウスが動いたら,カーソルをもとに戻す this.canvas.addInputEventListener(new PBasicInputEventHandler() { public void mouseMoved(final PInputEvent aEvent) { popCursor(); aEvent.setHandled(true); } }); } canvas.setDefaultRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); canvas.setAnimatingRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); canvas.setInteractingRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); // canvas.removeInputEventListener(canvas.getPanEventHandler()); notes = new TreeMap<Integer, Note>(); pimages = new Hashtable<Integer, MyPImage>(); // oldpimages = new Hashtable<Integer, MyPImage>(); menutoolbar = new SimpleATN_MenuToolbarAction(this); menutoolbar.foldToolbarText(true); ConfigWindow.setVisible(this, false); checkSecondaryDisplay();//もし,セカンダリ画面があれば,アイコン選択状態にする.あとで解除可能. getContentPane().add(this.canvas, BorderLayout.CENTER); validate(); setFullScreenMode(false); // pimagePathFinder = new ConfigPanel_PImageFinder(this, new File(System.getProperty("user.dir")), SimpleATN_ConfigWindow.configWin); dropTarget = new DropTarget(); try{ dropTarget.addDropTargetListener(new PathDropTargetListener(this)); getCanvas().setDropTarget(dropTarget); }catch(TooManyListenersException ex){ ex.printStackTrace(System.out); } SwingUtilities.invokeLater(new Runnable() { public void run() { SimpleATN.this.initialize(file); repaint(); } }); sheetVisibleToolbuttons = new InsideToolbar_SheetVisible(this); getCanvas().getCamera().addChild(sheetVisibleToolbuttons); InsideToolbar_ZoomHandle zh = new InsideToolbar_ZoomHandle(getCanvas().getCamera()); getCanvas().getCamera().addChild(zh); InsideToolbar_PanHandle ph = new InsideToolbar_PanHandle(getCanvas().getCamera()); getCanvas().getCamera().addChild(ph); updator = new SimpleATN_UDPNoticeReceiver(this); setVisible(true); } /** * 画像フォルダの設定と,保存済み筆跡マップの読み込み * @param f */ public void setBGImagePath(File f){ // File f = new File("atntemplates"); if (f != null && f.exists()){ pimagePath = f.getAbsolutePath(); System.out.println(pimagePath); pimages.clear();//一旦削除 if (isMACOSX){ for(int i=1;i<7;i++){ byte[] b = FileReadWriter.readBytesFromFile(pimagePath+File.separator+"スライド"+i+".png"); MyPImage pimg = new MyPImage(b, false); pimages.put(i,pimg); } } else { for(int i=1;i<7;i++){ byte[] b = FileReadWriter.readBytesFromFile(pimagePath+File.separator+"スライド"+i+".PNG"); MyPImage pimg = new MyPImage(b, false); pimages.put(i,pimg); } } //設定ファイルを読み込む ArrayList<String> setup = FileReadWriter.getLinesList(pimagePath+File.separator+"setup.txt", true); ArrayList<String> copy = new ArrayList<String>(); for(String ts: setup){ copy.add(ts); } boolean hasModification = false; for(String ts: copy){ String s = ts.trim(); if (s.startsWith("#")) continue; else if (s.length()<1) continue; else if (s.startsWith("seatmap")){ int conf = JOptionPane.showConfirmDialog(this, "筆席マップ "+s+" を読み込みますか?\n\n「いいえ」をおすと,次回も尋ねます.\n「取消」をおすと,設定を削除し,今後は尋ねません."); if (conf == JOptionPane.YES_OPTION){ new SeatmapController(s, SimpleATN.theapp); } else if (conf == JOptionPane.CANCEL_OPTION){ setup.remove(ts); hasModification = true; } } } if (hasModification){ FileReadWriter.putLines(this.pimagePath+File.separator+"setup.txt", setup); } } else { JOptionPane.showMessageDialog(this, "背景画像フォルダがみつかりませんでした"); } } public void pushCursor(int cursornum){ if (cursornum != current_cursornum){ current_cursornum = cursornum; canvas.pushCursor(new Cursor(current_cursornum)); } } public void popCursor(){ canvas.popCursor(); current_cursornum = Cursor.DEFAULT_CURSOR; } public void initialize(String file) { //remove default zoom event hander getCanvas().removeInputEventListener(getCanvas().getZoomEventHandler()); getCanvas().removeInputEventListener(getCanvas().getPanEventHandler()); // Button1 - Pan 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)); plugins = new ArrayList<DefaultPlugin>(); plugins.add(new WindowManagerPlugin(getCanvas(), this)); //プラグインとして,インスペクタを追加 inspector = new InspectorPlugin(getCanvas(), this); plugins.add(inspector); event_onsatn = new Event_onSATN(this); getCanvas().getCamera().addInputEventListener(event_onsatn); getCanvas().getPanEventHandler().setEventFilter(new PInputEventFilter(InputEvent.BUTTON3_DOWN_MASK)); //キー入力(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() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_F || e.getKeyCode() == KeyEvent.VK_R || e.getKeyCode() == KeyEvent.VK_M){ if (zrh.selection != null){ if (zrh.pressN != null && zrh.pressN instanceof Sheet){ Sheet s = (Sheet)zrh.pressN; s.collect(zrh.selection, e.getKeyCode()); } if (zrh.pressN != null && zrh.pressN instanceof SSGroup){ //SSGRoup だったら,シートに変換 SSGroup ssg = (SSGroup)zrh.pressN; ssg.sheet.collect(zrh.selection, e.getKeyCode()); } } zrh.dismissRegionLater(); } if (e.getKeyCode() == KeyEvent.VK_Z){ System.out.println("SimpleATN zoomLevel = "+getZoomLevel()); } if (e.getKeyCode() == KeyEvent.VK_A || e.getKeyCode() == KeyEvent.VK_0){ // addNote(); for(int i=0;i<7;i++){ sheetVisibleMode[i]=2; } sheetVisibleToolbuttons.updateStatus(); setSheetVisible(-1, 2); } if (e.getKeyCode() == KeyEvent.VK_F11){ menutoolbar.getButton("Full Screen").doClick(); } //範囲選択中なら... if (zrh.isDragging() && zrh.selection != null){ if (KeyEvent.VK_1 <= e.getKeyCode() && e.getKeyCode() <= KeyEvent.VK_5){ //領域フィルタに追加 if (zrh.pressN != null && zrh.pressN instanceof Sheet){ Sheet s = (Sheet)zrh.pressN; ConfigWindow.configWin.filter.addRegionFilter(s, zrh.selection, e.getKeyCode()); } if (zrh.pressN != null && zrh.pressN instanceof SSGroup){ //SSGRoup だったら,シートに変換 SSGroup ssg = (SSGroup)zrh.pressN; // ssg.sheet.collect(zrh.selection, e.getKeyCode()); ConfigWindow.configWin.filter.addRegionFilter(ssg.sheet, zrh.selection, e.getKeyCode()); } zrh.dismissRegionLater(); } } else { if (KeyEvent.VK_1 <= e.getKeyCode() && e.getKeyCode() <= KeyEvent.VK_6){ //以前:1〜6の数字を入力したら,そのシートの表示モードの切り替え // int sn = e.getKeyCode() - KeyEvent.VK_0; // sheetVisibleMode[sn] = (sheetVisibleMode[sn]+1)%3; // setSheetVisible(sn, sheetVisibleMode[sn]); // sheetVisibleToolbuttons.updateStatus(); //現在:そのシートのみを表示 for(int i=0;i<7;i++){ sheetVisibleMode[i]=0; } sheetVisibleToolbuttons.updateStatus(); int sn = e.getKeyCode() - KeyEvent.VK_0; for(Note n: notes.values()) n.applySheetVisible(); setSheetVisible(sn, 2); } } PBounds pb = getCanvas().getCamera().getViewBounds(); int keyCode = e.getKeyCode(); if (keyCode == 38) {// 上 pb.moveBy(0, -pb.getHeight()); zoomToBounds(pb,1000,"KeyPan"); } if (keyCode == 37) {// 左 pb.moveBy(-pb.getWidth(),0); zoomToBounds(pb,1000,"KeyPan"); } if (keyCode == 39) {// 右 pb.moveBy(pb.getWidth(),0); zoomToBounds(pb,1000,"KeyPan"); } if (keyCode == 40) {// 下 pb.moveBy(0,pb.getHeight()); zoomToBounds(pb,1000,"KeyPan"); } } }); getCanvas().requestFocus(); layer = getCanvas().getLayer(); //最初にデータベースを読みに行く if (file==null){ openConnection(); } else { // loadFromFile(file); } } /** * シートの表示・非表示. * sn=sheet number, 0はペン番号, 1~6はシート, -1なら全て(ペン番号含む) * mode=0は非表示,1は筆記があれば,2は常に * @param sn * @param mode */ public void setSheetVisible(int sn, int mode){ if (sn > -1) sheetVisibleMode[sn] = mode; // for(int i=0;i<7;i++) System.out.print(sheetVisibleMode[i]+" "); // System.out.println(""); setSheetVisible(sn, mode, true, true); } public void setSheetVisible(int sn, int mode, boolean doLayout, boolean showMessage){ if (sn == -1){ //Apply to All sheets for(int i=0;i<7;i++){ for(Note n: notes.values()){ n.toggleVisible(i, mode); } } if (doLayout){ relayout(1000, "SATN.setSheetVisible"); zoomToBounds(tempAfterLayoutBounds, 1000,"SATN.setSheetVisible"); } if (showMessage){ String m[] = {"を隠す","に書き込みがあれば表示","を表示"}; showFadingMessage("すべてのシート "+m[mode], messageColor, Color.black, 2, 0.9f); } } else { for(Note n: notes.values()){ n.toggleVisible(sn, mode); } if (doLayout){ relayout(1000, "SATN.setSheetVisible"); zoomToBounds(tempAfterLayoutBounds, 1000,"SATN.setSheetVisible"); } if (showMessage){ String num = "シート "+String.valueOf(sn); if (sn==0) num="ペン番号"; String m[] = {"を隠す","に書き込みがあれば表示","を表示"}; if (sn==0) m[1] = "は表示すべきシートがあるときのみ表示"; showFadingMessage(num+" "+m[mode], messageColor, Color.black, 2, 0.9f); } } } /** * ズームアウト,レイアウト済みなら-1 * 表示領域の高さがノートの高さより,すこしでも大きければ0 * 表示領域の高さがノートの高さと同じなら1 * 表示領域の高さがノートの高さの70%以下なら,ズームイン=2 * @return */ public int getZoomLevel(){ double h = getCanvas().getCamera().getViewBounds().getHeight(); double w = getCanvas().getCamera().getViewBounds().getWidth(); // PBounds pb = notes.get(0).getGlobalFullBounds(); PBounds gfb = getCanvas().getLayer().getGlobalFullBounds(); if (Math.abs(gfb.getWidth()-w)<w*0.01 || Math.abs(gfb.getHeight()-h)<h*0.01) return -1; //もうレイアウト済み if (h > Note.height * 1.02){ return 0; } else if (h < Note.height * 0.70){ 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を検索する.複数あったら最初のものを採用. Sheet sheet = findSheetAtGlobalPoint(centerP); if (sheet != null){ Rectangle2D globalb = sheet.getGlobalBounds(); zoomToBounds(globalb, 1000,"SATN.upview(int)"); } else { zoomToBounds(tempAfterLayoutBounds, 1000,"SATN.upview(int)"); } } else if (zoomLevel == -1){ relayout(1000, "SATN.upview(int)"); zoomToBounds(tempAfterLayoutBounds, 1000,"SATN.upview(int)"); } else { zoomToBounds(tempAfterLayoutBounds, 1000,"SATN.upview(int)"); } } public Sheet findSheetAtGlobalPoint(Point2D p){ @SuppressWarnings("unchecked") Collection<PNode> c = getCanvas().getLayer().getAllNodes(); for(PNode n: c){ if (n instanceof Sheet){ Sheet s = (Sheet)n; if (s.getGlobalBounds().contains(p)){ return s; } } } return null; } // //全体画面を表示 // public void zoomHome(int msec){ // getCanvas().getCamera().animateViewToCenterBounds(layer.getGlobalFullBounds(),true, msec);//msecミリ秒かけてアニメーション // } //called from DB import (initial) public Note getNote(int penid){ Note n = notes.get(penid); if (n==null){ n = addNote(penid); } return n; } //あいている番号を手当たり次第追加する public Note addNote(){ int n = 1; while(true){ if (notes.get(n)==null) {return addNote(n);} n++; } } //ボタンで,あとから追加する(ここでは,表示シートの設定やレイアウトはしない) public Note addNote(int penid){ if (notes.get(penid)!=null) return null; Note n = new Note(penid, this); notes.put(penid, n); getCanvas().getLayer().addChild(n); for(FocusFrame ff: FocusFrame.frames){ ff.applyToNote(n,true); } return n; } public static void main(final String[] args) { if (args.length >= 2){ StringBuffer sb = new StringBuffer(); for(int i=1;i<args.length;i++){ sb.append(args[i]+" "); } new SimpleATN(sb.toString().trim(), args.length); } else { new SimpleATN(); } } public void openConnection() { if (mysqldb == null) mysqldb = new ATN_Mysql_DB(this, dbuser, dbpass, dbname); if (mysqldb == null) return; if (mysqldb_root == null) mysqldb_root = new ATN_Mysql_DB(this, "root", "root", dbname); if (mysqldb_root == null) return; ArrayList<DB_Lecture> dblec = mysqldb.get_db_lectures(true); if (dblec == null) return; if (dblec.size()==0) { JOptionPane.showMessageDialog(this, "筆記がありませんでした"); return; } DB_Lecture selectedDBLec = null; if (dblec.size()>1){ // System.out.println(dblec.size()); // SingleSelector<DB_Lecture> sel = new SingleSelector<DB_Lecture>(dblec, this, "読み込む講義を選択してください"); SingleTableSelector<DB_Lecture> sel = new SingleTableSelector<DB_Lecture>(dblec, this, "読み込む講義を選択してください", new String[]{"id","name","size","Start datetime"," "}, new String[]{"id","name","dataamount","tstamp",""}, new String[]{"start"}, new int[]{30,300,60,200,100}); if (sel.selectedObj == null) return; selectedDBLec = sel.selectedObj; } else { //TODO: もうここは使わない? selectedDBLec = dblec.get(0); if (selectedDBLec.dataamount==0){ JOptionPane.showMessageDialog(this, "筆記がありませんでした"); return; } } //もし新規読み取りで、継続データがあれば、名前をつけて保存する。 if (selectedDBLec.dataamount == 0 && selectedDBLec == dblec.get(0)){ if (dblec.get(1).id == 0 && dblec.get(1).dataamount > 0){ //以前の筆記にテンポラリーな名前をつけて保存 SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mmに保存"); String name = JOptionPane.showInputDialog(this, "新規取り込みを開始するには、既存の筆記に名前をつけて保存してください\nキャンセルすると新規取り込みを中止します", sdf.format(System.currentTimeMillis())); if (name == null){ return; } mysqldb.fixAsNamedLecture(name); } showFadingMessage("新規取り込みを開始しました", SimpleATN.messageColor, Color.black, 2, 0.9f); } //もし以前に開いているノートがあれば,消す if (openingLecture != null) { openingLecture.stop(); this.removeAllNote(true); //シートマップの登録も解除 for(SeatmapController smap: ConfigWindow.configWin.seatmap.smaps){ smap.clean(); } } System.out.println("Loading "+selectedDBLec.toString()); selectedDBLec.loadPenData(this, mysqldb); // TODO: grouping // for(Note n: notes.values()){ // n.grouping(100); // } openingLecture = selectedDBLec; openingLectureid = String.valueOf(selectedDBLec.id); menutoolbar.getAction("Reload").setEnabled(true); // menutoolbar.getAction("Reload").setSelected(true);//UDP Notificationができたので自動で定期チェックはしない //ここで,フィルタがあれば読み込む TODO: 一旦削除 /// RegionSSFilter.loadAfterLectureLoad(); // relayout(0);//最初のレイアウト // zoomToBounds(tempAfterLayoutBounds,1000); Timer t = new Timer(1000, new SimpleATN_LayoutAction(this)); t.setRepeats(false); t.start(); } //OpenConnectionに失敗したとき public void findDBName(){ //まずroot/rootで試みて,データベースを探す JOptionPane.showMessageDialog(this, "データベース探索機能,パスワード再設定機能は未実装です"); } public void removeAllNote(boolean deleteff) { int p; if (!deleteff){ p = JOptionPane.showConfirmDialog(this, "集約表示枠も削除する?\n(表示リセットをキャンセルするときは「取消」)","表示リセット",JOptionPane.YES_NO_CANCEL_OPTION); if (p == JOptionPane.CANCEL_OPTION) return; } else { p = JOptionPane.YES_OPTION; } if (p == JOptionPane.YES_OPTION) { for(FocusFrame ff: FocusFrame.frames){ ff.dispose(); } FocusFrame.frames.clear(); } getCanvas().getLayer().removeAllChildren(); notes.clear(); //筆記モードなら,もとに戻す if (menutoolbar.getAction("Draw").isSelected()){ menutoolbar.getAction("Draw").doClick(); showFadingMessage("筆記モードを解除しました.\nDraw Mode has been reverted.", SimpleATN.messageColor, Color.black, 2, 0.9f); } } // //テスト用.筆記をそれぞれのNoteのSheetに追加する // public void addPNodeToEachNote(int sheetnum, Rectangle2D pb){ // for(Note n: notes.values()){ // Sheet s = n.sheets.get(sheetnum); // s.addChild(new PPath(pb)); // } // } @Override public void run() { try {Thread.sleep(1200);} catch (InterruptedException e) { e.printStackTrace();} for(FocusFrame ff: FocusFrame.frames) ff.updateCameraView(); } public ArrayList<LayoutContent> getLayoutContents(){ ArrayList<LayoutContent> cnt = new ArrayList<LayoutContent>(); cnt.addAll(notes.values()); return cnt; } public void relayout(int msec, String caller){ boolean finished = false; //筆跡マップが有効か? MyAction seatmap; if (menutoolbar != null){ seatmap = menutoolbar.getAction("SheetMap"); if (seatmap != null && seatmap.isSelected()){ 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); finished = true; } } } if (!finished){ layoutabst = new LayoutAbstract(getCanvas().getCamera()); layoutabst.layout(0, this); tempAfterLayoutBounds = layoutabst.contentregion(this); //最適な配置を考える // System.out.println("relayout by "+caller); // tempAfterLayoutBounds = new PBounds(); // int gap = 0; // ArrayList<Note> rects = new ArrayList<Note>(); // rects.addAll(notes.values()); // int cols = getBestFitLayout(rects, getCanvas().getCamera().getViewBounds(), gap, gap); // ArrayList<PActivity> palist = layout(rects, cols, gap, gap, msec, tempAfterLayoutBounds); // layoutcols = cols; // long mtime = System.currentTimeMillis(); // for (PActivity pact : palist) if (pact != null) pact.setStartTime(mtime); } // update FocusFrame view Thread t = new Thread(this); t.start(); //もしペン筆記到来からの再レイアウト要求でなければ if (!caller.equals("DB_Lec.loadPenData")){ for(Note n: notes.values()){ for(Sheet s: n.sheets.values()){ s.showFadingSheetNum(2000); } } } } /** * シートマップでレイアウト * @param stu2pos */ 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); zoomToBounds(tempAfterLayoutBounds,1000,"satn.layoutBySeatmap"); } public void zoomToBounds(Rectangle2D pb, int msec, String caller){ zoomToBounds(pb, msec, caller, null); } public void zoomToBounds(Rectangle2D pb, int msec, String caller, PInputEvent aEvent) { if (pb != null) { // System.out.println("zoom to "+pb.toString()+" by "+caller); new SimpleATN_animateCameraView(getCanvas().getCamera(), pb, msec, aEvent); } } public static void openMemoryMonitor() { final MemoryMonitor demo = new MemoryMonitor(); final JFrame f = new JFrame("MemoryMonitor"); WindowListener l = new WindowAdapter() { public void windowClosing(WindowEvent e) { demo.surf.stop(); f.dispose(); } public void windowDeiconified(WindowEvent e) { demo.surf.start(); } public void windowIconified(WindowEvent e) { demo.surf.stop(); } }; f.addWindowListener(l); f.getContentPane().add(demo, BorderLayout.CENTER); f.pack(); f.setSize(new Dimension(200, 200)); f.setVisible(true); f.setLocation(965, 1); demo.surf.start(); } public void setDrawMode(boolean b) { if (drawToolbar == null) drawToolbar = new DrawPenToolbar(); if (b){ panEventHandler.setEventFilter(new PInputEventFilter(InputEvent.BUTTON2_MASK));//本当は効果を消したい PCamera cam = getCanvas().getCamera(); cam.addChild(drawToolbar); drawToolbar.setOffset((cam.getWidth()-drawToolbar.getWidth())/2,0); if (SimpleATN.theapp.isNoDB){ SimpleATN.theapp.showFadingMessage("DB未接続です.筆記を保存するにはファイルに保存してください", SimpleATN.messageColor, Color.black, 2, 0.9f); } } else { panEventHandler.setEventFilter(new PInputEventFilter(InputEvent.BUTTON1_MASK)); drawToolbar.removeFromParent(); } for(Note n: notes.values()){ for(Sheet s: n.sheets.values()){ s.setDrawMode(b); } } } public String selectfile(boolean issave, String ext){ // ファイルダイアログを開く String cdir = System.getProperty("user.dir"); JFileChooser fd = new JFileChooser(cdir); NullFileFilter nff = new NullFileFilter(ext); fd.setFileFilter(nff); int returnval; if (issave) returnval = fd.showSaveDialog(this); else returnval = fd.showOpenDialog(this); if (returnval == JFileChooser.APPROVE_OPTION){ // 拡張子がついていないとき,むりやりつける StringBuffer path = new StringBuffer(fd.getSelectedFile().getAbsolutePath()); if (!path.toString().endsWith(ext)){ path.append(ext); } return path.toString(); }else{ return null; } } public void saveToFile(String fn) { if (fn == null) fn = selectfile(true,".satn"); if (fn == null) return;//もしファイル名を選択しなかったら FileReadWriter.writeBytesToFile(fn, byteSerializeExport(true)); File f = new File(fn); showFadingMessage(f.getName()+"\nに保存しました", messageColor, Color.black, 2, 0.9f); } public void saveFrameToFile(String fn) { if (fn == null) fn = selectfile(true,".waku"); if (fn == null) return;//もしファイル名を選択しなかったら FileReadWriter.writeBytesToFile(fn, byteSerializeExport(false)); File f = new File(fn); showFadingMessage("領域データを "+f.getName()+"\nに保存しました", messageColor, Color.black, 2, 0.9f); } public void loadFromFile(String fn,int num){ if (filedialogopennum == 2 && num==2) return; System.out.println(num); filedialogopennum = num; if (fn == null) fn = selectfile(false,".satn"); if (fn == null) return;//もしファイル名を選択しなかったら removeAllNote(true); byte[] ba = FileReadWriter.readBytesFromFile(fn); byteSerializeImport(ba,true); File f = new File(fn); showFadingMessage(f.getName()+"\nから読み込みました", messageColor, Color.black, 2, 0.9f); changeTitle(f.getAbsolutePath()); openingLectureid = f.getName(); //ここで,フィルタがあれば読み込む RegionSSFilter.loadAfterLectureLoad(); relayout(1000, "SimpleATN.loadFromFile"); zoomToBounds(tempAfterLayoutBounds, 1000, "DB_Lec.loadPenData"); } public void loadFrameFromFile(String fn){ if (fn == null) fn = selectfile(false,".waku"); if (fn == null) return;//もしファイル名を選択しなかったら byte[] ba = FileReadWriter.readBytesFromFile(fn); byteSerializeImport(ba,false); File f = new File(fn); showFadingMessage("領域データを "+f.getName()+"\nから読み込みました", messageColor, Color.black, 2, 0.9f); } public transient static Color messageColor = new Color(204,238,255); public byte[] byteSerializeExport(boolean waku_all) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputStream gzipos = null; PObjectOutputStream pobjos = null; // PNodeを保存するときはPObjectOutputStream try { gzipos = new GZIPOutputStream(baos); pobjos = new PObjectOutputStream(gzipos); if (waku_all){ // collect target nodes pobjos.writeInt(notes.size()); System.out.println("Note size "+notes.size()); for(Note n: notes.values()){ pobjos.writeInt(n.getAll().size()); System.out.println("Note "+n.penid+" SS size "+n.getAll().size()); for(ShortStroke ss: n.getAll()){ ss.penid = n.penid; pobjos.writeObjectTree(ss); } } pobjos.writeInt(pimages.size()); System.out.println("PImages size "+pimages.size()); for(int i=1;i<=pimages.size();i++){ pobjos.writeObjectTree(pimages.get(i)); } } pobjos.close(); gzipos.close(); } catch (IOException iex) { iex.printStackTrace(System.out); } System.out.println("save size: " + baos.size() + " bytes."); return baos.toByteArray(); } public void byteSerializeImport(byte[] ba, boolean waku_all){ ByteArrayInputStream bais = new ByteArrayInputStream(ba); InputStream gzipis = null; ObjectInputStream ois = null; PNode pn = null; try { gzipis = new GZIPInputStream(bais); ois = new ObjectInputStream(gzipis); if (waku_all){ int num = ois.readInt(); for(int i=0;i<num;i++){ int ssnum = ois.readInt(); for(int j=0;j<ssnum;j++){ pn = (PNode) ois.readObject(); if (pn instanceof ShortStroke){ ShortStroke ss = (ShortStroke)pn; ss.addEventOnSS(); this.getNote(ss.penid).addStroke(ss); } } } int pinum = ois.readInt(); if (pinum > 0) pimages.clear(); for(int i=1;i<=pinum;i++){ pn = (PNode) ois.readObject(); if (pn instanceof MyPImage){ MyPImage ss = (MyPImage)pn; pimages.put(i, ss); } } } ois.close(); gzipis.close(); bais.close(); } catch (EOFException eofex) { eofex.printStackTrace(); } catch (IOException excep) { excep.printStackTrace(System.err); } catch (ClassNotFoundException excnf) { System.err.println("ClassNotFound Error"); } finally { } } public void printToPDF() { // setSize(592,876); String sht = JOptionPane.showInputDialog(this,"(1/2) 印刷するシート番号(1-6)を入力してください。"); int shtnum = 0; if (sht == null) return; try{ shtnum = Integer.parseInt(sht); } catch(NumberFormatException nfex){ return; } if (shtnum == 0) return; if (menutoolbar.getAction("Landscape Mode").isSelected()) { setSize(876-90,572+90); } else { setSize(572,876); } //ハンドルの消去 for(Object o: getCanvas().getCamera().getAllNodes()){ if (o instanceof PNode){ PNode pn = (PNode)o; if (pn instanceof InsideToolbar_ZoomHandle){ pn.setVisible(false); } else if (pn instanceof InsideToolbar_PanHandle){ pn.setVisible(false); } } } validate(); //非表示ノートチェック boolean noshowsheet_exist = false; for(Note n: notes.values()){ Sheet s = n.getSheet(shtnum); if (!s.getVisible()) noshowsheet_exist = true; } if (noshowsheet_exist) { int res = JOptionPane.showConfirmDialog(this, "非表示設定のシートがあります.それらは印刷スキップされませんが,続けてよろしいですか?","非表示シート",JOptionPane.YES_NO_OPTION); if (res == JOptionPane.NO_OPTION) return; } String ret = JOptionPane.showInputDialog(this,"(2/2) 出力するPDFファイル名を入力してください。"); if (ret == null) return; if (!ret.endsWith(".pdf")){ ret = ret + ".pdf"; } PrintPrintable pdfprint = new PrintPrintable(); if (menutoolbar.getAction("Landscape Mode").isSelected()) { pdfprint.prePrintByInstance(getCanvas(), "A4L", ret); } else { pdfprint.prePrintByInstance(getCanvas(), "A4P", ret); } ArrayList<Sheet> targetSheet = new ArrayList<Sheet>(); for(Note n: notes.values()){ Sheet s = n.getSheet(shtnum); if (s.getVisible()) targetSheet.add(s); s.prepare_for_print(true);//true=before n.prepare_for_print(true); } for(Sheet s: targetSheet){ if (menutoolbar.getAction("Landscape Mode").isSelected()) { //調整なし PBounds b = s.getGlobalBounds(); getCanvas().getCamera().setViewBounds(b); pdfprint.printPageByInstance(); } else { PBounds b = s.getGlobalBounds(); b.setOrigin(b.getX()-20, b.getY()-20); getCanvas().getCamera().setViewBounds(b); pdfprint.printPageByInstance(); } } for(Sheet s: targetSheet){ s.prepare_for_print(false);//false = after } for(Note n: notes.values()){ n.prepare_for_print(false); } pdfprint.postPrintByInstance(); //ハンドルの再表示 for(Object o: getCanvas().getCamera().getAllNodes()){ if (o instanceof PNode){ PNode pn = (PNode)o; if (pn instanceof InsideToolbar_ZoomHandle){ pn.setVisible(true); } else if (pn instanceof InsideToolbar_PanHandle){ pn.setVisible(true); } } } showFadingMessage("PDF出力が完了しました", messageColor, Color.black, 2, 0.9f); NetUtil.openPDF(ret); zoomToBounds(tempAfterLayoutBounds, 1000, "SATN.printToPDF"); NetUtil.openpath("."); } //ファイルのドラッグ&ドロップ @Override public void dropPath(String path, DropTargetDropEvent dtde) { System.out.println(path); if (path.endsWith(".satn")){ loadFromFile(path,99); } if (path.endsWith(".waku")){ loadFrameFromFile(path); } File f = new File(path); if (f.isDirectory()){ // System.out.println("Load Image"); for(int i=1;i<7;i++){ byte[] b = FileReadWriter.readBytesFromFile(path+File.separator+"スライド"+i+".PNG"); MyPImage pimg = new MyPImage(b, false); pimages.put(i,pimg); } showFadingMessage("画像を読み込みました", messageColor, Color.black, 2, 0.9f); } } //画面(Camera)の左上に,ペン番号とシート番号を表示(b==trueのとき) public void showSheetInfoOnCamera(Sheet sheet, boolean b) { // if (sheetVisibleMode[0]==0){ // System.out.println("Tooltip "+sheetVisibleMode[0]); // getCanvas().requestFocus(); if (toolTipPText == null) { toolTipPText = new PText(); toolTipPText.setScale(2f); getCanvas().getCamera().addChild(toolTipPText); } toolTipPText.setText(" "+sheet.getNote().penid+" - "+sheet.num+" "); toolTipPText.setTextPaint(Sheet.numPTColorAry[sheet.num]); toolTipPText.setVisible(b); // } } public void checkSecondaryDisplay(){ ArrayList<Rectangle> dispList = MultiDisplay.getMultiDisplayRectList(); if (dispList.size()>1){ menutoolbar.getAction("Secondary Display").setSelected(true); } } public void showFrameOnSecondaryDisplay(JFrame f) { //thisとは別のディスプレイ(true)に,全画面で表示する(true) MultiDisplay.moveWindow(this, f, true, true); } //追加機能分のメニュー public void addPluginMenuTo(JPopupMenu menu) { for(DefaultPlugin dp: plugins){ dp.addMenu(menu); } } public void setLandscapeMode(boolean b, boolean showMessage, boolean doLayout) { for(Note n: notes.values()){ n.setLandscapeMode(b); } if (showMessage){ if (b) { showFadingMessage("横長モード", messageColor, Color.black, 2, 0.9f); } else { showFadingMessage("縦長モード", messageColor, Color.black, 2, 0.9f); } } if (doLayout){ relayout(1000, "SATN.setSheetVisible"); zoomToBounds(tempAfterLayoutBounds, 1000,"SATN.setSheetVisible"); } } public void applyLandscapeMode(){ setLandscapeMode(menutoolbar.getAction("Landscape Mode").isSelected(), false, false); } public void applyDrawingMode() { for(Note n: notes.values()) n.applyDrawingMode(); } }