diff --git a/lib/flashdebugger.jar b/lib/flashdebugger.jar index 8e5511090..caff5adf3 100644 Binary files a/lib/flashdebugger.jar and b/lib/flashdebugger.jar differ diff --git a/lib/jsyntaxpane-0.9.5.jar b/lib/jsyntaxpane-0.9.5.jar index 310f86d9a..195c89e1b 100644 Binary files a/lib/jsyntaxpane-0.9.5.jar and b/lib/jsyntaxpane-0.9.5.jar differ diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java index 897951e94..590df4541 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java @@ -281,7 +281,7 @@ public class ScriptPack extends AS3ClassTreeItem { @Override public int hashCode() { int hash = 7; - hash = 79 * hash + Objects.hashCode(abc); + hash = 79 * hash + System.identityHashCode(abc); hash = 79 * hash + scriptIndex; hash = 79 * hash + Objects.hashCode(path); return hash; @@ -296,7 +296,7 @@ public class ScriptPack extends AS3ClassTreeItem { return false; } final ScriptPack other = (ScriptPack) obj; - if (!Objects.equals(abc, other.abc)) { + if (abc != other.abc) { return false; } if (scriptIndex != other.scriptIndex) { @@ -325,59 +325,62 @@ public class ScriptPack extends AS3ClassTreeItem { String txt = decompiled.text; txt = txt.replace("\r", ""); for (int i = 0; i < txt.length(); i++) { + blk: + { + Highlighting cls = Highlighting.searchPos(decompiled.classHilights, i); + /*if (cls == null) { + continue; + }*/ + Highlighting trt = Highlighting.searchPos(decompiled.traitHilights, i); + /*if (trt == null) { + continue; + }*/ + Highlighting method = Highlighting.searchPos(decompiled.methodHilights, i); + if (method == null) { + break blk; + } + Highlighting instr = Highlighting.searchPos(decompiled.instructionHilights, i); + /*if (instr == null) { + continue; + }*/ + int classIndex = cls == null ? -1 : (int) cls.getProperties().index; + int methodIndex = (int) method.getProperties().index; + int bodyIndex = abc.findBodyIndex(methodIndex); + if (bodyIndex == -1) { + break blk; + } + int pos = -1; + if (instr != null) { + long instrOffset = instr.getProperties().offset; + if (trt != null && cls != null) { + int traitIndex = (int) trt.getProperties().index; + + Trait trait = abc.findTraitByTraitId(classIndex, traitIndex); + if (((trait instanceof TraitMethodGetterSetter) && (((TraitMethodGetterSetter) trait).method_info != methodIndex)) + || ((trait instanceof TraitFunction) && (((TraitFunction) trait).method_info != methodIndex))) { + continue; //inner anonymous function - ignore. TODO: make work + } + } + + try { + pos = abc.bodies.get(bodyIndex).getCode().adr2pos(instrOffset); + } catch (ConvertException cex) { + //ignore + } + if (pos == -1) { + break blk; + } + if (!bodyToPosToLine.containsKey(bodyIndex)) { + bodyToPosToLine.put(bodyIndex, new HashMap<>()); + } + bodyToPosToLine.get(bodyIndex).put(pos, line); + } else { + lonelyBody.add(bodyIndex); + } + } if (txt.charAt(i) == '\n') { line++; } - Highlighting cls = Highlighting.searchPos(decompiled.classHilights, i); - /*if (cls == null) { - continue; - }*/ - Highlighting trt = Highlighting.searchPos(decompiled.traitHilights, i); - /*if (trt == null) { - continue; - }*/ - Highlighting method = Highlighting.searchPos(decompiled.methodHilights, i); - if (method == null) { - continue; - } - Highlighting instr = Highlighting.searchPos(decompiled.instructionHilights, i); - /*if (instr == null) { - continue; - }*/ - int classIndex = cls == null ? -1 : (int) cls.getProperties().index; - int methodIndex = (int) method.getProperties().index; - int bodyIndex = abc.findBodyIndex(methodIndex); - if (bodyIndex == -1) { - continue; - } - int pos = -1; - if (instr != null) { - long instrOffset = instr.getProperties().offset; - if (trt != null && cls != null) { - int traitIndex = (int) trt.getProperties().index; - - Trait trait = abc.findTraitByTraitId(classIndex, traitIndex); - if (((trait instanceof TraitMethodGetterSetter) && (((TraitMethodGetterSetter) trait).method_info != methodIndex)) - || ((trait instanceof TraitFunction) && (((TraitFunction) trait).method_info != methodIndex))) { - continue; //inner anonymous function - ignore. TODO: make work - } - } - - try { - pos = abc.bodies.get(bodyIndex).getCode().adr2pos(instrOffset); - } catch (ConvertException cex) { - //ignore - } - if (pos == -1) { - continue; - } - if (!bodyToPosToLine.containsKey(bodyIndex)) { - bodyToPosToLine.put(bodyIndex, new HashMap<>()); - } - bodyToPosToLine.get(bodyIndex).put(pos, line); - } else { - lonelyBody.add(bodyIndex); - } } } catch (InterruptedException ex) { diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/components/BreakPointListener.java b/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/components/BreakPointListener.java new file mode 100644 index 000000000..26c312341 --- /dev/null +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/components/BreakPointListener.java @@ -0,0 +1,10 @@ +package jsyntaxpane.components; + +/** + * + * @author JPEXS + */ +public interface BreakPointListener { + + public void toggled(int line); +} diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/components/LineNumbersBreakpointsRuler.java b/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/components/LineNumbersBreakpointsRuler.java new file mode 100644 index 000000000..126c38661 --- /dev/null +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/components/LineNumbersBreakpointsRuler.java @@ -0,0 +1,57 @@ +/* + * Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jsyntaxpane.components; + +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.JEditorPane; +import javax.swing.text.BadLocationException; +import jsyntaxpane.actions.ActionUtils; + +/** + * + * @author JPEXS + */ +public class LineNumbersBreakpointsRuler extends LineNumbersRuler { + + @Override + public void install(final JEditorPane editor) { + super.install(editor); + removeMouseListener(mouseListener); + mouseListener = new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + Point p = e.getPoint(); + p.x = 0; + int loc = editor.viewToModel(p); + + int currentLine = -1; + try { + currentLine = ActionUtils.getLineNumber(editor, loc) + 1; + } catch (BadLocationException ex) { + //ignore + } + + if (currentLine > -1 && (editor instanceof BreakPointListener)) { + ((BreakPointListener) editor).toggled(currentLine); + } + } + + }; + addMouseListener(mouseListener); + } + +} diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/components/LineNumbersRuler.java b/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/components/LineNumbersRuler.java index e7ff36525..78db74374 100644 --- a/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/components/LineNumbersRuler.java +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/components/LineNumbersRuler.java @@ -47,286 +47,284 @@ import jsyntaxpane.util.Configuration; /** * This class will display line numbers for a related text component. The text - * component must use the same line height for each line. + * component must use the same line height for each line. * - * This class was designed to be used as a component added to the row header - * of a JScrollPane. + * This class was designed to be used as a component added to the row header of + * a JScrollPane. * - * Original code from http://tips4java.wordpress.com/2009/05/23/text-component-line-number/ + * Original code from + * http://tips4java.wordpress.com/2009/05/23/text-component-line-number/ * * @author Rob Camick * * Revised for jsyntaxpane - * + * * @author Ayman Al-Sairafi */ public class LineNumbersRuler extends JPanel - implements CaretListener, DocumentListener, PropertyChangeListener, SyntaxComponent { + implements CaretListener, DocumentListener, PropertyChangeListener, SyntaxComponent { - public static final String PROPERTY_BACKGROUND = "LineNumbers.Background"; - public static final String PROPERTY_FOREGROUND = "LineNumbers.Foreground"; - public static final String PROPERTY_CURRENT_BACK = "LineNumbers.CurrentBack"; - public static final String PROPERTY_LEFT_MARGIN = "LineNumbers.LeftMargin"; - public static final String PROPERTY_RIGHT_MARGIN = "LineNumbers.RightMargin"; - public static final String PROPERTY_Y_OFFSET = "LineNumbers.YOFFset"; - public static final int DEFAULT_R_MARGIN = 5; - public static final int DEFAULT_L_MARGIN = 5; - private Status status; - private final static int HEIGHT = Integer.MAX_VALUE - 1000000; - // Text component this TextTextLineNumber component is in sync with - private JEditorPane editor; - private int minimumDisplayDigits = 2; - // Keep history information to reduce the number of times the component - // needs to be repainted - private int lastDigits; - private int lastHeight; - private int lastLine; - private MouseListener mouseListener = null; - // The formatting to use for displaying numbers. Use in String.format(numbersFormat, line) - private String numbersFormat = "%3d"; + public static final String PROPERTY_BACKGROUND = "LineNumbers.Background"; + public static final String PROPERTY_FOREGROUND = "LineNumbers.Foreground"; + public static final String PROPERTY_CURRENT_BACK = "LineNumbers.CurrentBack"; + public static final String PROPERTY_LEFT_MARGIN = "LineNumbers.LeftMargin"; + public static final String PROPERTY_RIGHT_MARGIN = "LineNumbers.RightMargin"; + public static final String PROPERTY_Y_OFFSET = "LineNumbers.YOFFset"; + public static final int DEFAULT_R_MARGIN = 5; + public static final int DEFAULT_L_MARGIN = 5; + private Status status; + private final static int HEIGHT = Integer.MAX_VALUE - 1000000; + // Text component this TextTextLineNumber component is in sync with + private JEditorPane editor; + private int minimumDisplayDigits = 2; + // Keep history information to reduce the number of times the component + // needs to be repainted + private int lastDigits; + private int lastHeight; + private int lastLine; + //JPEXS: private lowered to protected to allow replacing mouseListener + protected MouseListener mouseListener = null; + // The formatting to use for displaying numbers. Use in String.format(numbersFormat, line) + private String numbersFormat = "%3d"; - private Color currentLineColor; + private Color currentLineColor; - /** - * Get the JscrollPane that contains this EditorPane, or null if no - * JScrollPane is the parent of this editor - * @param editorPane - * @return - */ - public JScrollPane getScrollPane(JTextComponent editorPane) { - Container p = editorPane.getParent(); - while (p != null) { - if (p instanceof JScrollPane) { - return (JScrollPane) p; - } - p = p.getParent(); - } - return null; - } + /** + * Get the JscrollPane that contains this EditorPane, or null if no + * JScrollPane is the parent of this editor + * + * @param editorPane + * @return + */ + public JScrollPane getScrollPane(JTextComponent editorPane) { + Container p = editorPane.getParent(); + while (p != null) { + if (p instanceof JScrollPane) { + return (JScrollPane) p; + } + p = p.getParent(); + } + return null; + } - @Override - public void config(Configuration config) { - int right = config.getInteger(PROPERTY_RIGHT_MARGIN, DEFAULT_R_MARGIN); - int left = config.getInteger(PROPERTY_LEFT_MARGIN, DEFAULT_L_MARGIN); - Color foreground = config.getColor(PROPERTY_FOREGROUND, Color.BLACK); - setForeground(foreground); - Color back = config.getColor(PROPERTY_BACKGROUND, Color.WHITE); - setBackground(back); - setBorder(BorderFactory.createEmptyBorder(0, left, 0, right)); - currentLineColor = config.getColor(PROPERTY_CURRENT_BACK, back); - } + @Override + public void config(Configuration config) { + int right = config.getInteger(PROPERTY_RIGHT_MARGIN, DEFAULT_R_MARGIN); + int left = config.getInteger(PROPERTY_LEFT_MARGIN, DEFAULT_L_MARGIN); + Color foreground = config.getColor(PROPERTY_FOREGROUND, Color.BLACK); + setForeground(foreground); + Color back = config.getColor(PROPERTY_BACKGROUND, Color.WHITE); + setBackground(back); + setBorder(BorderFactory.createEmptyBorder(0, left, 0, right)); + currentLineColor = config.getColor(PROPERTY_CURRENT_BACK, back); + } - @Override - public void install(final JEditorPane editor) { - this.editor = editor; + @Override + public void install(final JEditorPane editor) { + this.editor = editor; - setFont(editor.getFont()); + setFont(editor.getFont()); - // setMinimumDisplayDigits(3); + // setMinimumDisplayDigits(3); + editor.getDocument().addDocumentListener(this); + editor.addCaretListener(this); + editor.addPropertyChangeListener(this); + JScrollPane sp = getScrollPane(editor); + sp.setRowHeaderView(this); + mouseListener = new MouseAdapter() { - editor.getDocument().addDocumentListener(this); - editor.addCaretListener(this); - editor.addPropertyChangeListener(this); - JScrollPane sp = getScrollPane(editor); - sp.setRowHeaderView(this); - mouseListener = new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + GotoLineDialog.showForEditor(editor); + } + }; + addMouseListener(mouseListener); + status = Status.INSTALLING; + } - @Override - public void mouseClicked(MouseEvent e) { - GotoLineDialog.showForEditor(editor); - } - }; - addMouseListener(mouseListener); - status = Status.INSTALLING; - } + @Override + public void deinstall(JEditorPane editor) { + removeMouseListener(mouseListener); + status = Status.DEINSTALLING; + editor.getDocument().removeDocumentListener(this); + editor.removeCaretListener(this); + editor.removePropertyChangeListener(this); + JScrollPane sp = getScrollPane(editor); + if (sp != null) { + sp.setRowHeaderView(null); + } + } - @Override - public void deinstall(JEditorPane editor) { - removeMouseListener(mouseListener); - status = Status.DEINSTALLING; - this.editor.getDocument().removeDocumentListener(this); - editor.removeCaretListener(this); - editor.removePropertyChangeListener(this); - JScrollPane sp = getScrollPane(editor); - if (sp != null) { - editor.getDocument().removeDocumentListener(this); - sp.setRowHeaderView(null); - } - } + /** + * Gets the minimum display digits + * + * @return the minimum display digits + */ + public int getMinimumDisplayDigits() { + return minimumDisplayDigits; + } - /** - * Gets the minimum display digits - * - * @return the minimum display digits - */ - public int getMinimumDisplayDigits() { - return minimumDisplayDigits; - } + /** + * Specify the minimum number of digits used to calculate the preferred + * width of the component. Default is 3. + * + * @param minimumDisplayDigits the number digits used in the preferred width + * calculation + */ + public void setMinimumDisplayDigits(int minimumDisplayDigits) { + this.minimumDisplayDigits = minimumDisplayDigits; + setPreferredWidth(); + } - /** - * Specify the minimum number of digits used to calculate the preferred - * width of the component. Default is 3. - * - * @param minimumDisplayDigits the number digits used in the preferred - * width calculation - */ - public void setMinimumDisplayDigits(int minimumDisplayDigits) { - this.minimumDisplayDigits = minimumDisplayDigits; - setPreferredWidth(); - } + /** + * Calculate the width needed to display the maximum line number + */ + private void setPreferredWidth() { + int lines = ActionUtils.getLineCount(editor); + int digits = Math.max(String.valueOf(lines).length(), minimumDisplayDigits); - /** - * Calculate the width needed to display the maximum line number - */ - private void setPreferredWidth() { - int lines = ActionUtils.getLineCount(editor); - int digits = Math.max(String.valueOf(lines).length(), minimumDisplayDigits); + // Update sizes when number of digits in the line number changes + if (lastDigits != digits) { + lastDigits = digits; + numbersFormat = "%" + digits + "d"; + FontMetrics fontMetrics = getFontMetrics(getFont()); + int width = fontMetrics.charWidth('0') * digits; + Insets insets = getInsets(); + int preferredWidth = insets.left + insets.right + width; - // Update sizes when number of digits in the line number changes + Dimension d = getPreferredSize(); + d.setSize(preferredWidth, HEIGHT); + setPreferredSize(d); + setSize(d); - if (lastDigits != digits) { - lastDigits = digits; - numbersFormat = "%" + digits + "d"; - FontMetrics fontMetrics = getFontMetrics(getFont()); - int width = fontMetrics.charWidth('0') * digits; - Insets insets = getInsets(); - int preferredWidth = insets.left + insets.right + width; + } + } - Dimension d = getPreferredSize(); - d.setSize(preferredWidth, HEIGHT); - setPreferredSize(d); - setSize(d); + /** + * Draw the line numbers + */ + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); - } - } + FontMetrics fontMetrics = editor.getFontMetrics(editor.getFont()); + Insets insets = getInsets(); + int currentLine = -1; + try { + // get current line, and add one as we start from 1 for the display + currentLine = ActionUtils.getLineNumber(editor, editor.getCaretPosition()) + 1; + } catch (BadLocationException ex) { + // this wont happen, even if it does, we can ignore it and we will not have + // a current line to worry about... + } - /** - * Draw the line numbers - */ - @Override - public void paintComponent(Graphics g) { - super.paintComponent(g); + int lh = fontMetrics.getHeight(); + int maxLines = ActionUtils.getLineCount(editor); + SyntaxView.setRenderingHits((Graphics2D) g); - FontMetrics fontMetrics = editor.getFontMetrics(editor.getFont()); - Insets insets = getInsets(); - int currentLine = -1; - try { - // get current line, and add one as we start from 1 for the display - currentLine = ActionUtils.getLineNumber(editor, editor.getCaretPosition()) + 1; - } catch (BadLocationException ex) { - // this wont happen, even if it does, we can ignore it and we will not have - // a current line to worry about... - } - - int lh = fontMetrics.getHeight(); - int maxLines = ActionUtils.getLineCount(editor); - SyntaxView.setRenderingHits((Graphics2D) g); - - Rectangle bounds = g.getClipBounds(); - int minY = bounds.y; - int maxY = minY + bounds.height; - for (int line = 1; line <= maxLines; line++) { - int y = line * lh; - if (y < minY) { - continue; - } - if (y - lh > maxY) { - break; - } - String lineNumber = String.format(numbersFormat, line); - if (line == currentLine) { - g.setColor(currentLineColor); - g.fillRect(0, y - lh + fontMetrics.getDescent() - 1, getWidth(), lh); - g.setColor(getForeground()); - g.drawString(lineNumber, insets.left, y); - } else { - g.drawString(lineNumber, insets.left, y); - } - } - } + Rectangle bounds = g.getClipBounds(); + int minY = bounds.y; + int maxY = minY + bounds.height; + for (int line = 1; line <= maxLines; line++) { + int y = line * lh; + if (y < minY) { + continue; + } + if (y - lh > maxY) { + break; + } + String lineNumber = String.format(numbersFormat, line); + if (line == currentLine) { + g.setColor(currentLineColor); + g.fillRect(0, y - lh + fontMetrics.getDescent() - 1, getWidth(), lh); + g.setColor(getForeground()); + g.drawString(lineNumber, insets.left, y); + } else { + g.drawString(lineNumber, insets.left, y); + } + } + } // // Implement CaretListener interface // - @Override - public void caretUpdate(CaretEvent e) { - // Get the line the caret is positioned on + @Override + public void caretUpdate(CaretEvent e) { + // Get the line the caret is positioned on - int caretPosition = editor.getCaretPosition(); - Element root = editor.getDocument().getDefaultRootElement(); - int currentLine = root.getElementIndex(caretPosition); + int caretPosition = editor.getCaretPosition(); + Element root = editor.getDocument().getDefaultRootElement(); + int currentLine = root.getElementIndex(caretPosition); - // Need to repaint so the correct line number can be highlighted - - if (lastLine != currentLine) { - repaint(); - lastLine = currentLine; - } - } + // Need to repaint so the correct line number can be highlighted + if (lastLine != currentLine) { + repaint(); + lastLine = currentLine; + } + } // // Implement DocumentListener interface // - @Override - public void changedUpdate(DocumentEvent e) { - documentChanged(); - } + @Override + public void changedUpdate(DocumentEvent e) { + documentChanged(); + } - @Override - public void insertUpdate(DocumentEvent e) { - documentChanged(); - } + @Override + public void insertUpdate(DocumentEvent e) { + documentChanged(); + } - @Override - public void removeUpdate(DocumentEvent e) { - documentChanged(); - } + @Override + public void removeUpdate(DocumentEvent e) { + documentChanged(); + } - /* - * A document change may affect the number of displayed lines of text. - * Therefore the lines numbers will also change. - */ - private void documentChanged() { - // Preferred size of the component has not been updated at the time - // the DocumentEvent is fired + /* + * A document change may affect the number of displayed lines of text. + * Therefore the lines numbers will also change. + */ + private void documentChanged() { + // Preferred size of the component has not been updated at the time + // the DocumentEvent is fired - SwingUtilities.invokeLater(new Runnable() { + SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - int preferredHeight = editor.getPreferredSize().height; + @Override + public void run() { + int preferredHeight = editor.getPreferredSize().height; - // Document change has caused a change in the number of lines. - // Repaint to reflect the new line numbers + // Document change has caused a change in the number of lines. + // Repaint to reflect the new line numbers + if (lastHeight != preferredHeight) { + setPreferredWidth(); + repaint(); + lastHeight = preferredHeight; + } + } + }); + } - if (lastHeight != preferredHeight) { - setPreferredWidth(); - repaint(); - lastHeight = preferredHeight; - } - } - }); - } - - /** - * Implement PropertyChangeListener interface - */ - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals("document")) { - if (evt.getOldValue() instanceof SyntaxDocument) { - SyntaxDocument syntaxDocument = (SyntaxDocument) evt.getOldValue(); - syntaxDocument.removeDocumentListener(this); - } - if (evt.getNewValue() instanceof SyntaxDocument && status.equals(Status.INSTALLING)) { - SyntaxDocument syntaxDocument = (SyntaxDocument) evt.getNewValue(); - syntaxDocument.addDocumentListener(this); - setPreferredWidth(); - repaint(); - } - } else if (evt.getNewValue() instanceof Font) { - setPreferredWidth(); - repaint(); - } - } + /** + * Implement PropertyChangeListener interface + */ + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("document")) { + if (evt.getOldValue() instanceof SyntaxDocument) { + SyntaxDocument syntaxDocument = (SyntaxDocument) evt.getOldValue(); + syntaxDocument.removeDocumentListener(this); + } + if (evt.getNewValue() instanceof SyntaxDocument && status.equals(Status.INSTALLING)) { + SyntaxDocument syntaxDocument = (SyntaxDocument) evt.getNewValue(); + syntaxDocument.addDocumentListener(this); + setPreferredWidth(); + repaint(); + } + } else if (evt.getNewValue() instanceof Font) { + setPreferredWidth(); + repaint(); + } + } } diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_de.properties b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_de.properties index df01d1bab..99c08bf48 100644 --- a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_de.properties +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_de.properties @@ -1,24 +1,24 @@ DefaultAction.copy-to-clipboard.MenuText = Kopieren DefaultAction.cut-to-clipboard.MenuText = Ausschneiden -DefaultAction.paste-from-clipboard.MenuText = Einf\u00FCgen -DefaultAction.select-all.MenuText = Alles ausw\u00E4hlen +DefaultAction.paste-from-clipboard.MenuText = Einf\u00fcgen +DefaultAction.select-all.MenuText = Alles ausw\u00e4hlen Action.find.MenuText = Suchen Action.find.ToolTip = Suche anzeigen und Dialog ersetzen -Action.find-next.MenuText = N\u00E4chstes suchen +Action.find-next.MenuText = N\u00e4chstes suchen Action.find-next.ToolTip = Letzte Suche wiederholen Action.goto-line.MenuText = Zu Linienmummer gehen Action.goto-line.ToolTip = Zu Linienmummer gehen Action.indent.MenuText = Einzug Action.unindent.MenuText = Auszug -Action.undo.MenuText = R\u00FCchg\u00E4ngig +Action.undo.MenuText = R\u00fcchg\u00e4ngig Action.redo.MenuText = Wiederholen -Action.delete-lines.MenuText = Linie(n) L\u00F6schen +Action.delete-lines.MenuText = Linie(n) L\u00f6schen Action.dup-lines-up.MenuText = Obere Linie dublizieren Action.dup-lines-down.MenuText = Untere Linie dublizieren Action.toggle-lines.MenuText = Liniennummern umshalten -Action.show-abbs.MenuText = Abk\u00FCrzungen anzeigen -Action.show-abbs.ToolTip = Abk\u00FCrzungen anzeigen +Action.show-abbs.MenuText = Abk\u00fcrzungen anzeigen +Action.show-abbs.ToolTip = Abk\u00fcrzungen anzeigen Action.complete-word.MenuText = Wort komplettieren Action.jump-to-pair.MenuText = Gehe zum Paar Action.toggle-comments.MenuText = Kommentare umschalten diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_nl.properties b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_nl.properties index cb9363c74..48c9fd984 100644 --- a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_nl.properties +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_nl.properties @@ -1,4 +1,4 @@ -DefaultAction.copy-to-clipboard.MenuText = Kopi\u00EBren +DefaultAction.copy-to-clipboard.MenuText = Kopi\u00ebren DefaultAction.cut-to-clipboard.MenuText = Snijden DefaultAction.paste-from-clipboard.MenuText = Plakken DefaultAction.select-all.MenuText = Alles selecteren diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_pt_BR.properties b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_pt_BR.properties index 93b07e592..bb223e85e 100644 --- a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_pt_BR.properties +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_pt_BR.properties @@ -4,11 +4,11 @@ DefaultAction.paste-from-clipboard.MenuText = Colar DefaultAction.select-all.MenuText = Escolher tudo Action.find.MenuText = Procurar -Action.find.ToolTip = Mostrar procura e trocar diálogo +Action.find.ToolTip = Mostrar procura e trocar di\u00c3\u00a1logo Action.find-next.MenuText = Procurar proximo -Action.find-next.ToolTip = Repetir última procura -Action.goto-line.MenuText = Ir para a linha número -Action.goto-line.ToolTip = Ir para a linha número +Action.find-next.ToolTip = Repetir \u00c3\u00baltima procura +Action.goto-line.MenuText = Ir para a linha n\u00c3\u00bamero +Action.goto-line.ToolTip = Ir para a linha n\u00c3\u00bamero Action.indent.MenuText = Indentar Action.unindent.MenuText = Des-identar Action.undo.MenuText = Voltar a tr\u00e1s diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_ru.properties b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_ru.properties index b1e554666..c95eb16fb 100644 --- a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_ru.properties +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_ru.properties @@ -4,24 +4,24 @@ DefaultAction.paste-from-clipboard.MenuText = \u0412\u0441\u0442\u0430\u0432\u04 DefaultAction.select-all.MenuText = \u0412\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u0432\u0441\u0451 Action.find.MenuText = \u041d\u0430\u0439\u0442\u0438 -Action.find.ToolTip = \u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0434\u0438\u0430\u043B\u043E\u0433\u043E\u0432\u043E\u0435 \u043E\u043A\u043D\u043E \u041D\u0430\u0439\u0442\u0438 \u0438 \u0437\u0430\u043C\u0435\u043D\u0438\u0442\u044C +Action.find.ToolTip = \u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0435 \u043e\u043a\u043d\u043e \u041d\u0430\u0439\u0442\u0438 \u0438 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c Action.find-next.MenuText = \u0418\u0441\u043a\u0430\u0442\u044c \u0434\u0430\u043b\u0435\u0435 Action.find-next.ToolTip = \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u043f\u043e\u0438\u0441\u043a -Action.goto-line.MenuText = \u041F\u0435\u0440\u0435\u0439\u0442\u0438 \u043A \u0441\u0442\u0440\u043E\u043A\u0435 +Action.goto-line.MenuText = \u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u0441\u0442\u0440\u043e\u043a\u0435 Action.goto-line.ToolTip = \u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0443 \u0441 \u043d\u043e\u043c\u0435\u0440\u043e\u043c Action.indent.MenuText = \u041e\u0442\u0441\u0442\u0443\u043f\u0438\u0442\u044c Action.unindent.MenuText = \u0423\u0431\u0440\u0430\u0442\u044c \u043e\u0442\u0441\u0442\u0443\u043f -Action.undo.MenuText = \u041E\u0442\u043C\u0435\u043D\u0438\u0442\u044C -Action.redo.MenuText = \u0412\u0435\u0440\u043D\u0443\u0442\u044C -Action.delete-lines.MenuText = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443(\u0441\u0442\u0440\u043E\u043A\u0438) +Action.undo.MenuText = \u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c +Action.redo.MenuText = \u0412\u0435\u0440\u043d\u0443\u0442\u044c +Action.delete-lines.MenuText = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443(\u0441\u0442\u0440\u043e\u043a\u0438) Action.dup-lines-up.MenuText = \u0414\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0438 \u0432\u044b\u0448\u0435 Action.dup-lines-down.MenuText = \u0414\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0438 \u043d\u0438\u0436\u0435 -Action.toggle-lines.MenuText = \u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u044e \u0441\u0442\u0440\u043e\u043a -Action.show-abbs.MenuText = \u041F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f -Action.show-abbs.ToolTip = \u041F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f +Action.toggle-lines.MenuText = \u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u044e \u0441\u0442\u0440\u043e\u043a +Action.show-abbs.MenuText = \u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f +Action.show-abbs.ToolTip = \u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f Action.complete-word.MenuText = \u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0441\u043b\u043e\u0432\u043e Action.jump-to-pair.MenuText = \u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u043f\u0430\u0440\u0435 -Action.toggle-comments.MenuText = \u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 +Action.toggle-comments.MenuText = \u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 # !!!! FFDec translators - please do not edit anything below this line !!! #========================================================================== diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_uk.properties b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_uk.properties index fecdc779d..d672851a3 100644 --- a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_uk.properties +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/defaultsyntaxkit/config_uk.properties @@ -1,27 +1,27 @@ -DefaultAction.copy-to-clipboard.MenuText = \u041A\u043E\u043F\u0456\u044E\u0432\u0430\u0442\u0438 +DefaultAction.copy-to-clipboard.MenuText = \u041a\u043e\u043f\u0456\u044e\u0432\u0430\u0442\u0438 DefaultAction.cut-to-clipboard.MenuText = \u0412\u0438\u0440\u0456\u0437\u0430\u0442\u0438 DefaultAction.paste-from-clipboard.MenuText = \u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 -DefaultAction.select-all.MenuText = \u0412\u0438\u0434\u0456\u043B\u0438\u0442\u0438 \u0432\u0441\u0435 +DefaultAction.select-all.MenuText = \u0412\u0438\u0434\u0456\u043b\u0438\u0442\u0438 \u0432\u0441\u0435 -Action.find.MenuText = \u0417\u043D\u0430\u0439\u0442\u0438 -Action.find.ToolTip = \u041F\u043E\u043A\u0430\u0437\u0430\u0442\u0438 \u0432\u0456\u043A\u043D\u043E \u0434\u0456\u0430\u043B\u043E\u0433\u0443 \u0417\u043D\u0430\u0439\u0442\u0438 \u0456 \u0437\u0430\u043C\u0456\u043D\u0438\u0442\u0438 -Action.find-next.MenuText = \u0428\u0443\u043A\u0430\u0442\u0438 \u0434\u0430\u043B\u0456 -Action.find-next.ToolTip = \u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0438 \u043E\u0441\u0442\u0430\u043D\u043D\u0456\u0439 \u043F\u043E\u0448\u0443\u043A -Action.goto-line.MenuText = \u041F\u0435\u0440\u0435\u0439\u0442\u0438 \u0434\u043E \u0440\u044F\u0434\u043A\u0430 -Action.goto-line.ToolTip = \u041F\u0435\u0440\u0435\u0439\u0442\u0438 \u0434\u043E \u0440\u044F\u0434\u043A\u0430 \u0437\u0430 \u043D\u043E\u043C\u0435\u0440\u043E\u043C -Action.indent.MenuText = \u0417\u0440\u043E\u0431\u0438\u0442\u0438 \u0432\u0456\u0434\u0441\u0442\u0443\u043F -Action.unindent.MenuText = \u041F\u0440\u0438\u0431\u0440\u0430\u0442\u0438 \u0432\u0456\u0434\u0441\u0442\u0443\u043F -Action.undo.MenuText = \u0421\u043A\u0430\u0441\u0443\u0432\u0430\u0442\u0438 -Action.redo.MenuText = \u041F\u043E\u0432\u0435\u0440\u043D\u0443\u0442\u0438 -Action.delete-lines.MenuText = \u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438 \u0440\u044F\u0434\u043E\u043A(\u0440\u044F\u0434\u043A\u0438) -Action.dup-lines-up.MenuText = \u0414\u0443\u0431\u043B\u044E\u0432\u0430\u0442\u0438 \u0440\u044F\u0434\u043A\u0438 \u0432\u0438\u0449\u0435 -Action.dup-lines-down.MenuText = \u0414\u0443\u0431\u043B\u044E\u0432\u0430\u0442\u0438 \u0440\u044F\u0434\u043A\u0438 \u043D\u0438\u0436\u0447\u0435 -Action.toggle-lines.MenuText = \u0423\u0432\u0456\u043C\u043A\u043D\u0443\u0442\u0438 \u043D\u0443\u043C\u0435\u0440\u0430\u0446\u0456\u044E \u0440\u044F\u0434\u043A\u0456\u0432 -Action.show-abbs.MenuText = \u041F\u043E\u043A\u0430\u0437\u0443\u0432\u0430\u0442\u0438 \u0441\u043A\u043E\u0440\u043E\u0447\u0435\u043D\u043D\u044F -Action.show-abbs.ToolTip = \u041F\u043E\u043A\u0430\u0437\u0443\u0432\u0430\u0442\u0438 \u0441\u043A\u043E\u0440\u043E\u0447\u0435\u043D\u043D\u044F -Action.complete-word.MenuText = \u0414\u043E\u043F\u043E\u0432\u043D\u0438\u0442\u0438 \u0441\u043B\u043E\u0432\u043E -Action.jump-to-pair.MenuText = \u041F\u0435\u0440\u0435\u0439\u0442\u0438 \u0434\u043E \u043F\u0430\u0440\u0438 -Action.toggle-comments.MenuText = \u0423\u0432\u0456\u043C\u043A\u043D\u0443\u0442\u0438 \u043A\u043E\u043C\u0435\u043D\u0442\u0430\u0440\u0456 +Action.find.MenuText = \u0417\u043d\u0430\u0439\u0442\u0438 +Action.find.ToolTip = \u041f\u043e\u043a\u0430\u0437\u0430\u0442\u0438 \u0432\u0456\u043a\u043d\u043e \u0434\u0456\u0430\u043b\u043e\u0433\u0443 \u0417\u043d\u0430\u0439\u0442\u0438 \u0456 \u0437\u0430\u043c\u0456\u043d\u0438\u0442\u0438 +Action.find-next.MenuText = \u0428\u0443\u043a\u0430\u0442\u0438 \u0434\u0430\u043b\u0456 +Action.find-next.ToolTip = \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0438 \u043e\u0441\u0442\u0430\u043d\u043d\u0456\u0439 \u043f\u043e\u0448\u0443\u043a +Action.goto-line.MenuText = \u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u0434\u043e \u0440\u044f\u0434\u043a\u0430 +Action.goto-line.ToolTip = \u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u0434\u043e \u0440\u044f\u0434\u043a\u0430 \u0437\u0430 \u043d\u043e\u043c\u0435\u0440\u043e\u043c +Action.indent.MenuText = \u0417\u0440\u043e\u0431\u0438\u0442\u0438 \u0432\u0456\u0434\u0441\u0442\u0443\u043f +Action.unindent.MenuText = \u041f\u0440\u0438\u0431\u0440\u0430\u0442\u0438 \u0432\u0456\u0434\u0441\u0442\u0443\u043f +Action.undo.MenuText = \u0421\u043a\u0430\u0441\u0443\u0432\u0430\u0442\u0438 +Action.redo.MenuText = \u041f\u043e\u0432\u0435\u0440\u043d\u0443\u0442\u0438 +Action.delete-lines.MenuText = \u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u0440\u044f\u0434\u043e\u043a(\u0440\u044f\u0434\u043a\u0438) +Action.dup-lines-up.MenuText = \u0414\u0443\u0431\u043b\u044e\u0432\u0430\u0442\u0438 \u0440\u044f\u0434\u043a\u0438 \u0432\u0438\u0449\u0435 +Action.dup-lines-down.MenuText = \u0414\u0443\u0431\u043b\u044e\u0432\u0430\u0442\u0438 \u0440\u044f\u0434\u043a\u0438 \u043d\u0438\u0436\u0447\u0435 +Action.toggle-lines.MenuText = \u0423\u0432\u0456\u043c\u043a\u043d\u0443\u0442\u0438 \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0456\u044e \u0440\u044f\u0434\u043a\u0456\u0432 +Action.show-abbs.MenuText = \u041f\u043e\u043a\u0430\u0437\u0443\u0432\u0430\u0442\u0438 \u0441\u043a\u043e\u0440\u043e\u0447\u0435\u043d\u043d\u044f +Action.show-abbs.ToolTip = \u041f\u043e\u043a\u0430\u0437\u0443\u0432\u0430\u0442\u0438 \u0441\u043a\u043e\u0440\u043e\u0447\u0435\u043d\u043d\u044f +Action.complete-word.MenuText = \u0414\u043e\u043f\u043e\u0432\u043d\u0438\u0442\u0438 \u0441\u043b\u043e\u0432\u043e +Action.jump-to-pair.MenuText = \u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u0434\u043e \u043f\u0430\u0440\u0438 +Action.toggle-comments.MenuText = \u0423\u0432\u0456\u043c\u043a\u043d\u0443\u0442\u0438 \u043a\u043e\u043c\u0435\u043d\u0442\u0430\u0440\u0456 # !!!! FFDec translators - please do not edit anything below this line !!! #========================================================================== diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/syntaxkits/actionscriptsyntaxkit/config.properties b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/syntaxkits/actionscriptsyntaxkit/config.properties index 9b9b362dd..51fb2995e 100644 --- a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/syntaxkits/actionscriptsyntaxkit/config.properties +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/META-INF/services/jsyntaxpane/syntaxkits/actionscriptsyntaxkit/config.properties @@ -2,6 +2,8 @@ # ActionScript # +Components = jsyntaxpane.components.PairsMarker, jsyntaxpane.components.LineNumbersBreakpointsRuler + Action.indent.WordRegex=\\w+|\\/(\\*)+ Action.parenthesis = jsyntaxpane.actions.PairAction, typed ( Action.brackets = jsyntaxpane.actions.PairAction, typed [ diff --git a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java index 11bce10e7..21c11ac52 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java +++ b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java @@ -21,19 +21,23 @@ import com.jpexs.debugger.flash.DebugMessageListener; import com.jpexs.debugger.flash.Debugger; import com.jpexs.debugger.flash.DebuggerCommands; import com.jpexs.debugger.flash.DebuggerConnection; -import com.jpexs.debugger.flash.InDebuggerMessage; import com.jpexs.debugger.flash.messages.in.InAskBreakpoints; import com.jpexs.debugger.flash.messages.in.InBreakAt; import com.jpexs.debugger.flash.messages.in.InContinue; import com.jpexs.debugger.flash.messages.in.InNumScript; import com.jpexs.debugger.flash.messages.in.InScript; +import com.jpexs.debugger.flash.messages.in.InSetBreakpoint; import com.jpexs.debugger.flash.messages.in.InSwfInfo; import com.jpexs.decompiler.flash.abc.ClassPath; +import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.graph.DottedChain; +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import java.util.logging.ConsoleHandler; import java.util.logging.Level; import java.util.logging.Logger; @@ -48,6 +52,15 @@ public class DebuggerHandler implements DebugConnectionListener { private DebuggerCommands commands = null; private List swfs = new ArrayList<>(); private boolean paused = true; + private Map modulePaths = new HashMap<>(); + private Map classToModule = new HashMap<>(); + + public int moduleIdOf(ScriptPack pack) { + if (classToModule.containsKey(pack.getClassPath())) { + return classToModule.get(pack.getClassPath()); + } + return -1; + } public synchronized boolean isPaused() { return paused; @@ -57,11 +70,22 @@ public class DebuggerHandler implements DebugConnectionListener { return swfs; } + public void disconnect() { + connected = false; + if (commands != null) { + commands.disconnect(); + } + commands = null; + } + public boolean isConnected() { return connected; } - public DebuggerCommands getCommands() { + public DebuggerCommands getCommands() throws IOException { + if (!isConnected() || commands == null) { + throw new IOException("Not connected"); + } return commands; } @@ -84,66 +108,89 @@ public class DebuggerHandler implements DebugConnectionListener { //rootLog.getHandlers()[0].setLevel(level); commands = new DebuggerCommands(con); - commands.stopWarning(); - commands.setStopOnFault(); - commands.setEnumerateOverride(); - commands.setNotifyFailure(); - commands.setInvokeSetters(); - commands.setSwfLoadNotify(); - commands.setGetterTimeout(1500); - commands.setSetterTimeout(5000); - commands.squelch(true); - swfs = commands.getSwfInfo(1); - int numScript = con.getMessage(InNumScript.class).num; - final Map moduleNames = new HashMap<>(); - for (int i = 0; i < numScript; i++) { - InScript sc = con.getMessage(InScript.class); - System.out.println("" + sc.module + ":" + sc.name); - moduleNames.put(sc.module, sc.name); + try { + commands.stopWarning(); + commands.setStopOnFault(); + commands.setEnumerateOverride(); + commands.setNotifyFailure(); + commands.setInvokeSetters(); + commands.setSwfLoadNotify(); + commands.setGetterTimeout(1500); + commands.setSetterTimeout(5000); + commands.squelch(true); + swfs = commands.getSwfInfo(1); + + Map moduleNames = new HashMap<>(); + + modulePaths = new HashMap<>(); + classToModule = new HashMap<>(); + + int numScript = con.getMessage(InNumScript.class).num; + for (int i = 0; i < numScript; i++) { + InScript sc = con.getMessage(InScript.class); + moduleNames.put(sc.module, sc.name); + } + + for (int mname : moduleNames.keySet()) { + String name = moduleNames.get(mname); + String[] parts = name.split(";"); + + if (parts.length == 3) { + String clsName = parts[2].replace(".as", ""); + String pkg = parts[1].replace("/", "\\").replace("\\", "."); + ClassPath cp = new ClassPath(DottedChain.parse(pkg), clsName); + modulePaths.put(mname, cp); + classToModule.put(cp, mname); + } + } + + con.getMessage(InSetBreakpoint.class); + con.getMessage(InAskBreakpoints.class); + con.addMessageListener(new DebugMessageListener() { + + @Override + public void message(InContinue msg) { + synchronized (DebuggerHandler.this) { + paused = false; + } + Main.getMainFrame().getPanel().updateMenu(); + } + }); + con.addMessageListener(new DebugMessageListener() { + + @Override + public void message(InBreakAt message) { + synchronized (DebuggerHandler.this) { + paused = true; + } + Main.getMainFrame().getPanel().updateMenu(); + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "break at {0}:{1}", new Object[]{moduleNames.get(message.file), message.line}); + if (!modulePaths.containsKey(message.file)) { + return; + } + String cls = modulePaths.get(message.file).toString(); + Main.getMainFrame().getPanel().debuggerBreakAt(Main.getMainFrame().getPanel().getCurrentSwf(), cls, message.line); + //dc.sendContinue(); + } + }); + //commands.sendContinue(); + List packs = Main.getMainFrame().getPanel().getCurrentSwf().getAS3Packs(); + for (ScriptPack sp : packs) { + ClassPath cp = sp.getClassPath(); + if (classToModule.containsKey(cp)) { + int file = classToModule.get(cp); + Set bpts = new TreeSet<>(Main.getPackBreakPoints(sp)); + for (int line : bpts) { + if (!commands.addBreakPoint(file, line)) { + Main.markBreakPointInvalid(sp, line); + } + } + } + } + Main.getMainFrame().getPanel().refreshBreakPoints(); + connected = true; + } catch (IOException ex) { + connected = false; } - - final Map modulePaths = new HashMap<>(); - - for (int mname : moduleNames.keySet()) { - String name = moduleNames.get(mname); - String[] parts = name.split(";"); - - if (parts.length == 3) { - String clsName = parts[2].replace(".as", ""); - String pkg = parts[1].replace("/", "\\").replace("\\", "."); - modulePaths.put(mname, new ClassPath(DottedChain.parse(pkg), clsName)); - } - } - - con.getMessage(InAskBreakpoints.class); - con.addMessageListener(new DebugMessageListener() { - - @Override - public void message(InContinue msg) { - synchronized (DebuggerHandler.this) { - paused = false; - } - Main.getMainFrame().getPanel().updateMenu(); - } - }); - con.addMessageListener(new DebugMessageListener() { - - @Override - public void message(InBreakAt message) { - synchronized (DebuggerHandler.this) { - paused = true; - } - Main.getMainFrame().getPanel().updateMenu(); - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "break at {0}:{1}", new Object[]{moduleNames.get(message.file), message.line}); - if (!modulePaths.containsKey(message.file)) { - return; - } - String cls = modulePaths.get(message.file).toString(); - Main.getMainFrame().getPanel().debuggerBreakAt(Main.getMainFrame().getPanel().getCurrentSwf(), cls, message.line); - //dc.sendContinue(); - } - }); - //commands.sendContinue(); - connected = true; } } diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 7016ca3bc..7e90e3483 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -34,6 +34,7 @@ import com.jpexs.decompiler.flash.SWFSourceInfo; import com.jpexs.decompiler.flash.SearchMode; import com.jpexs.decompiler.flash.SwfOpenException; import com.jpexs.decompiler.flash.Version; +import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration; @@ -90,10 +91,14 @@ import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeSet; +import java.util.WeakHashMap; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.logging.ConsoleHandler; @@ -153,6 +158,91 @@ public class Main { private static DebuggerHandler debugHandler = null; + private static Map> breakPointMap = new WeakHashMap<>(); + private static Map> invalidBreakPointMap = new WeakHashMap<>(); + + public static void clearBreakPoints(ScriptPack pack) { + if (breakPointMap.containsKey(pack)) { + breakPointMap.remove(pack); + } + } + + public static boolean isBreakPointValid(ScriptPack pack, int line) { + if (!invalidBreakPointMap.containsKey(pack)) { + return true; + } + return !invalidBreakPointMap.get(pack).contains(line); + + } + + public static void markBreakPointInvalid(ScriptPack pack, int line) { + if (!invalidBreakPointMap.containsKey(pack)) { + invalidBreakPointMap.put(pack, new TreeSet<>()); + } + invalidBreakPointMap.get(pack).add(line); + } + + public static void addBreakPoint(ScriptPack pack, int line) { + if (!breakPointMap.containsKey(pack)) { + breakPointMap.put(pack, new TreeSet<>()); + } + breakPointMap.get(pack).add(line); + if (debugHandler.isConnected()) { + int file = debugHandler.moduleIdOf(pack); + if (file > -1) { + try { + if (!debugHandler.getCommands().addBreakPoint(file, line)) { + markBreakPointInvalid(pack, line); + } + } catch (IOException ex) { + debugHandler.disconnect(); + //ignore + } + } + } + } + + public static void removeBreakPoint(ScriptPack pack, int line) { + if (breakPointMap.containsKey(pack)) { + Set lines = breakPointMap.get(pack); + if (lines != null) { + lines.remove(line); + } + } + if (debugHandler.isConnected()) { + int file = debugHandler.moduleIdOf(pack); + if (file > -1) { + try { + debugHandler.getCommands().removeBreakPoint(file, line); + } catch (IOException ex) { + debugHandler.disconnect(); + //ignore + } + } + } + } + + public static boolean toggleBreakPoint(ScriptPack pack, int line) { + if (!breakPointMap.containsKey(pack)) { + addBreakPoint(pack, line); + return true; + } + if (breakPointMap.get(pack).contains(line)) { + removeBreakPoint(pack, line); + return false; + } else { + addBreakPoint(pack, line); + return true; + } + } + + public static Set getPackBreakPoints(ScriptPack pack) { + if (!breakPointMap.containsKey(pack)) { + return new HashSet<>(); + } + return breakPointMap.get(pack); + } + public static DebuggerHandler getDebugHandler() { return debugHandler; } @@ -1465,7 +1555,7 @@ public class Main { String proxyAddress = Configuration.updateProxyAddress.get(); URL url = new URL(ApplicationInfo.updateCheckUrl); - URLConnection uc = null; + URLConnection uc; if (proxyAddress != null && !proxyAddress.isEmpty()) { int port = 8080; if (proxyAddress.contains(":")) { diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java index 4ea37793f..e433d06c0 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java @@ -1097,6 +1097,9 @@ public abstract class MainFrameMenu implements MenuBuilder { } runProcess = null; mainFrame.getPanel().clearDebuggerColors(); + if (runProcessDebug) { + Main.getDebugHandler().disconnect(); + } } private void runPlayer(String exePath, String file, String flashVars) { @@ -1124,8 +1127,7 @@ public abstract class MainFrameMenu implements MenuBuilder { proc.waitFor(); } catch (InterruptedException ex) { - Logger.getLogger(MainFrameMenu.class - .getName()).log(Level.SEVERE, null, ex); + //ignore } freeRun(); updateComponents(); @@ -1232,46 +1234,67 @@ public abstract class MainFrameMenu implements MenuBuilder { } public boolean pauseActionPerformed(ActionEvent evt) { - DebuggerCommands cmd = Main.getDebugHandler().getCommands(); - if (cmd != null) { + try { + DebuggerCommands cmd = Main.getDebugHandler().getCommands(); //TODO + + } catch (IOException ex) { + Main.getDebugHandler().disconnect(); + //ignore } return true; } public boolean stepOverActionPerformed(ActionEvent evt) { - DebuggerCommands cmd = Main.getDebugHandler().getCommands(); - if (cmd != null) { + try { + + DebuggerCommands cmd = Main.getDebugHandler().getCommands(); mainFrame.getPanel().clearDebuggerColors(); cmd.stepOver(); + } catch (IOException ex) { + Main.getDebugHandler().disconnect(); + //ignore } return true; } public boolean stepIntoActionPerformed(ActionEvent evt) { - DebuggerCommands cmd = Main.getDebugHandler().getCommands(); - if (cmd != null) { + try { + DebuggerCommands cmd = Main.getDebugHandler().getCommands(); mainFrame.getPanel().clearDebuggerColors(); cmd.stepInto(); + } catch (IOException ex) { + Main.getDebugHandler().disconnect(); + //ignore } + return true; } public boolean stepOutActionPerformed(ActionEvent evt) { - DebuggerCommands cmd = Main.getDebugHandler().getCommands(); - if (cmd != null) { + try { + DebuggerCommands cmd = Main.getDebugHandler().getCommands(); mainFrame.getPanel().clearDebuggerColors(); + cmd.stepOut(); + } catch (IOException ex) { + Main.getDebugHandler().disconnect(); + //ignore } + return true; } public boolean continueActionPerformed(ActionEvent evt) { - DebuggerCommands cmd = Main.getDebugHandler().getCommands(); - if (cmd != null) { + try { + DebuggerCommands cmd = Main.getDebugHandler().getCommands(); mainFrame.getPanel().clearDebuggerColors(); cmd.sendContinue(); + } catch (IOException ex) { + Main.getDebugHandler().disconnect(); + //ignore } + return true; } diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 55f6cf7a2..5e5dc956e 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -84,6 +84,7 @@ import com.jpexs.decompiler.flash.gui.controls.JPersistentSplitPane; import com.jpexs.decompiler.flash.gui.dumpview.DumpTree; import com.jpexs.decompiler.flash.gui.dumpview.DumpTreeModel; import com.jpexs.decompiler.flash.gui.dumpview.DumpViewPanel; +import com.jpexs.decompiler.flash.gui.editor.LineMarkedEditorPane; import com.jpexs.decompiler.flash.gui.helpers.ObservableList; import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel; import com.jpexs.decompiler.flash.gui.tagtree.TagTree; @@ -1539,10 +1540,16 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } + public void refreshBreakPoints() { + if (abcPanel != null) { + abcPanel.decompiledTextArea.refreshBreakPoints(); + } + } + public void debuggerBreakAt(SWF swf, String cls, int line) { gotoClassLine(swf, cls, line); if (abcPanel != null) { - abcPanel.decompiledTextArea.setLineColor(line - 1, Color.green); + abcPanel.decompiledTextArea.addColorMarker(line, DecompiledEditorPane.FG_IP_COLOR, DecompiledEditorPane.BG_IP_COLOR); } } @@ -2806,7 +2813,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se public void clearDebuggerColors() { if (abcPanel != null) { - abcPanel.decompiledTextArea.clearLineColors(); + abcPanel.decompiledTextArea.removeColorMarkerOnAllLines(DecompiledEditorPane.FG_IP_COLOR, DecompiledEditorPane.BG_IP_COLOR); } } diff --git a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java index b3a6bd1b4..c233b1707 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java @@ -35,6 +35,7 @@ import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction; import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; import com.jpexs.decompiler.flash.gui.AppStrings; +import com.jpexs.decompiler.flash.gui.Main; import com.jpexs.decompiler.flash.gui.View; import com.jpexs.decompiler.flash.gui.editor.LineMarkedEditorPane; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -43,18 +44,22 @@ import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; import com.jpexs.decompiler.flash.helpers.hilight.Highlighting; import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.decompiler.graph.DottedChain; +import java.awt.Color; import java.awt.Point; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.Timer; import java.util.TimerTask; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; +import jsyntaxpane.DefaultSyntaxKit; import jsyntaxpane.SyntaxDocument; import jsyntaxpane.Token; import jsyntaxpane.TokenType; +import jsyntaxpane.components.BreakPointListener; -public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretListener { +public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretListener, BreakPointListener { private List highlights = new ArrayList<>(); @@ -86,6 +91,31 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL private final List scriptListeners = new ArrayList<>(); + public static final Color BG_BREAKPOINT_COLOR = new Color(0xfc, 0x9d, 0x9f); + public static final Color FG_BREAKPOINT_COLOR = null; + + public static final Color BG_IP_COLOR = new Color(0xbd, 0xe6, 0xaa); + public static final Color FG_IP_COLOR = null; + + public static final Color BG_INVALID_BREAKPOINT_COLOR = new Color(0xdc, 0xdc, 0xd8); + public static final Color FG_INVALID_BREAKPOINT_COLOR = null; + + @Override + public void toggled(int line) { + boolean on = Main.toggleBreakPoint(script, line); + removeColorMarker(line, FG_INVALID_BREAKPOINT_COLOR, BG_INVALID_BREAKPOINT_COLOR); + if (on) { + if (Main.isBreakPointValid(script, line)) { + addColorMarker(line, FG_BREAKPOINT_COLOR, BG_BREAKPOINT_COLOR); + } else { + addColorMarker(line, FG_INVALID_BREAKPOINT_COLOR, BG_INVALID_BREAKPOINT_COLOR); + } + } else { + removeColorMarker(line, FG_BREAKPOINT_COLOR, BG_BREAKPOINT_COLOR); + removeColorMarker(line, FG_INVALID_BREAKPOINT_COLOR, BG_INVALID_BREAKPOINT_COLOR); + } + } + public void addScriptListener(Runnable l) { scriptListeners.add(l); } @@ -573,7 +603,7 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL } } currentMethodHighlight = null; - currentTrait = null; + //currentTrait = null; String name = abc.instance_info.get(classIndex).getName(abc.constants).getNameWithNamespace(abc.constants).toPrintableString(true); currentTrait = getCurrentTrait(); isStatic = abc.isStaticTraitId(classIndex, lastTraitIndex); @@ -599,8 +629,8 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL Highlighting tc = Highlighting.searchIndex(classHighlights, classIndex); if (tc != null || isScriptInit) { - Highlighting th = Highlighting.searchIndex(traitHighlights, traitId, isScriptInit ? 0 : tc.startPos, isScriptInit ? -1 : tc.startPos + tc.len); - int pos; + Highlighting th = Highlighting.searchIndex(traitHighlights, traitId, isScriptInit || tc == null ? 0 : tc.startPos, isScriptInit || tc == null ? -1 : tc.startPos + tc.len); + int pos = 0; if (th != null) { if (th.len > 1) { ignoreCarret = true; @@ -611,7 +641,7 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL ignoreCarret = false; } pos = th.startPos; - } else { + } else if (tc != null) { pos = tc.startPos; } @@ -705,9 +735,25 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL return script == null ? null : script.abc; } + public void refreshBreakPoints() { + Set bkptLines = Main.getPackBreakPoints(script); + removeColorMarkerOnAllLines(FG_BREAKPOINT_COLOR, BG_BREAKPOINT_COLOR); + removeColorMarkerOnAllLines(FG_INVALID_BREAKPOINT_COLOR, BG_INVALID_BREAKPOINT_COLOR); + + for (int line : bkptLines) { + if (Main.isBreakPointValid(script, line)) { + addColorMarker(line, FG_BREAKPOINT_COLOR, BG_BREAKPOINT_COLOR); + } else { + addColorMarker(line, FG_INVALID_BREAKPOINT_COLOR, BG_INVALID_BREAKPOINT_COLOR); + } + } + } + @Override public void setText(String t) { super.setText(t); setCaretPosition(0); + refreshBreakPoints(); + } } diff --git a/src/com/jpexs/decompiler/flash/gui/editor/LineMarkedEditorPane.java b/src/com/jpexs/decompiler/flash/gui/editor/LineMarkedEditorPane.java index f41399fe6..3610a25de 100644 --- a/src/com/jpexs/decompiler/flash/gui/editor/LineMarkedEditorPane.java +++ b/src/com/jpexs/decompiler/flash/gui/editor/LineMarkedEditorPane.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.gui.editor; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.gui.AppStrings; import java.awt.Color; @@ -32,8 +33,11 @@ import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Objects; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.plaf.TextUI; @@ -44,10 +48,17 @@ import javax.swing.text.Element; import javax.swing.text.Highlighter.HighlightPainter; import javax.swing.text.JTextComponent; import javax.swing.text.Position; +import javax.swing.text.Segment; +import javax.swing.text.TabExpander; import javax.swing.text.View; +import jsyntaxpane.DefaultSyntaxKit; import jsyntaxpane.SyntaxDocument; +import jsyntaxpane.SyntaxStyle; import jsyntaxpane.Token; import jsyntaxpane.actions.ActionUtils; +import jsyntaxpane.components.BreakPointListener; +import jsyntaxpane.components.LineNumbersRuler; +import jsyntaxpane.components.Markers; /** * @@ -57,6 +68,9 @@ public class LineMarkedEditorPane extends UndoFixedEditorPane implements LinkHan private static final int truncateLimit = 2 * 1024 * 1024; + public static final Color BG_SELECTED_LINE = new Color(0xe9, 0xef, 0xf8); + public static final Color BG_ERROR_LINE = new Color(255, 200, 200); + private int lastLine = -1; private boolean error = false; @@ -67,17 +81,109 @@ public class LineMarkedEditorPane extends UndoFixedEditorPane implements LinkHan private LinkHandler linkHandler = this; - private Map lineColors = new HashMap<>(); + public static class LineMarker { + + private Color bgColor; + private Color color; + private FgPainter fgPainter; + private int line; + + public FgPainter getForegroundPainter() { + return fgPainter; + } + + public LineMarker(int line, Color color, Color bgColor) { + this.line = line; + this.bgColor = bgColor; + this.color = color; + if (color != null) { + this.fgPainter = new FgPainter(color, bgColor); + } + } + + @Override + public int hashCode() { + int hash = 5; + hash = 17 * hash + Objects.hashCode(this.bgColor); + hash = 17 * hash + Objects.hashCode(this.color); + hash = 17 * hash + this.line; + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final LineMarker other = (LineMarker) obj; + if (!Objects.equals(this.bgColor, other.bgColor)) { + return false; + } + if (!Objects.equals(this.color, other.color)) { + return false; + } + return this.line == other.line; + } + + public Color getBgColor() { + return bgColor; + } + + public Color getColor() { + return color; + } + + } + + private Map> lineMarkers = new HashMap<>(); + + public void setLineMarkers(Map> colorMarkers) { + this.lineMarkers = colorMarkers; + } public void clearLineColors() { - lineColors.clear(); + lineMarkers.clear(); repaint(); } - public void setLineColor(int line, Color color) { - lineColors.remove(line); - if (color != null) { - lineColors.put(line, color); + public void removeColorMarker(int line, Color color, Color bgColor) { + if (lineMarkers.containsKey(line)) { + LineMarker lm = new LineMarker(line, color, bgColor); + lineMarkers.get(line).remove(lm); + } + repaint(); + } + + public void removeColorMarkerOnAllLines(Color color, Color bgColor) { + for (int line : lineMarkers.keySet()) { + removeColorMarker(line, color, bgColor); + } + } + + public void toggleColorMarker(int line, Color color, Color bgColor) { + if (!lineMarkers.containsKey(line)) { + addColorMarker(line, color, bgColor); + } else { + if (lineMarkers.get(line).contains(color)) { + removeColorMarker(line, color, bgColor); + } else { + addColorMarker(line, color, bgColor); + } + } + repaint(); + } + + public void addColorMarker(int line, Color color, Color bgColor) { + if (!lineMarkers.containsKey(line)) { + lineMarkers.put(line, new ArrayList<>()); + + } + LineMarker marker = new LineMarker(line, color, bgColor); + if (!lineMarkers.get(line).contains(marker)) { + lineMarkers.get(line).add(marker); } repaint(); } @@ -94,7 +200,7 @@ public class LineMarkedEditorPane extends UndoFixedEditorPane implements LinkHan setCaretPosition(ActionUtils.getDocumentPosition(this, line, 0)); } - public void selectLine(int line) { + private void getLineBounds(int line, Reference lineStart, Reference lineEnd) { Document d = getDocument(); String text = ""; try { @@ -103,27 +209,35 @@ public class LineMarkedEditorPane extends UndoFixedEditorPane implements LinkHan //ignore } int lineCnt = 1; - int lineStart = 0; - int lineEnd = -1; + int lineStartVal = 0; + int lineEndVal = -1; for (int i = 0; i < text.length(); i++) { if (text.charAt(i) == '\n') { lineCnt++; if (lineCnt == line) { - lineStart = i + 1; + lineStartVal = i + 1; } if (lineCnt == line + 1) { - lineEnd = i; + lineEndVal = i; } } } if (lineCnt == 1) { - lineEnd = text.length() - 1; + lineEndVal = text.length() - 1; if (line > 1) { - lineStart = text.length() - 1; + lineStartVal = text.length() - 1; } } + lineEnd.setVal(lineEndVal); + lineStart.setVal(lineStartVal); + } - select(lineStart, lineEnd); + public void selectLine(int line) { + Reference lineStart = new Reference<>(0); + Reference lineEnd = new Reference<>(0); + getLineBounds(line, lineStart, lineEnd); + + select(lineStart.getVal(), lineEnd.getVal()); requestFocus(); } @@ -287,15 +401,101 @@ public class LineMarkedEditorPane extends UndoFixedEditorPane implements LinkHan } + public void setText(String t, Map> lineMarkers) { + setText(t); + this.lineMarkers = lineMarkers; + repaint(); + } + @Override public void setText(String t) { + this.lineMarkers = new HashMap<>(); lastLine = -1; error = false; if (Configuration.debugMode.get() && t != null && t.length() > truncateLimit) { t = t.substring(0, truncateLimit) + "\r\n" + AppStrings.translate("editorTruncateWarning").replace("%chars%", Integer.toString(truncateLimit)); } super.setText(t); - setCaretPosition(0); //scroll to top + setCaretPosition(0); //scroll to top + } + + public static class FgPainter extends DefaultHighlighter.DefaultHighlightPainter { + + private SyntaxStyle fgStyle; + + public FgPainter(Color color, Color bgColor) { + super(bgColor); + this.fgStyle = new SyntaxStyle(color, false, false); + } + + @Override + public void paint(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c) { + try { + // --- determine locations --- + TextUI mapper = c.getUI(); + + Segment seg = new Segment(); + ((SyntaxDocument) c.getDocument()).getText(offs0, offs1 - offs0, seg); + + Rectangle r = mapper.modelToView(c, offs0, Position.Bias.Forward); + FontMetrics fm = g.getFontMetrics(); + //int fh = fm.getHeight(); + fgStyle.drawText(seg, r.x, r.y + fm.getAscent(), g, null, offs0); + /*for (int i = offs0; i < offs1; i++) { + + Rectangle r = mapper.modelToView(c, i, Position.Bias.Forward); + Rectangle r1 = mapper.modelToView(c, i + 1, Position.Bias.Forward); + if (r1.y == r.y) { + ((SyntaxDocument) c.getDocument()).getText(i, 1, seg); + fgStyle.drawText(seg, r.x, r.y, g, null, i); + //g.drawLine(r.x, r.y + r.height - 3, r1.x, r.y + r.height - 3); + } + }*/ + + } catch (BadLocationException e) { + // can't render + } + } + + @Override + public Shape paintLayer(Graphics g, int offs0, int offs1, + Shape bounds, JTextComponent c, View view) { + + g.setColor(c.getSelectionColor()); + + Rectangle r; + + if (offs0 == view.getStartOffset() + && offs1 == view.getEndOffset()) { + // Contained in view, can just use bounds. + if (bounds instanceof Rectangle) { + r = (Rectangle) bounds; + } else { + r = bounds.getBounds(); + } + } else { + // Should only render part of View. + try { + // --- determine locations --- + Shape shape = view.modelToView(offs0, Position.Bias.Forward, + offs1, Position.Bias.Backward, + bounds); + r = (shape instanceof Rectangle) + ? (Rectangle) shape : shape.getBounds(); + } catch (BadLocationException e) { + // can't render + r = null; + } + } + + if (r != null) { + r.width = Math.max(r.width, 1); + + paint(g, offs0, offs1, r, c); + } + + return r; + } } public static class UnderLinePainter extends DefaultHighlighter.DefaultHighlightPainter { @@ -381,16 +581,38 @@ public class LineMarkedEditorPane extends UndoFixedEditorPane implements LinkHan if (lastLine > 0) { if (error) { - g.setColor(new Color(255, 200, 200)); + g.setColor(BG_ERROR_LINE); } else { - g.setColor(new Color(0xee, 0xee, 0xee)); + g.setColor(BG_SELECTED_LINE); } g.fillRect(0, d + lh * lastLine - 1, getWidth(), lh); } - for (int line : lineColors.keySet()) { - g.setColor(lineColors.get(line)); - g.fillRect(0, d + lh * line - 1, getWidth(), lh); + for (int line : lineMarkers.keySet()) { + List cs = lineMarkers.get(line); + if (cs.isEmpty()) { + continue; + } + LineMarker lastMarker = cs.get(cs.size() - 1); + if (lastMarker.getBgColor() == null) { + continue; + } + g.setColor(lastMarker.getBgColor()); + g.fillRect(0, d + lh * (line - 1), getWidth(), lh); } super.paint(g); + for (int line : lineMarkers.keySet()) { + List cs = lineMarkers.get(line); + if (cs.isEmpty()) { + continue; + } + Reference lineStart = new Reference<>(0); + Reference lineEnd = new Reference<>(0); + getLineBounds(line, lineStart, lineEnd); + FgPainter fgp = cs.get(cs.size() - 1).getForegroundPainter(); + if (fgp != null) { + fgp.paint(g, lineStart.getVal(), lineEnd.getVal(), null, this); + } + } } + }