diff --git a/CHANGELOG.md b/CHANGELOG.md index cffc17a32..eb972db14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file. the new TOML file, when exists) - `-configFile` and `-storeConfigFile` commandline parameters for loading/storing configuration file - Option to .bat and .sh file to enable J2D_D3D_NO_HWCHECK +- [#2404] Quick find in text/script editors - show number of occurences ### Fixed - [#2456] FLA export - NullPointer exception while exporting to CS4 or lower via commandline @@ -18,6 +19,7 @@ All notable changes to this project will be documented in this file. - Resize export dialogs labels to match localized strings - AS1/2 debugger - deletion of SWD file after debugging - Proper freeing memory after SWF close +- AS1/2 improper selection of search result ## [23.0.1] - 2025-05-16 ### Fixed @@ -3800,6 +3802,7 @@ Major version of SWF to XML export changed to 2. [alpha 9]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha8...alpha9 [alpha 8]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha7...alpha8 [alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7 +[#2404]: https://www.free-decompiler.com/flash/issues/2404 [#2456]: https://www.free-decompiler.com/flash/issues/2456 [#2427]: https://www.free-decompiler.com/flash/issues/2427 [#1826]: https://www.free-decompiler.com/flash/issues/1826 diff --git a/lib/jsyntaxpane-0.9.5.jar b/lib/jsyntaxpane-0.9.5.jar index 63409e2b9..67b2a6ce1 100644 Binary files a/lib/jsyntaxpane-0.9.5.jar and b/lib/jsyntaxpane-0.9.5.jar differ diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/DocumentSearchData.java b/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/DocumentSearchData.java index acda9688e..fec2c4f5c 100644 --- a/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/DocumentSearchData.java +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/DocumentSearchData.java @@ -15,6 +15,8 @@ package jsyntaxpane.actions; import java.awt.Component; import java.text.MessageFormat; +import java.util.Map; +import java.util.WeakHashMap; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; @@ -46,6 +48,10 @@ public class DocumentSearchData { private boolean wrap = true; private ReplaceDialog replaceDlg; private QuickFindDialog quickFindDlg; + /** + * JPEXS + */ + private Map currentOccurenceMap = new WeakHashMap<>(); /** * This prevent creating a new instance. You must call the getFromEditor @@ -55,6 +61,8 @@ public class DocumentSearchData { private DocumentSearchData() { } + + public Pattern getPattern() { return pattern; } @@ -176,20 +184,57 @@ public class DocumentSearchData { // go throw all matches, and stop when we reach current pos int start = -1; int end = -1; + int occurenceNumber = 0; //JPEXS while (matcher.find()) { if (matcher.end() >= dot) { break; } + occurenceNumber++; start = matcher.start(); end = matcher.end(); } if (end > 0) { target.select(start, end); + currentOccurenceMap.put(target, occurenceNumber); return true; } else { - return false; + return false; } } + + /** + * Gets search occurences. (JPEXS) + * + * @param target + * @return Number of occurences + */ + public int getOccurencesCount(JTextComponent target) { + if (getPattern() == null) { + return 0; + } + SyntaxDocument sDoc = ActionUtils.getSyntaxDocument(target); + if (sDoc == null) { + return 0; + } + Matcher matcher = sDoc.getMatcher(getPattern()); + int count = 0; + while (matcher.find()) { + count++; + } + return count; + } + + /** + * Gets current occurence number. (JPEXS) + * @param target + * @return Current occurence number. + */ + public int getCurrentOccurence(JTextComponent target) { + if (!currentOccurenceMap.containsKey(target)) { + return 0; + } + return currentOccurenceMap.get(target); + } /** * Perform a FindNext operation on the given text component. Position @@ -214,22 +259,37 @@ public class DocumentSearchData { if (start >= sDoc.getLength()) { start = sDoc.getLength(); } - Matcher matcher = sDoc.getMatcher(getPattern(), start); - if (matcher != null && matcher.find()) { - // since we used an offset in the matcher, the matcher location - // MUST be offset by that location - target.select(matcher.start() + start, matcher.end() + start); + Matcher matcher = sDoc.getMatcher(getPattern()); + + //JPEXS + int occurenceNumber = 0; + boolean found = false; + if (matcher != null) { + while(matcher.find()) { + occurenceNumber++; + if (matcher.start() >= start) { + found = true; + break; + } + } + } + + if (found) { //JPEXS + target.select(matcher.start(), matcher.end()); //JPEXS + currentOccurenceMap.put(target, occurenceNumber); return true; } else { if (isWrap()) { matcher = sDoc.getMatcher(getPattern()); if (matcher != null && matcher.find()) { target.select(matcher.start(), matcher.end()); + currentOccurenceMap.put(target, 1); return true; } else { + currentOccurenceMap.put(target, 0); return false; } - } else { + } else { return false; } } diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/gui/QuickFindDialog.form b/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/gui/QuickFindDialog.form index 0a4d582d2..c029c6c01 100644 --- a/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/gui/QuickFindDialog.form +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/gui/QuickFindDialog.form @@ -46,7 +46,6 @@ - @@ -91,7 +90,6 @@ - @@ -108,13 +106,24 @@ - + + + + + + + + + + + + @@ -122,7 +131,6 @@ - @@ -136,7 +144,6 @@ - @@ -150,7 +157,6 @@ - diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/gui/QuickFindDialog.java b/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/gui/QuickFindDialog.java index f596833a2..6c4102f02 100644 --- a/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/gui/QuickFindDialog.java +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/java/jsyntaxpane/actions/gui/QuickFindDialog.java @@ -87,6 +87,7 @@ public class QuickFindDialog extends javax.swing.JDialog public QuickFindDialog(final JTextComponent target, DocumentSearchData data) { super(ActionUtils.getFrameFor(target), false); initComponents(); + jToolBar1.setFloatable(false); SwingUtils.addEscapeListener(this); dsd = new WeakReference(data); getRootPane().setWindowDecorationStyle(JRootPane.NONE); @@ -159,6 +160,7 @@ public class QuickFindDialog extends javax.swing.JDialog jSeparator3 = new javax.swing.JToolBar.Separator(); jBtnPrev = new javax.swing.JButton(); jBtnNext = new javax.swing.JButton(); + jLblOccurences = new javax.swing.JLabel(); jChkIgnoreCase = new javax.swing.JCheckBox(); jChkRegExp = new javax.swing.JCheckBox(); jChkWrap = new javax.swing.JCheckBox(); @@ -172,7 +174,6 @@ public class QuickFindDialog extends javax.swing.JDialog setResizable(false); jToolBar1.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - jToolBar1.setFloatable(false); jToolBar1.setRollover(true); jToolBar1.add(jSeparator1); @@ -192,7 +193,6 @@ public class QuickFindDialog extends javax.swing.JDialog jBtnPrev.setIcon(new javax.swing.ImageIcon(getClass().getResource("/META-INF/images/small-icons/go-up.png"))); // NOI18N jBtnPrev.setFocusable(false); jBtnPrev.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - jBtnPrev.setOpaque(false); jBtnPrev.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); jBtnPrev.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -205,7 +205,6 @@ public class QuickFindDialog extends javax.swing.JDialog jBtnNext.setFocusable(false); jBtnNext.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); jBtnNext.setMargin(new java.awt.Insets(2, 2, 2, 2)); - jBtnNext.setOpaque(false); jBtnNext.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); jBtnNext.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -214,10 +213,13 @@ public class QuickFindDialog extends javax.swing.JDialog }); jToolBar1.add(jBtnNext); + jLblOccurences.setText(bundle.getString("QuickFindDialog.Occurences.Zero")); // NOI18N + jLblOccurences.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 5, 0, 5)); + jToolBar1.add(jLblOccurences); + jChkIgnoreCase.setMnemonic('C'); jChkIgnoreCase.setText(bundle.getString("QuickFindDialog.jChkIgnoreCase.text")); // NOI18N jChkIgnoreCase.setFocusable(false); - jChkIgnoreCase.setOpaque(false); jChkIgnoreCase.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); jToolBar1.add(jChkIgnoreCase); jChkIgnoreCase.addActionListener(this); @@ -225,7 +227,6 @@ public class QuickFindDialog extends javax.swing.JDialog jChkRegExp.setMnemonic('R'); jChkRegExp.setText(bundle.getString("QuickFindDialog.jChkRegExp.text")); // NOI18N jChkRegExp.setFocusable(false); - jChkRegExp.setOpaque(false); jChkRegExp.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); jToolBar1.add(jChkRegExp); jChkRegExp.addActionListener(this); @@ -233,7 +234,6 @@ public class QuickFindDialog extends javax.swing.JDialog jChkWrap.setMnemonic('W'); jChkWrap.setText(bundle.getString("QuickFindDialog.jChkWrap.text")); // NOI18N jChkWrap.setFocusable(false); - jChkWrap.setOpaque(false); jChkWrap.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); jToolBar1.add(jChkWrap); jChkWrap.addActionListener(this); @@ -264,6 +264,7 @@ public class QuickFindDialog extends javax.swing.JDialog } else { jLblStatus.setText(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("QuickFindDialog.NotFound")); } + updateOccurences(); }//GEN-LAST:event_jBtnNextActionPerformed private void jBtnPrevActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jBtnPrevActionPerformed @@ -272,8 +273,25 @@ public class QuickFindDialog extends javax.swing.JDialog } else { jLblStatus.setText(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("QuickFindDialog.NotFound")); } + updateOccurences(); }//GEN-LAST:event_jBtnPrevActionPerformed + //JPEXS + private void updateOccurences() { + if (dsd.get().getOccurencesCount(target.get()) == 0) + { + jLblOccurences.setText( + java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("QuickFindDialog.Occurences.Zero") + ); + return; + } + jLblOccurences.setText( + java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("QuickFindDialog.Occurences") + .replace("%current%", "" + dsd.get().getCurrentOccurence(target.get())) + .replace("%total%", "" + dsd.get().getOccurencesCount(target.get())) + ); + } + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jBtnNext; private javax.swing.JButton jBtnPrev; @@ -281,6 +299,7 @@ public class QuickFindDialog extends javax.swing.JDialog private javax.swing.JCheckBox jChkRegExp; private javax.swing.JCheckBox jChkWrap; private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLblOccurences; private javax.swing.JLabel jLblStatus; private javax.swing.JToolBar.Separator jSeparator1; private javax.swing.JToolBar.Separator jSeparator2; @@ -311,6 +330,7 @@ public class QuickFindDialog extends javax.swing.JDialog String toFind = jTxtFind.getText(); if (toFind == null || toFind.isEmpty()) { jLblStatus.setText(null); + jLblOccurences.setText(null); return; } try { @@ -327,6 +347,7 @@ public class QuickFindDialog extends javax.swing.JDialog } else { jLblStatus.setText(null); } + updateOccurences(); //JPEXS setSize(getPreferredSize()); pack(); } catch (PatternSyntaxException e) { diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/Bundle.properties b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/Bundle.properties index 61eb66f35..366c398d5 100644 --- a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/Bundle.properties +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/Bundle.properties @@ -36,3 +36,6 @@ ScriptRunnerAction.ErrorExecutingScript = Error executing script:\\n ScriptRunnerAction.ScriptError = Script Error ScriptRunnerAction.ScriptEngineNotFound = Script Engine for [{0}] not found. Disable this Action? ShowAbbsAction.NoAbbsForType = No Abbreviations exist for this content type + +QuickFindDialog.Occurences = (%current%/%total%) +QuickFindDialog.Occurences.Zero = (0) \ No newline at end of file diff --git a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/Bundle_cs.properties b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/Bundle_cs.properties index c4f09c760..d301e295b 100644 --- a/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/Bundle_cs.properties +++ b/libsrc/jsyntaxpane/jsyntaxpane/src/main/resources/jsyntaxpane/Bundle_cs.properties @@ -36,3 +36,6 @@ ScriptRunnerAction.ErrorExecutingScript = Chyba vykon\u00e1v\u00e1n\u00ed skript ScriptRunnerAction.ScriptError = Chyba skriptu ScriptRunnerAction.ScriptEngineNotFound = Engine skriptu [{0}] nenalezen. Zak\u00e1zat tuto akci? ShowAbbsAction.NoAbbsForType = Pro tento typ obsahu neexistuj\u00ed zkratky + +QuickFindDialog.Occurences = (%current%/%total%) +QuickFindDialog.Occurences.Zero = (0) \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/ScrollPosStorage.java b/src/com/jpexs/decompiler/flash/gui/ScrollPosStorage.java index bd4b2261e..501d111bb 100644 --- a/src/com/jpexs/decompiler/flash/gui/ScrollPosStorage.java +++ b/src/com/jpexs/decompiler/flash/gui/ScrollPosStorage.java @@ -252,12 +252,18 @@ public class ScrollPosStorage { return; } actionScriptCaret = mainPanel.getABCPanel().decompiledTextArea.getCaretPosition(); + if (mainPanel.getABCPanel().decompiledTextArea.getSelectionStart() > 0) { + actionScriptCaret = mainPanel.getABCPanel().decompiledTextArea.getSelectionStart(); + } actionScriptScrollHorizontal = mainPanel.getABCPanel().decompiledScrollPane.getHorizontalScrollBar().getValue(); actionScriptScrollVertical = mainPanel.getABCPanel().decompiledScrollPane.getVerticalScrollBar().getValue(); pcodeScrollHorizontal = mainPanel.getABCPanel().detailPanel.methodTraitPanel.methodCodePanel.getSourceScrollPane().getHorizontalScrollBar().getValue(); pcodeScrollVertical = mainPanel.getABCPanel().detailPanel.methodTraitPanel.methodCodePanel.getSourceScrollPane().getVerticalScrollBar().getValue(); pcodeCaret = mainPanel.getABCPanel().detailPanel.methodTraitPanel.methodCodePanel.getSourceTextArea().getCaretPosition(); + if (mainPanel.getABCPanel().detailPanel.methodTraitPanel.methodCodePanel.getSourceTextArea().getSelectionStart() > 0) { + pcodeCaret = mainPanel.getABCPanel().detailPanel.methodTraitPanel.methodCodePanel.getSourceTextArea().getSelectionStart(); + } } } else if (asmItem instanceof ASMSource) { @@ -272,9 +278,15 @@ public class ScrollPosStorage { actionScriptScrollHorizontal = ((JScrollPane) mainPanel.getActionPanel().decompiledEditor.getParent().getParent()).getHorizontalScrollBar().getValue(); actionScriptScrollVertical = ((JScrollPane) mainPanel.getActionPanel().decompiledEditor.getParent().getParent()).getVerticalScrollBar().getValue(); actionScriptCaret = mainPanel.getActionPanel().decompiledEditor.getCaretPosition(); + if (mainPanel.getActionPanel().decompiledEditor.getSelectionStart() > 0) { + actionScriptCaret = mainPanel.getActionPanel().decompiledEditor.getSelectionStart(); + } pcodeScrollHorizontal = ((JScrollPane) mainPanel.getActionPanel().editor.getParent().getParent()).getHorizontalScrollBar().getValue(); pcodeScrollVertical = ((JScrollPane) mainPanel.getActionPanel().editor.getParent().getParent()).getVerticalScrollBar().getValue(); pcodeCaret = mainPanel.getActionPanel().editor.getCaretPosition(); + if (mainPanel.getActionPanel().editor.getSelectionStart() > 0) { + pcodeCaret = mainPanel.getActionPanel().editor.getSelectionStart(); + } } } int folderPreviewScrollVertical = 0; diff --git a/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java b/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java index 97775de56..f89f3285e 100644 --- a/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java @@ -86,6 +86,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.CancellationException; import java.util.logging.Level; import java.util.logging.Logger; @@ -1391,14 +1393,27 @@ public class ActionPanel extends JPanel implements SearchListener