Added #1870 AS3 Adding new class - Target DoABC tag or position can be selected to prevent Error 1014

This commit is contained in:
Jindra Petřík
2022-11-16 18:07:45 +01:00
parent c0f9fd4fcc
commit 30fbef178d
9 changed files with 339 additions and 39 deletions

View File

@@ -2,6 +2,9 @@
All notable changes to this project will be documented in this file.
## [Unreleased]
### Added
- [#1870] AS3 Adding new class - Target DoABC tag or position can be selected to prevent Error 1014
### Fixed
- [#1869] Replace references now replaces all references, not just PlaceObject
- Handle StartSound tag as CharacterIdTag
@@ -2581,6 +2584,7 @@ All notable changes to this project will be documented in this file.
[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
[#1870]: https://www.free-decompiler.com/flash/issues/1870
[#1869]: https://www.free-decompiler.com/flash/issues/1869
[#1867]: https://www.free-decompiler.com/flash/issues/1867
[#1868]: https://www.free-decompiler.com/flash/issues/1868

View File

@@ -36,6 +36,8 @@ public abstract class AppDialog extends JDialog {
private ResourceBundle resourceBundle = ResourceBundle.getBundle(AppStrings.getResourcePath(getClass()));
protected Window owner;
/*public AppDialog() {
View.installEscapeCloseOperation(this);
if (Configuration.useRibbonInterface.get()) {
@@ -45,6 +47,7 @@ public abstract class AppDialog extends JDialog {
public AppDialog(Window owner) {
super(owner);
this.owner = owner;
View.installEscapeCloseOperation(this);
if (Configuration.useRibbonInterface.get()) {
getRootPane().setWindowDecorationStyle(JRootPane.FRAME);

View File

@@ -20,7 +20,11 @@ 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.SelectTagPositionDialog;
import com.jpexs.decompiler.flash.gui.View;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.timeline.Timelined;
import java.awt.Component;
import java.awt.Container;
import java.awt.FlowLayout;
@@ -29,12 +33,17 @@ import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.basic.BasicMenuUI;
/**
*
@@ -42,32 +51,80 @@ import javax.swing.event.DocumentListener;
*/
public class AddClassDialog extends AppDialog {
private final JButton okButton = new JButton(translate("button.ok"));
private final JButton proceedButton = new JButton(translate("button.proceed"));
private final JButton cancelButton = new JButton(translate("button.cancel"));
private final JTextField classNameTextField = new JTextField(30);
private String result = null;
private String selectedClass = null;
private ABCContainerTag selectedAbcContainer;
private Tag selectedPosition;
private Timelined selectedTimelined;
private int result = ERROR_OPTION;
private SWF swf;
private int abcCount = 0;
private JRadioButton existingAbcTagRadioButton = new JRadioButton(translate("abc.where.existing"));
private JRadioButton newAbcTagRadioButton = new JRadioButton(translate("abc.where.new"));
public AddClassDialog(Window owner) {
public AddClassDialog(Window owner, SWF swf) {
super(owner);
this.swf = swf;
abcCount = 0;
for(Tag t : swf.getTags()) {
if (t instanceof ABCContainerTag) {
abcCount++;
}
}
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);
JPanel abcTargetPanel = new JPanel();
abcTargetPanel.setLayout(new BoxLayout(abcTargetPanel, BoxLayout.Y_AXIS));
abcTargetPanel.add(new JLabel(translate("abc.where")));
existingAbcTagRadioButton.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
checkEnabled();
}
});
newAbcTagRadioButton.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
checkEnabled();
}
});
ButtonGroup abcTargetButtonGroup = new ButtonGroup();
abcTargetButtonGroup.add(existingAbcTagRadioButton);
abcTargetButtonGroup.add(newAbcTagRadioButton);
existingAbcTagRadioButton.setSelected(true);
abcTargetPanel.add(existingAbcTagRadioButton);
abcTargetPanel.add(newAbcTagRadioButton);
if (abcCount == 0) {
newAbcTagRadioButton.setSelected(true);
abcTargetPanel.setVisible(false);
}
JPanel buttonsPanel = new JPanel(new FlowLayout());
proceedButton.addActionListener(this::okButtonActionPerformed);
cancelButton.addActionListener(this::cancelButtonActionPerformed);
panButtons.add(okButton);
panButtons.add(cancelButton);
buttonsPanel.add(proceedButton);
buttonsPanel.add(cancelButton);
JLabel classNameLabel = new JLabel(translate("classname"));
classNameLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
classNameLabel.setAlignmentX(JLabel.CENTER);
cnt.add(classNameLabel);
cnt.add(classNameTextField);
cnt.add(abcTargetPanel);
cnt.add(panButtons);
cnt.add(buttonsPanel);
classNameTextField.getDocument().addDocumentListener(new DocumentListener() {
@Override
@@ -97,7 +154,14 @@ public class AddClassDialog extends AppDialog {
}
private void checkEnabled() {
if (existingAbcTagRadioButton.isSelected() && abcCount == 1) {
proceedButton.setText(translate("button.ok"));
} else {
proceedButton.setText(translate("button.proceed"));
}
boolean ok = true;
if (classNameTextField.getText().isEmpty()) {
@@ -122,29 +186,72 @@ public class AddClassDialog extends AppDialog {
}
}
okButton.setEnabled(ok);
proceedButton.setEnabled(ok);
}
private void okButtonActionPerformed(ActionEvent evt) {
if (!okButton.isEnabled()) {
if (!proceedButton.isEnabled()) {
return;
}
result = classNameTextField.getText();
setVisible(false);
if (existingAbcTagRadioButton.isSelected()) {
SelectDoABCDialog selectDoABCDialog = new SelectDoABCDialog(owner, swf);
selectedAbcContainer = selectDoABCDialog.showDialog();
if (selectedAbcContainer == null) {
cancelButtonActionPerformed(evt);
return;
}
}
if (newAbcTagRadioButton.isSelected()) {
SelectTagPositionDialog selectTagPositionDialog = new SelectTagPositionDialog(owner, swf, true);
if (selectTagPositionDialog.showDialog() != OK_OPTION) {
cancelButtonActionPerformed(evt);
return;
}
selectedPosition = selectTagPositionDialog.getSelectedTag();
selectedTimelined = selectTagPositionDialog.getSelectedTimelined();
}
result = OK_OPTION;
selectedClass = classNameTextField.getText();
setVisible(false);
}
private void cancelButtonActionPerformed(ActionEvent evt) {
result = null;
selectedClass = null;
selectedAbcContainer = null;
selectedPosition = null;
selectedTimelined = null;
result = CANCEL_OPTION;
setVisible(false);
}
public String showDialog() {
public int showDialog() {
return showDialog("");
}
public String showDialog(String pkg) {
public int showDialog(String pkg) {
classNameTextField.setText(pkg);
result = null;
selectedClass = null;
selectedAbcContainer = null;
selectedPosition = null;
selectedTimelined = null;
setVisible(true);
return result;
}
public Tag getSelectedPosition() {
return selectedPosition;
}
public String getSelectedClass() {
return selectedClass;
}
public Timelined getSelectedTimelined() {
return selectedTimelined;
}
public ABCContainerTag getSelectedAbcContainer() {
return selectedAbcContainer;
}
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui.abc;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.gui.AppDialog;
import com.jpexs.decompiler.flash.gui.TreeNodeType;
import com.jpexs.decompiler.flash.gui.View;
import com.jpexs.decompiler.flash.gui.tagtree.TagTree;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.decompiler.flash.tags.Tag;
import java.awt.Component;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import javax.swing.BoxLayout;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
/**
*
* @author JPEXS
*/
public class SelectDoABCDialog extends AppDialog {
private JComboBox<ComboItem> abcComboBox;
private ABCContainerTag result = null;
public SelectDoABCDialog(Window window, SWF swf) {
super(window);
setTitle(translate("dialog.title"));
Container cnt = getContentPane();
abcComboBox = new JComboBox<>();
int pos = 0;
for(Tag t : swf.getTags()) {
if (t instanceof ABCContainerTag) {
abcComboBox.addItem(new ComboItem(pos, (ABCContainerTag) t));
pos++;
}
}
abcComboBox.setRenderer(new DefaultListCellRenderer(){
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
label.setIcon(TagTree.getIconForType(TreeNodeType.AS));
label.setText(value.toString());
return label;
}
});
JButton okButton = new JButton(translate("button.ok"));
okButton.addActionListener(this::okButtonActionPerformed);
JButton cancelButton = new JButton(translate("button.cancel"));
cancelButton.addActionListener(this::cancelButtonActionPerformed);
JPanel buttonsPanel = new JPanel(new FlowLayout());
buttonsPanel.add(okButton);
buttonsPanel.add(cancelButton);
cnt.setLayout(new BoxLayout(cnt, BoxLayout.Y_AXIS));
cnt.add(abcComboBox);
cnt.add(buttonsPanel);
pack();
setModal(true);
setResizable(false);
View.setWindowIcon(this);
View.centerScreen(this);
}
public ABCContainerTag getResult() {
return result;
}
@SuppressWarnings("unchecked")
private void okButtonActionPerformed(ActionEvent evt) {
result = ((ComboItem) abcComboBox.getSelectedItem()).abc;
setVisible(false);
}
private void cancelButtonActionPerformed(ActionEvent evt) {
result = null;
setVisible(false);
}
public ABCContainerTag showDialog() {
result = null;
if (abcComboBox.getItemCount() == 0) {
return null;
}
if (abcComboBox.getItemCount() == 1) {
result = abcComboBox.getItemAt(0).abc;
return result;
}
setVisible(true);
return result;
}
}
class ComboItem {
public int index;
public ABCContainerTag abc;
public ComboItem(int index, ABCContainerTag abc) {
this.index = index;
this.abc = abc;
}
@Override
public String toString() {
return "" + (index + 1) +". " + abc.toString();
}
}

View File

@@ -17,4 +17,10 @@ dialog.title = Add script
button.ok = OK
button.cancel = Cancel
classname = Fully qualified class name:
classname = Fully qualified class name:
#after 16.3.1
button.proceed = Proceed
abc.where = Where to create byte code:
abc.where.existing = Existing DoABC tag
abc.where.new = New DoABC tag

View File

@@ -18,3 +18,9 @@ button.ok = OK
button.cancel = Storno
classname = Pln\u011b kvalifikovan\u00fd n\u00e1zev t\u0159\u00eddy:
#after 16.3.1
button.proceed = Pokra\u010dovat
abc.where = Kam um\u00edstit byte k\u00f3d:
abc.where.existing = Existuj\u00edc\u00ed DoABC tag
abc.where.new = Nov\u00fd DoABC tag

View File

@@ -0,0 +1,18 @@
# Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
dialog.title = Select DoABC tag
button.ok = OK
button.cancel = Cancel

View File

@@ -0,0 +1,18 @@
# Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
dialog.title = Vyberte DoABC tag
button.ok = OK
button.cancel = Storno

View File

@@ -1570,35 +1570,35 @@ public class TagTreeContextMenu extends JPopupMenu {
}
{
AddClassDialog acd = new AddClassDialog(Main.getDefaultDialogsOwner());
String className = acd.showDialog(preselected);
if (className == null) {
AddClassDialog acd = new AddClassDialog(Main.getDefaultDialogsOwner(), swf);
if (acd.showDialog(preselected) != AppDialog.OK_OPTION) {
return;
}
String className = acd.getSelectedClass();
String[] parts = className.contains(".") ? className.split("\\.") : new String[]{className};
DoABC2Tag doAbc = new DoABC2Tag(swf);
doAbc.setTimelined(swf);
doAbc.name = className;
ABCContainerTag doAbc = acd.getSelectedAbcContainer();
if (doAbc == null) {
DoABC2Tag doAbc2 = new DoABC2Tag(swf);
Timelined timelined = acd.getSelectedTimelined();
Tag position = acd.getSelectedPosition();
if (position == null) {
timelined.addTag(doAbc2);
} else {
timelined.addTag(timelined.indexOfTag(position), doAbc2);
}
doAbc2.setTimelined(acd.getSelectedTimelined());
doAbc2.name = className;
doAbc = doAbc2;
}
List<ABC> abcs = new ArrayList<>();
for (ABCContainerTag ct : swf.getAbcList()) {
abcs.add(ct.getABC());
}
ReadOnlyTagList tags = swf.getTags();
int insertPos = -1;
for (int i = 0; i < tags.size(); i++) {
if (tags.get(i) instanceof ShowFrameTag) {
insertPos = i;
break;
}
}
if (insertPos == -1) {
insertPos = tags.size();
}
swf.addTag(insertPos, doAbc);
String pkg = className.contains(".") ? className.substring(0, className.lastIndexOf(".")) : "";
String classSimpleName = className.contains(".") ? className.substring(className.lastIndexOf(".") + 1) : className;
String fileName = className.replace(".", "/");
@@ -1623,7 +1623,7 @@ public class TagTreeContextMenu extends JPopupMenu {
Logger.getLogger(TagTreeContextMenu.class.getName()).log(Level.SEVERE, "Error during script compilation", ex);
}
doAbc.setModified(true);
((Tag)doAbc).setModified(true);
swf.clearAllCache();
swf.setModified(true);
mainPanel.refreshTree(swf);