From 9cac6ddb496180a9126e83d0750e9233119fc2d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Tue, 23 Feb 2021 19:48:09 +0100 Subject: [PATCH] Scoped script text search and search across multiple SWFs --- CHANGELOG.md | 1 + .../flash/search/ABCSearchResult.java | 2 +- .../flash/search/ActionScriptSearch.java | 28 ++- .../flash/search/ActionSearchResult.java | 2 +- .../flash/search/ScriptSearchResult.java | 9 + .../decompiler/flash/gui/MainFrameMenu.java | 10 +- .../flash/gui/MainFrameRibbonMenu.java | 9 +- .../jpexs/decompiler/flash/gui/MainPanel.java | 184 ++++++++++++++---- .../decompiler/flash/gui/SearchDialog.java | 50 ++++- .../flash/gui/SearchResultsDialog.java | 10 +- .../decompiler/flash/gui/abc/ABCPanel.java | 25 ++- .../flash/gui/action/ActionPanel.java | 22 ++- .../flash/gui/locales/SearchDialog.properties | 7 + .../flash/gui/tagtree/TagTreeContextMenu.java | 52 +++++ 14 files changed, 343 insertions(+), 68 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ScriptSearchResult.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 55bd2aac3..b31d84530 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ All notable changes to this project will be documented in this file. - #1595 History of script search results per SWF - Ignore case and RegExp options displayed on search results dialog - #1611 Warning about initializers has do not show again checkbox +- Scoped script text search and search across multiple SWFs ### Fixed - #1298 AS1/2 properly decompiled setProperty/getProperty diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ABCSearchResult.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ABCSearchResult.java index 3ab8b6810..f0b194c1e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ABCSearchResult.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ABCSearchResult.java @@ -38,7 +38,7 @@ import java.util.logging.Logger; * * @author JPEXS */ -public class ABCSearchResult implements Serializable { +public class ABCSearchResult implements Serializable, ScriptSearchResult { public static String STR_INSTANCE_INITIALIZER = AppResources.translate("trait.instanceinitializer"); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionScriptSearch.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionScriptSearch.java index a671fc464..40a3d44ac 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionScriptSearch.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionScriptSearch.java @@ -43,9 +43,15 @@ import java.util.regex.Pattern; */ public class ActionScriptSearch { - public List searchAs2(SWF swf, final String txt, boolean ignoreCase, boolean regexp, boolean pcode, ScriptSearchListener listener) { + public List searchAs2(SWF swf, final String txt, boolean ignoreCase, boolean regexp, boolean pcode, ScriptSearchListener listener, Map scope) { if (txt != null && !txt.isEmpty()) { - Map asms = swf.getASMs(false); + Map asms; + if (scope == null) { + asms = swf.getASMs(false); + } else { + asms = scope; + } + final List found = new ArrayList<>(); Pattern pat = regexp ? Pattern.compile(txt, ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0) @@ -107,7 +113,7 @@ public class ActionScriptSearch { return null; } - public List searchAs3(final SWF swf, final String txt, boolean ignoreCase, boolean regexp, boolean pcode, ScriptSearchListener listener) { + public List searchAs3(final SWF swf, final String txt, boolean ignoreCase, boolean regexp, boolean pcode, ScriptSearchListener listener, List scope) { // todo: pcode seach if (txt != null && !txt.isEmpty()) { List ignoredClasses = new ArrayList<>(); @@ -118,7 +124,13 @@ public class ActionScriptSearch { } final List found = Collections.synchronizedList(new ArrayList<>()); - List allpacks = swf.getAS3Packs(); + final List fscope; + if (scope == null) { + fscope = swf.getAS3Packs(); + } else { + fscope = scope; + } + final Pattern pat = regexp ? Pattern.compile(txt, ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0) : Pattern.compile(Pattern.quote(txt), ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0); @@ -127,7 +139,7 @@ public class ActionScriptSearch { List> futures = new ArrayList<>(); try { loop: - for (final ScriptPack pack : allpacks) { + for (final ScriptPack pack : fscope) { pos++; if (!pack.isSimple && Configuration.ignoreCLikePackages.get()) { continue; @@ -146,7 +158,7 @@ public class ActionScriptSearch { if (pcode) { if (listener != null) { - listener.onSearch(pos, allpacks.size(), pack.getClassPath().toString()); + listener.onSearch(pos, fscope.size(), pack.getClassPath().toString()); } List methodInfos = new ArrayList<>(); @@ -175,7 +187,7 @@ public class ActionScriptSearch { return; } if (listener != null) { - listener.onDecompile(fpos, allpacks.size(), pack.getClassPath().toString()); + listener.onDecompile(fpos, fscope.size(), pack.getClassPath().toString()); } } @@ -184,7 +196,7 @@ public class ActionScriptSearch { if (!Thread.currentThread().isInterrupted()) { if (listener != null) { - listener.onSearch(fpos, allpacks.size(), pack.getClassPath().toString()); + listener.onSearch(fpos, fscope.size(), pack.getClassPath().toString()); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionSearchResult.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionSearchResult.java index dff7a8639..5ec8cfb6f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionSearchResult.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ActionSearchResult.java @@ -31,7 +31,7 @@ import java.util.Map; * * @author JPEXS */ -public class ActionSearchResult { +public class ActionSearchResult implements ScriptSearchResult { private final ASMSource src; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ScriptSearchResult.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ScriptSearchResult.java new file mode 100644 index 000000000..241720032 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/search/ScriptSearchResult.java @@ -0,0 +1,9 @@ +package com.jpexs.decompiler.flash.search; + +/** + * + * @author JPEXS + */ +public interface ScriptSearchResult { + +} diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java index 1e0a88c69..e88dd1b92 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java @@ -26,6 +26,8 @@ import com.jpexs.decompiler.flash.configuration.ConfigurationItemChangeListener; import com.jpexs.decompiler.flash.console.ContextMenuTools; import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools; import com.jpexs.decompiler.flash.gui.helpers.CheckResources; +import com.jpexs.decompiler.flash.search.ScriptSearchListener; +import com.jpexs.decompiler.flash.search.ScriptSearchResult; import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.helpers.ByteArrayRange; import com.jpexs.helpers.Helper; @@ -1181,11 +1183,15 @@ public abstract class MainFrameMenu implements MenuBuilder { String searched = Main.searchResultsStorage.getSearchedValueAt(fi); ActionListener a = (ActionEvent e) -> { SearchResultsDialog sr; + List> listeners = new ArrayList<>(); + listeners.add(Main.getMainFrame().getPanel().getABCPanel()); + listeners.add(Main.getMainFrame().getPanel().getActionPanel()); + if (swf.isAS3()) { - sr = new SearchResultsDialog<>(Main.getMainFrame().getWindow(), searched, Main.searchResultsStorage.isIgnoreCaseAt(fi), Main.searchResultsStorage.isRegExpAt(fi), Main.getMainFrame().getPanel().getABCPanel()); + sr = new SearchResultsDialog<>(Main.getMainFrame().getWindow(), searched, Main.searchResultsStorage.isIgnoreCaseAt(fi), Main.searchResultsStorage.isRegExpAt(fi), listeners); sr.setResults(Main.searchResultsStorage.getAbcSearchResultsAt(swf, fi)); } else { - sr = new SearchResultsDialog<>(Main.getMainFrame().getWindow(), searched, Main.searchResultsStorage.isIgnoreCaseAt(fi), Main.searchResultsStorage.isRegExpAt(fi), Main.getMainFrame().getPanel().getActionPanel()); + sr = new SearchResultsDialog<>(Main.getMainFrame().getWindow(), searched, Main.searchResultsStorage.isIgnoreCaseAt(fi), Main.searchResultsStorage.isRegExpAt(fi), listeners); sr.setResults(Main.searchResultsStorage.getActionSearchResultsAt(swf, fi)); } sr.setVisible(true); diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java index 1b8cfb25f..6380c9700 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.search.ABCSearchResult; import com.jpexs.decompiler.flash.search.ActionSearchResult; +import com.jpexs.decompiler.flash.search.ScriptSearchResult; import java.awt.BorderLayout; import java.awt.Color; import java.awt.event.ActionEvent; @@ -176,12 +177,16 @@ public class MainFrameRibbonMenu extends MainFrameMenu { historyButton.search = searched; historyButton.addActionListener((ActionEvent ae) -> { + + List> listeners = new ArrayList<>(); + listeners.add(Main.getMainFrame().getPanel().getABCPanel()); + listeners.add(Main.getMainFrame().getPanel().getActionPanel()); SearchResultsDialog sr; if (swf.isAS3()) { - sr = new SearchResultsDialog<>(Main.getMainFrame().getWindow(), searched, Main.searchResultsStorage.isIgnoreCaseAt(fi), Main.searchResultsStorage.isRegExpAt(fi), Main.getMainFrame().getPanel().getABCPanel()); + sr = new SearchResultsDialog<>(Main.getMainFrame().getWindow(), searched, Main.searchResultsStorage.isIgnoreCaseAt(fi), Main.searchResultsStorage.isRegExpAt(fi), listeners); sr.setResults(Main.searchResultsStorage.getAbcSearchResultsAt(swf, fi)); } else { - sr = new SearchResultsDialog<>(Main.getMainFrame().getWindow(), searched, Main.searchResultsStorage.isIgnoreCaseAt(fi), Main.searchResultsStorage.isRegExpAt(fi), Main.getMainFrame().getPanel().getActionPanel()); + sr = new SearchResultsDialog<>(Main.getMainFrame().getWindow(), searched, Main.searchResultsStorage.isIgnoreCaseAt(fi), Main.searchResultsStorage.isRegExpAt(fi), listeners); sr.setResults(Main.searchResultsStorage.getActionSearchResultsAt(swf, fi)); } sr.setVisible(true); diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index b08349125..7eff736a2 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -108,6 +108,7 @@ import com.jpexs.decompiler.flash.importers.TextImporter; import com.jpexs.decompiler.flash.importers.svg.SvgImporter; import com.jpexs.decompiler.flash.search.ABCSearchResult; import com.jpexs.decompiler.flash.search.ActionSearchResult; +import com.jpexs.decompiler.flash.search.ScriptSearchResult; import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; import com.jpexs.decompiler.flash.tags.DefineBitsJPEG3Tag; @@ -192,6 +193,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -1759,10 +1762,86 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } } + private void populateSwfs(SWF swfParent, List output) { + for (Tag t : swfParent.getTags()) { + if (t instanceof DefineBinaryDataTag) { + DefineBinaryDataTag b = (DefineBinaryDataTag) t; + if (b.innerSwf != null) { + output.add(b.innerSwf); + populateSwfs(b.innerSwf, output); + } + } + } + } + public void searchInActionScriptOrText(Boolean searchInText, SWF swf) { View.checkAccess(); - SearchDialog searchDialog = new SearchDialog(getMainFrame().getWindow(), false); + List allItems = tagTree.getAllSelected(); + + Map> scopeAs3 = new LinkedHashMap<>(); + Map> swfToAllASMSourceMap = new HashMap<>(); + Map> scopeAs12 = new LinkedHashMap<>(); + + Set swfsUsed = new LinkedHashSet<>(); + + for (TreeItem t : allItems) { + if (t instanceof ScriptPack) { + ScriptPack sp = (ScriptPack) t; + SWF s = sp.getSwf(); + if (!scopeAs3.containsKey(s)) { + scopeAs3.put(s, new ArrayList<>()); + } + scopeAs3.get(s).add(sp); + swfsUsed.add(s); + } + ASMSource as = null; + if (t instanceof ASMSource) { + as = (ASMSource) t; + } else if (t instanceof TagScript) { + TagScript ts = (TagScript) t; + if (ts.getTag() instanceof ASMSource) { + as = (ASMSource) ts.getTag(); + } + } + if (as != null) { + SWF s = as.getSourceTag().getSwf(); + String asId = null; + Map allSources; + if (swfToAllASMSourceMap.containsKey(s)) { + allSources = swfToAllASMSourceMap.get(s); + } else { + allSources = s.getASMs(false); + } + for (String path : allSources.keySet()) { + if (allSources.get(path) == as) { + asId = path; + break; + } + } + if (!scopeAs12.containsKey(s)) { + scopeAs12.put(s, new LinkedHashMap<>()); + } + scopeAs12.get(s).put(asId, as); + swfsUsed.add(s); + } + } + + List items = tagTree.getSelected(); + String selected; + + if (scopeAs12.isEmpty() && scopeAs3.isEmpty()) { + selected = null; + } else if (items.size() == 1) { + selected = items.get(0).toString(); + } else if (items.isEmpty()) { + selected = null; + } else { + selected = AppDialog.translateForDialog("scope.selection.nodes", SearchDialog.class).replace("%count%", "" + items.size()); + } + + + SearchDialog searchDialog = new SearchDialog(getMainFrame().getWindow(), false, selected); if (searchInText != null) { if (searchInText) { searchDialog.searchInTextsRadioButton.setSelected(true); @@ -1774,12 +1853,44 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se if (searchDialog.showDialog() == AppDialog.OK_OPTION) { final String txt = searchDialog.searchField.getText(); if (!txt.isEmpty()) { - if (swf.isAS3()) { + if (!scopeAs3.isEmpty()) { getABCPanel(); - } else { + } + if (!scopeAs12.isEmpty()) { getActionPanel(); } + if (searchDialog.getCurrentScope() == SearchDialog.SCOPE_CURRENT_FILE) { + scopeAs3.clear(); + scopeAs12.clear(); + if (swf.isAS3()) { + scopeAs3.put(swf, swf.getAS3Packs()); + } else { + scopeAs12.put(swf, swf.getASMs(false)); + } + swfsUsed.clear(); + swfsUsed.add(swf); + } + if (searchDialog.getCurrentScope() == SearchDialog.SCOPE_ALL_FILES) { + List allSwfs = new ArrayList<>(); + for (SWFList slist : getSwfs()) { + for (SWF s : slist.swfs) { + allSwfs.add(s); + populateSwfs(s, allSwfs); + } + } + + for (SWF s : allSwfs) { + if (s.isAS3()) { + scopeAs3.put(s, s.getAS3Packs()); + } else { + scopeAs12.put(s, s.getASMs(false)); + } + } + swfsUsed.clear(); + swfsUsed.addAll(allSwfs); + } + boolean ignoreCase = searchDialog.ignoreCaseCheckBox.isSelected(); boolean regexp = searchDialog.regexpCheckBox.isSelected(); @@ -1790,41 +1901,37 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se new CancellableWorker() { @Override protected Void doInBackground() throws Exception { - List abcResult = null; - List actionResult = null; - if (swf.isAS3()) { - abcResult = getABCPanel().search(swf, txt, ignoreCase, regexp, pCodeSearch, this); - } else { - actionResult = getActionPanel().search(swf, txt, ignoreCase, regexp, pCodeSearch, this); + + List fResult = new ArrayList<>(); + for (SWF s : swfsUsed) { + if (scopeAs3.containsKey(s)) { + List abcResult = getABCPanel().search(s, txt, ignoreCase, regexp, pCodeSearch, this, scopeAs3.get(s)); + fResult.addAll(abcResult); + Main.searchResultsStorage.addABCResults(s, txt, ignoreCase, regexp, abcResult); + } + if (scopeAs12.containsKey(s)) { + List actionResult = getActionPanel().search(s, txt, ignoreCase, regexp, pCodeSearch, this, scopeAs12.get(s)); + fResult.addAll(actionResult); + Main.searchResultsStorage.addActionResults(s, txt, ignoreCase, regexp, actionResult); + } } - List fAbcResult = abcResult; - List fActionResult = actionResult; View.execInEventDispatch(() -> { boolean found = false; - if (fAbcResult != null) { - found = true; - SearchResultsDialog sr = new SearchResultsDialog<>(getMainFrame().getWindow(), txt, ignoreCase, regexp, getABCPanel()); - sr.setResults(fAbcResult); - sr.setVisible(true); - if (!searchResultsDialogs.containsKey(swf)) { - searchResultsDialogs.put(swf, new ArrayList<>()); + found = true; + List> listeners = new ArrayList<>(); + listeners.add(getABCPanel()); + listeners.add(getActionPanel()); + SearchResultsDialog sr = new SearchResultsDialog<>(getMainFrame().getWindow(), txt, ignoreCase, regexp, listeners); + sr.setResults(fResult); + sr.setVisible(true); + if (swfsUsed.size() == 1) { + SWF usedSwf = swfsUsed.iterator().next(); + if (!searchResultsDialogs.containsKey(usedSwf)) { + searchResultsDialogs.put(usedSwf, new ArrayList<>()); } - searchResultsDialogs.get(swf).add(sr); - Main.searchResultsStorage.addABCResults(swf, txt, ignoreCase, regexp, fAbcResult); - } else if (fActionResult != null) { - found = true; - - SearchResultsDialog sr = new SearchResultsDialog<>(getMainFrame().getWindow(), txt, ignoreCase, regexp, getActionPanel()); - sr.setResults(fActionResult); - sr.setVisible(true); - if (!searchResultsDialogs.containsKey(swf)) { - searchResultsDialogs.put(swf, new ArrayList<>()); - } - searchResultsDialogs.get(swf).add(sr); - Main.searchResultsStorage.addActionResults(swf, txt, ignoreCase, regexp, fActionResult); + searchResultsDialogs.get(usedSwf).add(sr); } - if (!found) { View.showMessageDialog(null, translate("message.search.notfound").replace("%searchtext%", txt), translate("message.search.notfound.title"), JOptionPane.INFORMATION_MESSAGE); } @@ -1881,7 +1988,18 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } public void replaceText() { - SearchDialog replaceDialog = new SearchDialog(getMainFrame().getWindow(), true); + + List items = tagTree.getSelected(); + String selected; + if (items.size() == 1) { + selected = items.get(0).toString(); + } else if (items.isEmpty()) { + selected = null; + } else { + selected = AppDialog.translateForDialog("scope.selection.nodes", SearchDialog.class).replace("%count%", "" + items.size()); + } + + SearchDialog replaceDialog = new SearchDialog(getMainFrame().getWindow(), true, selected); if (replaceDialog.showDialog() == AppDialog.OK_OPTION) { final String txt = replaceDialog.searchField.getText(); if (!txt.isEmpty()) { diff --git a/src/com/jpexs/decompiler/flash/gui/SearchDialog.java b/src/com/jpexs/decompiler/flash/gui/SearchDialog.java index 1a7ae1ce6..9f24a6fd2 100644 --- a/src/com/jpexs/decompiler/flash/gui/SearchDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/SearchDialog.java @@ -22,6 +22,7 @@ import java.awt.FlowLayout; import java.awt.Image; import java.awt.Window; import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; @@ -30,6 +31,7 @@ import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; +import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; @@ -59,9 +61,25 @@ public class SearchDialog extends AppDialog { public JRadioButton searchInTextsRadioButton = new JRadioButton(translate("checkbox.searchText")); + private JComboBox scopeComboBox; + private int result = ERROR_OPTION; - public SearchDialog(Window owner, boolean replace) { + public static final int SCOPE_SELECTION = 0; + public static final int SCOPE_CURRENT_FILE = 1; + public static final int SCOPE_ALL_FILES = 2; + + public int getCurrentScope() { + int index = scopeComboBox.getSelectedIndex(); + + if (scopeComboBox.getModel().getSize() == 3) { + return index; + } else { + return 1 + index; + } + } + + public SearchDialog(Window owner, boolean replace, String selection) { super(owner); setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); ignoreCaseCheckBox.setSelected(true); @@ -89,6 +107,19 @@ public class SearchDialog extends AppDialog { cnt.add(panField); } + panField = new JPanel(new FlowLayout()); + List scopeItems = new ArrayList<>(); + if (selection != null) { + scopeItems.add(translate("scope.selection").replace("%selection%", selection)); + } + scopeItems.add(translate("scope.currentFile")); + scopeItems.add(translate("scope.allFiles")); + panField.add(new JLabel(translate("label.scope"))); + scopeComboBox = new JComboBox<>(scopeItems.toArray(new String[scopeItems.size()])); + panField.add(scopeComboBox); + + cnt.add(panField); + JPanel checkPanel = new JPanel(new FlowLayout()); checkPanel.add(ignoreCaseCheckBox); checkPanel.add(regexpCheckBox); @@ -112,6 +143,10 @@ public class SearchDialog extends AppDialog { rbPanel.add(searchInPCodeRadioButton); rbPanel.add(searchInTextsRadioButton); cnt.add(rbPanel); + + searchInASRadioButton.addActionListener(this::searchTypeActionPerformed); + searchInPCodeRadioButton.addActionListener(this::searchTypeActionPerformed); + searchInTextsRadioButton.addActionListener(this::searchTypeActionPerformed); } cnt.add(panButtons); @@ -127,6 +162,19 @@ public class SearchDialog extends AppDialog { setIconImages(images); } + private void searchTypeActionPerformed(ActionEvent e) { + if (searchInTextsRadioButton.isSelected()) { + if (scopeComboBox.getModel().getSize() == 3) { + scopeComboBox.setSelectedIndex(1); + } else { + scopeComboBox.setSelectedIndex(0); + } + scopeComboBox.setEnabled(false); + } else { + scopeComboBox.setEnabled(true); + } + } + @Override public void setVisible(boolean b) { if (b) { diff --git a/src/com/jpexs/decompiler/flash/gui/SearchResultsDialog.java b/src/com/jpexs/decompiler/flash/gui/SearchResultsDialog.java index 691db0924..a3e6cb461 100644 --- a/src/com/jpexs/decompiler/flash/gui/SearchResultsDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/SearchResultsDialog.java @@ -48,7 +48,7 @@ public class SearchResultsDialog extends AppDialog { private final DefaultListModel model; private final boolean regExp; - private final SearchListener listener; + private final List> listeners; private final JButton gotoButton = new JButton(translate("button.goto")); @@ -57,7 +57,7 @@ public class SearchResultsDialog extends AppDialog { private String text; private final boolean ignoreCase; - public SearchResultsDialog(Window owner, String text, boolean ignoreCase, boolean regExp, SearchListener listener) { + public SearchResultsDialog(Window owner, String text, boolean ignoreCase, boolean regExp, List> listeners) { super(owner); setTitle(translate("dialog.title").replace("%text%", text)); this.text = text; @@ -65,7 +65,7 @@ public class SearchResultsDialog extends AppDialog { model = new DefaultListModel<>(); resultsList = new JList<>(model); this.regExp = regExp; - this.listener = listener; + this.listeners = listeners; gotoButton.addActionListener(this::gotoButtonActionPerformed); closeButton.addActionListener(this::closeButtonActionPerformed); @@ -129,7 +129,9 @@ public class SearchResultsDialog extends AppDialog { private void gotoElement() { if (resultsList.getSelectedIndex() != -1) { - listener.updateSearchPos(text, ignoreCase, regExp, resultsList.getSelectedValue()); + for (SearchListener listener : listeners) { + listener.updateSearchPos(text, ignoreCase, regExp, resultsList.getSelectedValue()); + } } } } diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index 5eaf0fae7..0e3bf06e3 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -76,6 +76,7 @@ import com.jpexs.decompiler.flash.importers.FFDecAs3ScriptReplacer; import com.jpexs.decompiler.flash.search.ABCSearchResult; import com.jpexs.decompiler.flash.search.ActionScriptSearch; import com.jpexs.decompiler.flash.search.ScriptSearchListener; +import com.jpexs.decompiler.flash.search.ScriptSearchResult; import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.treeitems.TreeItem; @@ -140,7 +141,7 @@ import jsyntaxpane.TokenType; * * @author JPEXS */ -public class ABCPanel extends JPanel implements ItemListener, SearchListener, TagEditorPanel { +public class ABCPanel extends JPanel implements ItemListener, SearchListener, TagEditorPanel { private As3ScriptReplacerInterface scriptReplacer = null; @@ -174,7 +175,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener searchPanel; + public final SearchPanel searchPanel; private NewTraitDialog newTraitDialog; @@ -198,7 +199,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener search(final SWF swf, final String txt, boolean ignoreCase, boolean regexp, boolean pcode, CancellableWorker worker) { + public List search(final SWF swf, final String txt, boolean ignoreCase, boolean regexp, boolean pcode, CancellableWorker worker, List scope) { if (txt != null && !txt.isEmpty()) { searchPanel.setOptions(ignoreCase, regexp); @@ -214,7 +215,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener, TagEditorPanel { +public class ActionPanel extends JPanel implements SearchListener, TagEditorPanel { private static final Logger logger = Logger.getLogger(ActionPanel.class.getName()); @@ -171,7 +173,7 @@ public class ActionPanel extends JPanel implements SearchListener searchPanel; + public SearchPanel searchPanel; private CancellableWorker setSourceWorker; @@ -276,7 +278,7 @@ public class ActionPanel extends JPanel implements SearchListener search(SWF swf, final String txt, boolean ignoreCase, boolean regexp, boolean pcode, CancellableWorker worker) { + public List search(SWF swf, final String txt, boolean ignoreCase, boolean regexp, boolean pcode, CancellableWorker worker, Map scope) { if (txt != null && !txt.isEmpty()) { searchPanel.setOptions(ignoreCase, regexp); @@ -292,7 +294,7 @@ public class ActionPanel extends JPanel implements SearchListener sel = tagTree.getSelected(); if (!sel.isEmpty()) {