diff --git a/CHANGELOG.md b/CHANGELOG.md
index 541949db0..74523da1a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
### Added
- SoundStreamHead has associated sprite id in its name in the tagtree
- [#1485] Improved skins support, night mode
+- [#1681] AS3 - context menu for adding classes on packages
## [14.4.0] - 2021-04-05
### Added
@@ -2190,6 +2191,7 @@ All notable changes to this project will be documented in this file.
[alpha 8]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha7...alpha8
[alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7
[#1485]: https://www.free-decompiler.com/flash/issues/1485
+[#1681]: https://www.free-decompiler.com/flash/issues/1681
[#1015]: https://www.free-decompiler.com/flash/issues/1015
[#1466]: https://www.free-decompiler.com/flash/issues/1466
[#1513]: https://www.free-decompiler.com/flash/issues/1513
diff --git a/src/com/jpexs/decompiler/flash/gui/abc/AddClassDialog.java b/src/com/jpexs/decompiler/flash/gui/abc/AddClassDialog.java
new file mode 100644
index 000000000..cb8142e47
--- /dev/null
+++ b/src/com/jpexs/decompiler/flash/gui/abc/AddClassDialog.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2021 JPEXS
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.jpexs.decompiler.flash.gui.abc;
+
+import com.jpexs.decompiler.flash.SWF;
+import com.jpexs.decompiler.flash.abc.ScriptPack;
+import com.jpexs.decompiler.flash.gui.AppDialog;
+import com.jpexs.decompiler.flash.gui.Main;
+import com.jpexs.decompiler.flash.gui.View;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.FlowLayout;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+/**
+ *
+ * @author JPEXS
+ */
+public class AddClassDialog extends AppDialog {
+
+ private final JButton okButton = new JButton(translate("button.ok"));
+ private final JButton cancelButton = new JButton(translate("button.cancel"));
+
+ private final JTextField classNameTextField = new JTextField(30);
+ private String result = null;
+
+ public AddClassDialog(Window owner) {
+ super(owner);
+ setDefaultCloseOperation(HIDE_ON_CLOSE);
+ setTitle(translate("dialog.title"));
+
+ Container cnt = getContentPane();
+ cnt.setLayout(new BoxLayout(cnt, BoxLayout.Y_AXIS));
+
+ JPanel panButtons = new JPanel(new FlowLayout());
+ okButton.addActionListener(this::okButtonActionPerformed);
+ cancelButton.addActionListener(this::cancelButtonActionPerformed);
+ panButtons.add(okButton);
+ panButtons.add(cancelButton);
+
+ JLabel classNameLabel = new JLabel(translate("classname"));
+ classNameLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
+ cnt.add(classNameLabel);
+ cnt.add(classNameTextField);
+
+ cnt.add(panButtons);
+
+ classNameTextField.getDocument().addDocumentListener(new DocumentListener() {
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ checkEnabled();
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ checkEnabled();
+ }
+
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ checkEnabled();
+ }
+ });
+
+ classNameTextField.addActionListener(this::okButtonActionPerformed);
+
+ pack();
+ setModal(true);
+ setResizable(false);
+ View.setWindowIcon(this);
+ View.centerScreen(this);
+ checkEnabled();
+ }
+
+ private void checkEnabled() {
+
+ boolean ok = true;
+
+ if (classNameTextField.getText().isEmpty()) {
+ ok = false;
+ }
+
+ if (classNameTextField.getText().endsWith(".")) {
+ ok = false;
+ }
+
+ if (ok) {
+ SWF swf = Main.getMainFrame().getPanel().getCurrentSwf();
+ List classNames = new ArrayList<>();
+ classNames.add(classNameTextField.getText());
+ try {
+ List scriptPacks = swf.getScriptPacksByClassNames(classNames);
+ if (!scriptPacks.isEmpty()) {
+ ok = false;
+ }
+ } catch (Exception ex) {
+ ok = false;
+ }
+ }
+
+ okButton.setEnabled(ok);
+ }
+
+ private void okButtonActionPerformed(ActionEvent evt) {
+ if (!okButton.isEnabled()) {
+ return;
+ }
+ result = classNameTextField.getText();
+ setVisible(false);
+ }
+
+ private void cancelButtonActionPerformed(ActionEvent evt) {
+ result = null;
+ setVisible(false);
+ }
+
+ public String showDialog() {
+ return showDialog("");
+ }
+ public String showDialog(String pkg) {
+ classNameTextField.setText(pkg);
+ result = null;
+ setVisible(true);
+ return result;
+ }
+}
diff --git a/src/com/jpexs/decompiler/flash/gui/locales/abc/AddClassDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/abc/AddClassDialog.properties
new file mode 100644
index 000000000..0b8a039d1
--- /dev/null
+++ b/src/com/jpexs/decompiler/flash/gui/locales/abc/AddClassDialog.properties
@@ -0,0 +1,20 @@
+# Copyright (C) 2021 JPEXS
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+dialog.title = Add script
+button.ok = OK
+button.cancel = Cancel
+
+classname = Fully qualified class name:
\ No newline at end of file
diff --git a/src/com/jpexs/decompiler/flash/gui/locales/abc/AddClassDialog_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/abc/AddClassDialog_cs.properties
new file mode 100644
index 000000000..f85ee5568
--- /dev/null
+++ b/src/com/jpexs/decompiler/flash/gui/locales/abc/AddClassDialog_cs.properties
@@ -0,0 +1,20 @@
+# Copyright (C) 2021 JPEXS
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+dialog.title = P\u0159idat skript
+button.ok = OK
+button.cancel = Storno
+
+classname = Pln\u011b kvalifikovan\u00fd n\u00e1zev t\u0159\u00eddy:
diff --git a/src/com/jpexs/decompiler/flash/gui/locales/abc/AddClassDialog_ja.properties b/src/com/jpexs/decompiler/flash/gui/locales/abc/AddClassDialog_ja.properties
new file mode 100644
index 000000000..a18c76962
--- /dev/null
+++ b/src/com/jpexs/decompiler/flash/gui/locales/abc/AddClassDialog_ja.properties
@@ -0,0 +1,20 @@
+# Copyright (C) 2021 JPEXS
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+dialog.title = \u30b9\u30af\u30ea\u30d7\u30c8\u3092\u8ffd\u52a0
+button.ok = OK
+button.cancel = \u30ad\u30e3\u30f3\u30bb\u30eb
+
+classname = \u5b8c\u5168\u4fee\u98fe\u30af\u30e9\u30b9\u540d (\u30d1\u30c3\u30b1\u30fc\u30b8\u3082\u542b\u3081\u305f\u30af\u30e9\u30b9\u540d):
\ No newline at end of file
diff --git a/src/com/jpexs/decompiler/flash/gui/locales/abc/AddClassDialog_zh.properties b/src/com/jpexs/decompiler/flash/gui/locales/abc/AddClassDialog_zh.properties
new file mode 100644
index 000000000..2da649b96
--- /dev/null
+++ b/src/com/jpexs/decompiler/flash/gui/locales/abc/AddClassDialog_zh.properties
@@ -0,0 +1,4 @@
+dialog.title = \u6dfb\u52a0\u811a\u672c
+button.ok = \u786e\u5b9a
+button.cancel = \u53d6\u6d88
+classname = \u5168\u9650\u5b9a\u7c7b\u540d
diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java
index 99f5402c5..3a2807b95 100644
--- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java
+++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java
@@ -32,6 +32,7 @@ import com.jpexs.decompiler.flash.gui.MainPanel;
import com.jpexs.decompiler.flash.gui.ReplaceCharacterDialog;
import com.jpexs.decompiler.flash.gui.View;
import com.jpexs.decompiler.flash.gui.ViewMessages;
+import com.jpexs.decompiler.flash.gui.abc.AddClassDialog;
import com.jpexs.decompiler.flash.gui.abc.ClassesListTreeModel;
import com.jpexs.decompiler.flash.gui.action.AddScriptDialog;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
@@ -498,6 +499,9 @@ public class TagTreeContextMenu extends JPopupMenu {
if (firstItem instanceof ClassesListTreeModel) {
addAs3ClassMenuItem.setVisible(true);
}
+ if (firstItem instanceof AS3Package) {
+ addAs3ClassMenuItem.setVisible(true);
+ }
if (firstItem instanceof CharacterTag) {
replaceWithTagMenuItem.setVisible(true);
@@ -840,29 +844,37 @@ public class TagTreeContextMenu extends JPopupMenu {
private void addAs3ClassActionPerformed(ActionEvent evt) {
List sel = tagTree.getSelected();
if (!sel.isEmpty()) {
+ SWF swf = null;
+ String preselected = "";
if (sel.get(0) instanceof ClassesListTreeModel) {
ClassesListTreeModel cl = (ClassesListTreeModel) sel.get(0);
- SWF swf = cl.getSwf();
- String className = "";
- String parts[];
- loopinput:
- while (true) {
- className = ViewMessages.showInputDialog(mainPanel, AppDialog.translateForDialog("classname", AddScriptDialog.class), className);
- if (className == null || className.isEmpty()) {
- return;
+ swf = cl.getSwf();
+ }
+ if (sel.get(0) instanceof AS3Package) {
+ AS3Package pkg = (AS3Package) sel.get(0);
+ swf = pkg.getSwf();
+ TreePath tp = tagTree.getSelectionPaths()[0];
+ Object[] path = tp.getPath();
+ for (int p = path.length - 1; p >= 0; p--) {
+ if (path[p] instanceof ClassesListTreeModel) {
+ break;
}
-
-
- parts = className.contains(".") ? className.split("\\.") : new String[]{className};
- DottedChain classNameDc = new DottedChain(parts, "");
- for (ABCContainerTag ct : swf.getAbcList()) {
- if (ct.getABC().findClassByName(classNameDc) > -1) {
- ViewMessages.showMessageDialog(mainPanel, AppDialog.translateForDialog("message.classexists", AddScriptDialog.class), mainPanel.translate("error"), JOptionPane.ERROR_MESSAGE);
- continue loopinput;
- }
- }
- break;
+ preselected = ((AS3Package) path[p]).packageName + "." + preselected;
}
+ }
+
+ TreePath scriptsPath = tagTree.getSelectionPaths()[0];
+ while (!(scriptsPath.getLastPathComponent() instanceof ClassesListTreeModel)) {
+ scriptsPath = scriptsPath.getParentPath();
+ }
+
+ {
+ AddClassDialog acd = new AddClassDialog(Main.getDefaultDialogsOwner());
+ String className = acd.showDialog(preselected);
+ if (className == null) {
+ return;
+ }
+ String[] parts = className.contains(".") ? className.split("\\.") : new String[]{className};
DoABC2Tag doAbc = new DoABC2Tag(swf);
doAbc.setTimelined(swf);
@@ -917,9 +929,6 @@ public class TagTreeContextMenu extends JPopupMenu {
Object item = mainPanel.tagTree.getModel().getScriptsNode(swf);
- TreePath selection = mainPanel.tagTree.getSelectionPath();
- TreePath swfPath = selection.getParentPath();
- TreePath scriptsPath = swfPath.pathByAddingChild(item);
TreePath classPath = scriptsPath;
for (int i = 0; i < parts.length; i++) {