/* * Copyright (C) 2010-2013 JPEXS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package com.jpexs.asdec.abc.gui; import com.jpexs.asdec.Main; import com.jpexs.asdec.abc.ABC; import com.jpexs.asdec.abc.avm2.ConvertException; import com.jpexs.asdec.abc.types.ScriptInfo; import com.jpexs.asdec.abc.types.traits.Trait; import com.jpexs.asdec.abc.types.traits.TraitSlotConst; import com.jpexs.asdec.helpers.Highlighting; import com.jpexs.asdec.tags.DoABCTag; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Timer; import java.util.TimerTask; import javax.swing.JScrollPane; import javax.swing.JViewport; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.text.Caret; public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretListener { private List highlights = new ArrayList(); private List traitHighlights = new ArrayList(); private List methodHighlights = new ArrayList(); private List classHighlights = new ArrayList(); private Highlighting currentMethodHighlight; private ABC abc; private ScriptInfo script; public int lastTraitIndex = 0; private boolean ignoreCarret = false; private boolean reset = false; private ABCPanel abcPanel; public void setNoTrait() { abcPanel.detailPanel.showCard(DetailPanel.UNSUPPORTED_TRAIT_CARD); } public void hilightOffset(long offset) { if (currentMethodHighlight == null) { return; } for (Highlighting h2 : highlights) { if ((h2.startPos >= currentMethodHighlight.startPos) && (h2.startPos + h2.len <= currentMethodHighlight.startPos + currentMethodHighlight.len)) { if (h2.offset == offset) { ignoreCarret = true; try { setCaretPosition(h2.startPos); } catch (IllegalArgumentException ie) { } getCaret().setVisible(true); ignoreCarret = false; break; } } } } public void setClassIndex(int classIndex) { this.classIndex = classIndex; } private boolean displayMethod(int pos, int methodIndex) { int bi = abc.findBodyIndex(methodIndex); if (bi == -1) { return false; } abcPanel.detailPanel.showCard(DetailPanel.METHOD_TRAIT_CARD); if (reset || (abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getBodyIndex() != bi)) { abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setBodyIndex(bi, abc); abcPanel.detailPanel.methodTraitPanel.methodBodyParamsPanel.loadFromBody(abc.bodies[bi]); abcPanel.detailPanel.methodTraitPanel.methodInfoPanel.load(abc.bodies[bi].method_info, abc); abcPanel.detailPanel.setEditMode(false); } boolean success = false; for (Highlighting h : highlights) { if ((pos >= h.startPos) && (pos < h.startPos + h.len)) { abcPanel.detailPanel.methodTraitPanel.methodCodePanel.hilighOffset(h.offset); success = true; //return true; } } return success; } public void displayClass(int classIndex) { if (abcPanel.navigator.getClassIndex() != classIndex) { abcPanel.navigator.setClassIndex(classIndex); } } private int classIndex = -1; public void resetEditing() { reset = true; caretUpdate(null); reset = false; } public void caretUpdate(CaretEvent e) { if (ignoreCarret) { return; } getCaret().setVisible(true); int pos = getCaretPosition(); abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setIgnoreCarret(true); try { classIndex = -1; for (Highlighting cm : classHighlights) { if ((pos >= cm.startPos) && (pos < cm.startPos + cm.len)) { classIndex = (int) cm.offset; displayClass(classIndex); break; } } if (classIndex == -1) { setNoTrait(); return; } for (Highlighting tm : methodHighlights) { if ((pos >= tm.startPos) && (pos < tm.startPos + tm.len)) { displayMethod(pos, (int) tm.offset); currentMethodHighlight = tm; for (Highlighting th : traitHighlights) { if ((pos >= th.startPos) && (pos < th.startPos + th.len)) { lastTraitIndex = (int) th.offset; } } return; } } for (Highlighting th : traitHighlights) { if ((pos >= th.startPos) && (pos < th.startPos + th.len)) { lastTraitIndex = (int) th.offset; Trait tr = abc.findTraitByTraitId(classIndex, (int) th.offset); if (tr != null) { if (tr instanceof TraitSlotConst) { abcPanel.detailPanel.slotConstTraitPanel.load((TraitSlotConst) tr, abc); abcPanel.detailPanel.showCard(DetailPanel.SLOT_CONST_TRAIT_CARD); abcPanel.detailPanel.setEditMode(false); return; } } currentMethodHighlight = th; displayMethod(pos, abc.findMethodIdByTraitId(classIndex, (int) th.offset)); return; } } setNoTrait(); } finally { abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setIgnoreCarret(false); } } private class BufferedClass { public String text; public List highlights; public List traitHighlights; public List methodHighlights; public List classHighlights; public BufferedClass(String text, List highlights, List traitHighlights, List methodHighlights, List classHighlights) { this.text = text; this.highlights = highlights; this.traitHighlights = traitHighlights; this.methodHighlights = methodHighlights; this.classHighlights = classHighlights; } } private HashMap bufferedClasses = new HashMap(); public void gotoLastTrait() { gotoTrait(lastTraitIndex); } public void gotoTrait(int traitId) { if (traitId == -1) { setCaretPosition(0); return; } for (Highlighting tc : classHighlights) { if (tc.offset == classIndex) { for (Highlighting th : traitHighlights) { if ((th.startPos > tc.startPos) && (th.startPos + th.len < tc.startPos + tc.len)) { if (th.offset == traitId) { try { ignoreCarret=true; setCaretPosition(th.startPos + th.len - 1); ignoreCarret=false; } catch (IllegalArgumentException iae) { } final int pos = th.startPos; new Timer().schedule(new TimerTask() { public void run() { try { setCaretPosition(pos); } catch (IllegalArgumentException iae) { } } }, 100); return; } } } break; } } setCaretPosition(0); } public DecompiledEditorPane(ABCPanel abcPanel) { setEditable(false); getCaret().setVisible(true); addCaretListener(this); this.abcPanel = abcPanel; } private List abcList; public void clearScriptCache() { bufferedClasses.clear(); } public void setScript(ScriptInfo script, ABC abc, List abcList) { if (script == null) { highlights = new ArrayList(); traitHighlights = new ArrayList(); methodHighlights = new ArrayList(); this.script = null; return; } setText("//Please wait..."); String hilightedCode; if (!bufferedClasses.containsKey(script)) { hilightedCode = script.convert(abcList, abc, false, true); highlights = Highlighting.getInstrHighlights(hilightedCode); traitHighlights = Highlighting.getTraitHighlights(hilightedCode); methodHighlights = Highlighting.getMethodHighlights(hilightedCode); classHighlights = Highlighting.getClassHighlights(hilightedCode); hilightedCode = Highlighting.stripHilights(hilightedCode); bufferedClasses.put(script, new BufferedClass(hilightedCode, highlights, traitHighlights, methodHighlights, classHighlights)); } else { BufferedClass bc = bufferedClasses.get(script); hilightedCode = bc.text; highlights = bc.highlights; traitHighlights = bc.traitHighlights; methodHighlights = bc.methodHighlights; classHighlights = bc.classHighlights; } setText(hilightedCode); this.abc = abc; this.abcList = abcList; this.script = script; } public void reloadClass() { int ci=classIndex; if (bufferedClasses.containsKey(script)) { bufferedClasses.remove(script); } setScript(script, abc, abcList); setNoTrait(); setClassIndex(ci); } public int getClassIndex() { return classIndex; } public void setABC(ABC abc) { this.abc = abc; bufferedClasses.clear(); setText(""); } }