get needed characters refactored, get rid of innertags in showframe (using Timelined instead), last frame bug fixed (when there is no ShowFrame tag after the last placeobject tags), remove characters from tags (without removing the whole tag) + organize imports, code formatting

This commit is contained in:
honfika
2014-05-26 16:10:36 +02:00
parent 8112d9206f
commit 63ebe7e476
145 changed files with 55567 additions and 55241 deletions
@@ -1,367 +1,364 @@
/*
* Copyright (C) 2010-2014 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;
import com.jpexs.decompiler.flash.AppStrings;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.configuration.ConfigurationCategory;
import com.jpexs.decompiler.flash.configuration.ConfigurationItem;
import com.jpexs.decompiler.flash.gui.helpers.SpringUtilities;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
import javax.swing.table.DefaultTableModel;
/**
*
* @author JPEXS
*/
public class AdvancedSettingsDialog extends AppDialog implements ActionListener {
private Map<String, Component> componentsMap = new HashMap<>();
/**
* Creates new form AdvancedSettingsDialog
*/
public AdvancedSettingsDialog() {
initComponents();
View.centerScreen(this);
View.setWindowIcon(this);
//configurationTable.setCellEditor(configurationTable.getDefaultEditor(null));
pack();
}
private DefaultTableModel getModel() {
return new javax.swing.table.DefaultTableModel(
new Object[][]{},
new String[]{
translate("advancedSettings.columns.name"),
translate("advancedSettings.columns.value"),
translate("advancedSettings.columns.description")
}
) {
Class[] types = new Class[]{
String.class, Object.class, String.class
};
boolean[] canEdit = new boolean[]{
false, true, false
};
@Override
public Class getColumnClass(int columnIndex) {
return types[columnIndex];
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return canEdit[columnIndex];
}
};
}
private void initComponents() {
okButton = new JButton();
cancelButton = new JButton();
resetButton = new JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle(translate("advancedSettings.dialog.title"));
setModal(true);
setPreferredSize(new java.awt.Dimension(800, 500));
okButton.setText(AppStrings.translate("button.ok"));
okButton.addActionListener(this);
okButton.setActionCommand("OK");
cancelButton.setText(AppStrings.translate("button.cancel"));
cancelButton.addActionListener(this);
cancelButton.setActionCommand("CANCEL");
resetButton.setText(AppStrings.translate("button.reset"));
resetButton.addActionListener(this);
resetButton.setActionCommand("RESET");
Container cnt = getContentPane();
cnt.setLayout(new BorderLayout());
//cnt.add(new JScrollPane(configurationTable),BorderLayout.CENTER);
JPanel buttonsPanel = new JPanel(new BorderLayout());
JPanel buttonsLeftPanel = new JPanel(new FlowLayout());
buttonsLeftPanel.add(resetButton, BorderLayout.WEST);
buttonsPanel.add(buttonsLeftPanel, BorderLayout.WEST);
JPanel buttonsRightPanel = new JPanel(new FlowLayout());
buttonsRightPanel.add(cancelButton);
buttonsRightPanel.add(okButton);
buttonsPanel.add(buttonsRightPanel, BorderLayout.EAST);
cnt.add(buttonsPanel, BorderLayout.SOUTH);
Map<String, Field> fields = Configuration.getConfigurationFields();
String[] keys = new String[fields.size()];
keys = fields.keySet().toArray(keys);
Arrays.sort(keys);
Map<String, Map<String, Field>> categorized = new HashMap<>();
for (String name : keys) {
Field field = fields.get(name);
ConfigurationCategory cat = field.getAnnotation(ConfigurationCategory.class);
String scat = cat == null?"other":cat.value();
if (!categorized.containsKey(scat)) {
categorized.put(scat, new HashMap<String, Field>());
}
categorized.get(scat).put(name, field);
}
JTabbedPane tabPane = new JTabbedPane();
Map<String,Component> tabs=new HashMap<>();
for (String cat : categorized.keySet()) {
JPanel configPanel = new JPanel(new SpringLayout());
for (String name : categorized.get(cat).keySet()) {
Field field = categorized.get(cat).get(name);
String locName = translate("config.name." + name);
try {
ConfigurationItem item = (ConfigurationItem) field.get(null);
ParameterizedType listType = (ParameterizedType) field.getGenericType();
Class itemType = (Class<?>) listType.getActualTypeArguments()[0];
/*String description = Configuration.getDescription(field);
if (description == null) {
description = "";
}*/
String description = translate("config.description." + name);
Object defaultValue = Configuration.getDefaultValue(field);
if (defaultValue != null) {
description += " (" + translate("default") + ": " + defaultValue + ")";
}
//model.addRow(new Object[]{locName, item.get(), description});
JLabel l = new JLabel(locName, JLabel.TRAILING);
l.setToolTipText(description);
configPanel.add(l);
Component c = null;
if ((itemType == String.class) || (itemType == Integer.class) || (itemType == Long.class) || (itemType == Double.class) || (itemType == Float.class) || (itemType == Calendar.class)) {
JTextField tf = new JTextField();
Object val = item.get();
if (val == null) {
val = "";
}
if (itemType == Calendar.class) {
tf.setText(new SimpleDateFormat().format(((Calendar) item.get()).getTime()));
} else {
tf.setText(val.toString());
}
tf.setToolTipText(description);
tf.setMaximumSize(new Dimension(Integer.MAX_VALUE,tf.getPreferredSize().height));
c = tf;
}
if (itemType == Boolean.class) {
JCheckBox cb = new JCheckBox();
cb.setSelected((Boolean) item.get());
cb.setToolTipText(description);
c = cb;
}
componentsMap.put(name, c);
l.setLabelFor(c);
configPanel.add(c);
} catch (IllegalArgumentException | IllegalAccessException ex) {
// Reflection exceptions. This should never happen
throw new Error(ex.getMessage());
}
}
SpringUtilities.makeCompactGrid(configPanel,
categorized.get(cat).size(), 2, //rows, cols
6, 6, //initX, initY
6, 6); //xPad, yPad
tabs.put(cat,new JScrollPane(configPanel));
}
String catOrder[] = new String[]{"ui","display","decompilation","script","format","export","limit","update","debug","other"};
for(String cat:catOrder){
if(!tabs.containsKey(cat)){
continue;
}
tabPane.add(translate("config.group.name."+cat),tabs.get(cat));
tabPane.setToolTipTextAt(tabPane.getTabCount()-1, translate("config.group.description."+cat));
}
cnt.add(tabPane, BorderLayout.CENTER);
pack();
}
private void showRestartConfirmDialod() {
if (View.showConfirmDialog(this, translate("advancedSettings.restartConfirmation"), AppStrings.translate("message.warning"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
View.execInEventDispatchLater(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(AdvancedSettingsDialog.class.getName()).log(Level.SEVERE, null, ex);
}
SelectLanguageDialog.reloadUi();
}
});
}
}
private JButton cancelButton;
private JButton okButton;
private JButton resetButton;
//private EachRowRendererEditor configurationTable;
@Override
@SuppressWarnings("unchecked")
public void actionPerformed(ActionEvent e) {
switch (e.getActionCommand()) {
case "OK":
boolean modified = false;
Map<String, Field> fields = Configuration.getConfigurationFields();
Map<String, Object> values = new HashMap<>();
for (String name : fields.keySet()) {
Component c = componentsMap.get(name);
Object value = null;
ParameterizedType listType = (ParameterizedType) fields.get(name).getGenericType();
Class itemType = (Class<?>) listType.getActualTypeArguments()[0];
if (itemType == String.class) {
value = ((JTextField) c).getText();
}
if (itemType == Boolean.class) {
value = ((JCheckBox) c).isSelected();
}
if (itemType == Calendar.class) {
Calendar cal = Calendar.getInstance();
try {
cal.setTime(new SimpleDateFormat().parse(((JTextField) c).getText()));
} catch (ParseException ex) {
c.requestFocusInWindow();
return;
}
value = cal;
}
try {
if (itemType == Integer.class) {
value = Integer.parseInt(((JTextField) c).getText());
}
if (itemType == Long.class) {
value = Long.parseLong(((JTextField) c).getText());
}
if (itemType == Double.class) {
value = Double.parseDouble(((JTextField) c).getText());
}
if (itemType == Float.class) {
value = Float.parseFloat(((JTextField) c).getText());
}
} catch (NumberFormatException nfe) {
if (!((JTextField) c).getText().equals("")) {
c.requestFocusInWindow();
return;
}//else null
}
values.put(name, value);
}
for (String name : fields.keySet()) {
Component c = componentsMap.get(name);
Object value = values.get(name);
Field field = fields.get(name);
ConfigurationItem item = null;
try {
item = (ConfigurationItem) field.get(null);
} catch (IllegalArgumentException | IllegalAccessException ex) {
// Reflection exceptions. This should never happen
throw new Error(ex.getMessage());
}
if (item.get() != null && !item.get().equals(value)) {
item.set(value);
modified = true;
}
}
Configuration.saveConfig();
setVisible(false);
if (modified) {
showRestartConfirmDialod();
}
break;
case "CANCEL":
setVisible(false);
break;
case "RESET":
Map<String, Field> rfields = Configuration.getConfigurationFields();
for (Entry<String, Field> entry : rfields.entrySet()) {
String name = entry.getKey();
Field field = entry.getValue();
try {
ConfigurationItem item = (ConfigurationItem) field.get(null);
item.unset();
} catch (IllegalArgumentException | IllegalAccessException ex) {
// Reflection exceptions. This should never happen
throw new Error(ex.getMessage());
}
}
Configuration.saveConfig();
setVisible(false);
showRestartConfirmDialod();
break;
}
}
}
/*
* Copyright (C) 2010-2014 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;
import com.jpexs.decompiler.flash.AppStrings;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.configuration.ConfigurationCategory;
import com.jpexs.decompiler.flash.configuration.ConfigurationItem;
import com.jpexs.decompiler.flash.gui.helpers.SpringUtilities;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
import javax.swing.table.DefaultTableModel;
/**
*
* @author JPEXS
*/
public class AdvancedSettingsDialog extends AppDialog implements ActionListener {
private Map<String, Component> componentsMap = new HashMap<>();
/**
* Creates new form AdvancedSettingsDialog
*/
public AdvancedSettingsDialog() {
initComponents();
View.centerScreen(this);
View.setWindowIcon(this);
//configurationTable.setCellEditor(configurationTable.getDefaultEditor(null));
pack();
}
private DefaultTableModel getModel() {
return new javax.swing.table.DefaultTableModel(
new Object[][]{},
new String[]{
translate("advancedSettings.columns.name"),
translate("advancedSettings.columns.value"),
translate("advancedSettings.columns.description")
}
) {
Class[] types = new Class[]{
String.class, Object.class, String.class
};
boolean[] canEdit = new boolean[]{
false, true, false
};
@Override
public Class getColumnClass(int columnIndex) {
return types[columnIndex];
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return canEdit[columnIndex];
}
};
}
private void initComponents() {
okButton = new JButton();
cancelButton = new JButton();
resetButton = new JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle(translate("advancedSettings.dialog.title"));
setModal(true);
setPreferredSize(new java.awt.Dimension(800, 500));
okButton.setText(AppStrings.translate("button.ok"));
okButton.addActionListener(this);
okButton.setActionCommand("OK");
cancelButton.setText(AppStrings.translate("button.cancel"));
cancelButton.addActionListener(this);
cancelButton.setActionCommand("CANCEL");
resetButton.setText(AppStrings.translate("button.reset"));
resetButton.addActionListener(this);
resetButton.setActionCommand("RESET");
Container cnt = getContentPane();
cnt.setLayout(new BorderLayout());
//cnt.add(new JScrollPane(configurationTable),BorderLayout.CENTER);
JPanel buttonsPanel = new JPanel(new BorderLayout());
JPanel buttonsLeftPanel = new JPanel(new FlowLayout());
buttonsLeftPanel.add(resetButton, BorderLayout.WEST);
buttonsPanel.add(buttonsLeftPanel, BorderLayout.WEST);
JPanel buttonsRightPanel = new JPanel(new FlowLayout());
buttonsRightPanel.add(cancelButton);
buttonsRightPanel.add(okButton);
buttonsPanel.add(buttonsRightPanel, BorderLayout.EAST);
cnt.add(buttonsPanel, BorderLayout.SOUTH);
Map<String, Field> fields = Configuration.getConfigurationFields();
String[] keys = new String[fields.size()];
keys = fields.keySet().toArray(keys);
Arrays.sort(keys);
Map<String, Map<String, Field>> categorized = new HashMap<>();
for (String name : keys) {
Field field = fields.get(name);
ConfigurationCategory cat = field.getAnnotation(ConfigurationCategory.class);
String scat = cat == null ? "other" : cat.value();
if (!categorized.containsKey(scat)) {
categorized.put(scat, new HashMap<String, Field>());
}
categorized.get(scat).put(name, field);
}
JTabbedPane tabPane = new JTabbedPane();
Map<String, Component> tabs = new HashMap<>();
for (String cat : categorized.keySet()) {
JPanel configPanel = new JPanel(new SpringLayout());
for (String name : categorized.get(cat).keySet()) {
Field field = categorized.get(cat).get(name);
String locName = translate("config.name." + name);
try {
ConfigurationItem item = (ConfigurationItem) field.get(null);
ParameterizedType listType = (ParameterizedType) field.getGenericType();
Class itemType = (Class<?>) listType.getActualTypeArguments()[0];
/*String description = Configuration.getDescription(field);
if (description == null) {
description = "";
}*/
String description = translate("config.description." + name);
Object defaultValue = Configuration.getDefaultValue(field);
if (defaultValue != null) {
description += " (" + translate("default") + ": " + defaultValue + ")";
}
//model.addRow(new Object[]{locName, item.get(), description});
JLabel l = new JLabel(locName, JLabel.TRAILING);
l.setToolTipText(description);
configPanel.add(l);
Component c = null;
if ((itemType == String.class) || (itemType == Integer.class) || (itemType == Long.class) || (itemType == Double.class) || (itemType == Float.class) || (itemType == Calendar.class)) {
JTextField tf = new JTextField();
Object val = item.get();
if (val == null) {
val = "";
}
if (itemType == Calendar.class) {
tf.setText(new SimpleDateFormat().format(((Calendar) item.get()).getTime()));
} else {
tf.setText(val.toString());
}
tf.setToolTipText(description);
tf.setMaximumSize(new Dimension(Integer.MAX_VALUE, tf.getPreferredSize().height));
c = tf;
}
if (itemType == Boolean.class) {
JCheckBox cb = new JCheckBox();
cb.setSelected((Boolean) item.get());
cb.setToolTipText(description);
c = cb;
}
componentsMap.put(name, c);
l.setLabelFor(c);
configPanel.add(c);
} catch (IllegalArgumentException | IllegalAccessException ex) {
// Reflection exceptions. This should never happen
throw new Error(ex.getMessage());
}
}
SpringUtilities.makeCompactGrid(configPanel,
categorized.get(cat).size(), 2, //rows, cols
6, 6, //initX, initY
6, 6); //xPad, yPad
tabs.put(cat, new JScrollPane(configPanel));
}
String catOrder[] = new String[]{"ui", "display", "decompilation", "script", "format", "export", "limit", "update", "debug", "other"};
for (String cat : catOrder) {
if (!tabs.containsKey(cat)) {
continue;
}
tabPane.add(translate("config.group.name." + cat), tabs.get(cat));
tabPane.setToolTipTextAt(tabPane.getTabCount() - 1, translate("config.group.description." + cat));
}
cnt.add(tabPane, BorderLayout.CENTER);
pack();
}
private void showRestartConfirmDialod() {
if (View.showConfirmDialog(this, translate("advancedSettings.restartConfirmation"), AppStrings.translate("message.warning"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
View.execInEventDispatchLater(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(AdvancedSettingsDialog.class.getName()).log(Level.SEVERE, null, ex);
}
SelectLanguageDialog.reloadUi();
}
});
}
}
private JButton cancelButton;
private JButton okButton;
private JButton resetButton;
//private EachRowRendererEditor configurationTable;
@Override
@SuppressWarnings("unchecked")
public void actionPerformed(ActionEvent e) {
switch (e.getActionCommand()) {
case "OK":
boolean modified = false;
Map<String, Field> fields = Configuration.getConfigurationFields();
Map<String, Object> values = new HashMap<>();
for (String name : fields.keySet()) {
Component c = componentsMap.get(name);
Object value = null;
ParameterizedType listType = (ParameterizedType) fields.get(name).getGenericType();
Class itemType = (Class<?>) listType.getActualTypeArguments()[0];
if (itemType == String.class) {
value = ((JTextField) c).getText();
}
if (itemType == Boolean.class) {
value = ((JCheckBox) c).isSelected();
}
if (itemType == Calendar.class) {
Calendar cal = Calendar.getInstance();
try {
cal.setTime(new SimpleDateFormat().parse(((JTextField) c).getText()));
} catch (ParseException ex) {
c.requestFocusInWindow();
return;
}
value = cal;
}
try {
if (itemType == Integer.class) {
value = Integer.parseInt(((JTextField) c).getText());
}
if (itemType == Long.class) {
value = Long.parseLong(((JTextField) c).getText());
}
if (itemType == Double.class) {
value = Double.parseDouble(((JTextField) c).getText());
}
if (itemType == Float.class) {
value = Float.parseFloat(((JTextField) c).getText());
}
} catch (NumberFormatException nfe) {
if (!((JTextField) c).getText().isEmpty()) {
c.requestFocusInWindow();
return;
}//else null
}
values.put(name, value);
}
for (String name : fields.keySet()) {
Component c = componentsMap.get(name);
Object value = values.get(name);
Field field = fields.get(name);
ConfigurationItem item = null;
try {
item = (ConfigurationItem) field.get(null);
} catch (IllegalArgumentException | IllegalAccessException ex) {
// Reflection exceptions. This should never happen
throw new Error(ex.getMessage());
}
if (item.get() != null && !item.get().equals(value)) {
item.set(value);
modified = true;
}
}
Configuration.saveConfig();
setVisible(false);
if (modified) {
showRestartConfirmDialod();
}
break;
case "CANCEL":
setVisible(false);
break;
case "RESET":
Map<String, Field> rfields = Configuration.getConfigurationFields();
for (Entry<String, Field> entry : rfields.entrySet()) {
String name = entry.getKey();
Field field = entry.getValue();
try {
ConfigurationItem item = (ConfigurationItem) field.get(null);
item.unset();
} catch (IllegalArgumentException | IllegalAccessException ex) {
// Reflection exceptions. This should never happen
throw new Error(ex.getMessage());
}
}
Configuration.saveConfig();
setVisible(false);
showRestartConfirmDialod();
break;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,146 +1,138 @@
/*
* Copyright (C) 2010-2014 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;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JPanel;
/**
* Panel with loading animation
*
* @author JPEXS
*/
public class LoadingPanel extends JPanel {
BufferedImage lastImage;
int lastSize = 0;
Color col;
double rotation = 0;
Timer drawTimer;
public LoadingPanel(int width,int height){
this.col = new Color(0,0,255);
setPreferredSize(new Dimension(width,height));
}
private synchronized void setRotation(double rotation) {
this.rotation = rotation;
}
private synchronized double getRotation() {
return rotation;
}
private synchronized int getLastSize() {
return lastSize;
}
private synchronized void redrawImage(int size){
if(drawTimer!=null){
drawTimer.cancel();;
drawTimer = null;
}
BufferedImage bi = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
Graphics2D big = bi.createGraphics();
big.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
big.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
big.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int br = size/16;
if(br<2){
br = 2;
}
int border = 2;
int r = size / 2 - br - border;
int o = (int) Math.round(Math.PI * 2 * r);
double max = Math.PI * 2;
double skip = max / o;
big.setComposite(AlphaComposite.Src);
for (int i = 0; i < o; i++) {
int c = i * 256 / o;
double alfa = skip * i;
double x = border + br + r + Math.round(Math.sin(alfa) * r);
double y = border + br + r + Math.round(Math.cos(alfa) * r);
big.setColor(new Color(col.getRed(), col.getGreen(), col.getBlue(), c));
big.fill(new Ellipse2D.Double(x - br, y - br, 2 * br, 2 * br));
}
lastImage = bi;
lastSize = size;
drawTimer = new Timer();
int timeSpin = 1000;
double delay = 0;
delay = timeSpin/o;
while(delay<10){
o--;
delay = timeSpin/o;
}
final int segments = o;
int idelay = (int)Math.round(delay);
drawTimer.schedule(new TimerTask() {
@Override
public void run() {
double rot2 = rotation - Math.PI*2/segments;
if(rot2<0){
rot2+=Math.PI*2;
}
setRotation(rot2);
repaint();
}
}, idelay,idelay);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int size = Math.min(getWidth(), getHeight());
if (lastImage == null || getLastSize()!=size) {
redrawImage(size);
}
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
AffineTransform t = AffineTransform.getRotateInstance(getRotation(), size/2, size/2);
g2.setTransform(t);
g2.drawImage(lastImage, 0, 0, this);
}
}
/*
* Copyright (C) 2010-2014 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;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JPanel;
/**
* Panel with loading animation
*
* @author JPEXS
*/
public class LoadingPanel extends JPanel {
BufferedImage lastImage;
int lastSize = 0;
Color col;
double rotation = 0;
Timer drawTimer;
public LoadingPanel(int width, int height) {
this.col = new Color(0, 0, 255);
setPreferredSize(new Dimension(width, height));
}
private synchronized void setRotation(double rotation) {
this.rotation = rotation;
}
private synchronized double getRotation() {
return rotation;
}
private synchronized int getLastSize() {
return lastSize;
}
private synchronized void redrawImage(int size) {
if (drawTimer != null) {
drawTimer.cancel();;
drawTimer = null;
}
BufferedImage bi = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
Graphics2D big = bi.createGraphics();
big.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
big.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
big.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int br = size / 16;
if (br < 2) {
br = 2;
}
int border = 2;
int r = size / 2 - br - border;
int o = (int) Math.round(Math.PI * 2 * r);
double max = Math.PI * 2;
double skip = max / o;
big.setComposite(AlphaComposite.Src);
for (int i = 0; i < o; i++) {
int c = i * 256 / o;
double alfa = skip * i;
double x = border + br + r + Math.round(Math.sin(alfa) * r);
double y = border + br + r + Math.round(Math.cos(alfa) * r);
big.setColor(new Color(col.getRed(), col.getGreen(), col.getBlue(), c));
big.fill(new Ellipse2D.Double(x - br, y - br, 2 * br, 2 * br));
}
lastImage = bi;
lastSize = size;
drawTimer = new Timer();
int timeSpin = 1000;
double delay = 0;
delay = timeSpin / o;
while (delay < 10) {
o--;
delay = timeSpin / o;
}
final int segments = o;
int idelay = (int) Math.round(delay);
drawTimer.schedule(new TimerTask() {
@Override
public void run() {
double rot2 = rotation - Math.PI * 2 / segments;
if (rot2 < 0) {
rot2 += Math.PI * 2;
}
setRotation(rot2);
repaint();
}
}, idelay, idelay);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int size = Math.min(getWidth(), getHeight());
if (lastImage == null || getLastSize() != size) {
redrawImage(size);
}
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
AffineTransform t = AffineTransform.getRotateInstance(getRotation(), size / 2, size / 2);
g2.setTransform(t);
g2.drawImage(lastImage, 0, 0, this);
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,95 +1,94 @@
/*
* Copyright (C) 2014 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;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import javax.swing.plaf.ComponentUI;
import org.pushingpixels.flamingo.api.common.JCommandButton;
import org.pushingpixels.flamingo.api.common.popup.JCommandPopupMenu;
import org.pushingpixels.flamingo.api.common.popup.JPopupPanel;
import org.pushingpixels.flamingo.api.common.popup.PopupPanelManager;
import org.pushingpixels.substance.flamingo.common.ui.SubstanceCommandButtonUI;
/**
*
* Own CommandButtonUI because original Flamingo UI throws Exception in some cases
*
* @author JPEXS
*/
public class MyCommandButtonUI extends SubstanceCommandButtonUI{
public static ComponentUI createUI(JComponent comp) {
return new MyCommandButtonUI((JCommandButton)comp);
}
public MyCommandButtonUI(JCommandButton jcb) {
super(jcb);
}
@Override
protected void installListeners() {
super.installListeners();
this.commandButton.removeActionListener(this.disposePopupsActionListener);
this.disposePopupsActionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(commandButton == null){ //Added by JPEXS
return;
}
boolean toDismiss = !Boolean.TRUE.equals(commandButton
.getClientProperty(DONT_DISPOSE_POPUPS));
if (toDismiss) {
JCommandPopupMenu menu = (JCommandPopupMenu) SwingUtilities
.getAncestorOfClass(JCommandPopupMenu.class,
commandButton);
if (menu != null) {
toDismiss = menu.isToDismissOnChildClick();
}
}
if (toDismiss) {
if (SwingUtilities.getAncestorOfClass(JPopupPanel.class,
commandButton) != null) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// command button may be cleared if the
// button click resulted in LAF switch
if (commandButton != null) {
// clear the active states
commandButton.getActionModel().setPressed(
false);
commandButton.getActionModel().setRollover(
false);
commandButton.getActionModel().setArmed(
false);
}
}
});
}
PopupPanelManager.defaultManager().hidePopups(null);
}
}
};
this.commandButton.addActionListener(disposePopupsActionListener);
}
}
/*
* Copyright (C) 2014 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;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import javax.swing.plaf.ComponentUI;
import org.pushingpixels.flamingo.api.common.JCommandButton;
import org.pushingpixels.flamingo.api.common.popup.JCommandPopupMenu;
import org.pushingpixels.flamingo.api.common.popup.JPopupPanel;
import org.pushingpixels.flamingo.api.common.popup.PopupPanelManager;
import org.pushingpixels.substance.flamingo.common.ui.SubstanceCommandButtonUI;
/**
*
* Own CommandButtonUI because original Flamingo UI throws Exception in some
* cases
*
* @author JPEXS
*/
public class MyCommandButtonUI extends SubstanceCommandButtonUI {
public static ComponentUI createUI(JComponent comp) {
return new MyCommandButtonUI((JCommandButton) comp);
}
public MyCommandButtonUI(JCommandButton jcb) {
super(jcb);
}
@Override
protected void installListeners() {
super.installListeners();
this.commandButton.removeActionListener(this.disposePopupsActionListener);
this.disposePopupsActionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (commandButton == null) { //Added by JPEXS
return;
}
boolean toDismiss = !Boolean.TRUE.equals(commandButton
.getClientProperty(DONT_DISPOSE_POPUPS));
if (toDismiss) {
JCommandPopupMenu menu = (JCommandPopupMenu) SwingUtilities
.getAncestorOfClass(JCommandPopupMenu.class,
commandButton);
if (menu != null) {
toDismiss = menu.isToDismissOnChildClick();
}
}
if (toDismiss) {
if (SwingUtilities.getAncestorOfClass(JPopupPanel.class,
commandButton) != null) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// command button may be cleared if the
// button click resulted in LAF switch
if (commandButton != null) {
// clear the active states
commandButton.getActionModel().setPressed(
false);
commandButton.getActionModel().setRollover(
false);
commandButton.getActionModel().setArmed(
false);
}
}
});
}
PopupPanelManager.defaultManager().hidePopups(null);
}
}
};
this.commandButton.addActionListener(disposePopupsActionListener);
}
}
File diff suppressed because it is too large Load Diff
@@ -1,460 +1,461 @@
/*
* Copyright (C) 2010-2014 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;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.gui.abc.ClassesListTreeModel;
import com.jpexs.decompiler.flash.gui.abc.treenodes.ClassesListNode;
import com.jpexs.decompiler.flash.gui.abc.treenodes.TreeElement;
import com.jpexs.decompiler.flash.gui.treenodes.SWFBundleNode;
import com.jpexs.decompiler.flash.gui.treenodes.SWFContainerNode;
import com.jpexs.decompiler.flash.gui.treenodes.SWFNode;
import com.jpexs.decompiler.flash.gui.treenodes.StringNode;
import com.jpexs.decompiler.flash.gui.treenodes.TagTreeRoot;
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
import com.jpexs.decompiler.flash.tags.ShowFrameTag;
import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag;
import com.jpexs.decompiler.flash.treeitems.FrameNodeItem;
import com.jpexs.decompiler.flash.treeitems.SWFList;
import com.jpexs.decompiler.flash.treeitems.StringItem;
import com.jpexs.decompiler.flash.treeitems.TreeElementItem;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
import com.jpexs.decompiler.flash.treenodes.FrameNode;
import com.jpexs.decompiler.flash.treenodes.TagNode;
import com.jpexs.decompiler.flash.treenodes.TreeNode;
import com.jpexs.helpers.Helper;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
public class TagTreeModel implements TreeModel {
public static final String FOLDER_TEXTS = "texts";
public static final String FOLDER_IMAGES = "images";
public static final String FOLDER_MOVIES = "movies";
public static final String FOLDER_SOUNDS = "sounds";
public static final String FOLDER_BINARY_DATA = "binaryData";
public static final String FOLDER_FONTS = "fonts";
public static final String FOLDER_SPRITES = "sprites";
public static final String FOLDER_SHAPES = "shapes";
public static final String FOLDER_MORPHSHAPES = "morphshapes";
public static final String FOLDER_BUTTONS = "buttons";
public static final String FOLDER_FRAMES = "frames";
public static final String FOLDER_OTHERS = "others";
public static final String FOLDER_SCRIPTS = "scripts";
private final TagTreeRoot root = new TagTreeRoot();
private final List<SWFContainerNode> swfs;
private final Map<SWF, SWFNode> swfToSwfNode;
private final MainFrame mainFrame;
public TagTreeModel(MainFrame mainFrame, List<SWFList> swfs) {
this.mainFrame = mainFrame;
this.swfs = new ArrayList<>();
swfToSwfNode = new HashMap<>();
for (SWFList swfList : swfs) {
if (swfList.isBundle) {
SWFBundleNode bundleNode = new SWFBundleNode(swfList, swfList.name);
for (SWF swf : swfList) {
bundleNode.swfs.add(createSwfNode(swf));
}
this.swfs.add(bundleNode);
} else {
SWF swf = swfList.get(0);
this.swfs.add(createSwfNode(swf));
}
}
}
private SWFNode createSwfNode(SWF swf) {
ClassesListTreeModel classTreeModel = new ClassesListTreeModel(swf);
SWFNode swfNode = new SWFNode(swf, swf.getShortFileName());
swfNode.list = createTagList(swf.tags, null, swf, swfNode, classTreeModel);
swfToSwfNode.put(swf, swfNode);
return swfNode;
}
private String translate(String key) {
return mainFrame.translate(key);
}
private List<TreeNode> createTagList(List<Tag> list, Tag parent, SWF swf, SWFNode swfNode, ClassesListTreeModel classTreeModel) {
boolean hasAbc = swf.abcList != null && !swf.abcList.isEmpty();
List<TreeNode> ret = new ArrayList<>();
List<TreeNode> frames = new ArrayList<>();
List<TreeNode> shapes = new ArrayList<>();
List<TreeNode> morphShapes = new ArrayList<>();
List<TreeNode> sprites = new ArrayList<>();
List<TreeNode> buttons = new ArrayList<>();
List<TreeNode> images = new ArrayList<>();
List<TreeNode> fonts = new ArrayList<>();
List<TreeNode> texts = new ArrayList<>();
List<TreeNode> movies = new ArrayList<>();
List<TreeNode> sounds = new ArrayList<>();
List<TreeNode> binaryData = new ArrayList<>();
List<TreeNode> others = new ArrayList<>();
List<TreeNode> actionScript = SWF.createASTagList(list, null);
List<Tag> actionScriptTags = new ArrayList<>();
SWF.getTagsFromTreeNodes(actionScript, actionScriptTags);
int frameCnt = 0;
for (Tag t : list) {
TreeNodeType ttype = TagTree.getTreeNodeType(t);
switch (ttype) {
case SHOW_FRAME:
ShowFrameTag showFrameTag = (ShowFrameTag) t;
frames.add(new FrameNode(new FrameNodeItem(t.getSwf(), ++frameCnt, parent, showFrameTag, true), showFrameTag.innerTags, false));
break;
case SHAPE:
shapes.add(new TagNode(t));
break;
case MORPH_SHAPE:
morphShapes.add(new TagNode(t));
break;
case SPRITE:
sprites.add(new TagNode(t));
break;
case BUTTON:
buttons.add(new TagNode(t));
break;
case IMAGE:
images.add(new TagNode(t));
break;
case FONT:
fonts.add(new TagNode(t));
break;
case TEXT:
texts.add(new TagNode(t));
break;
case MOVIE:
movies.add(new TagNode(t));
break;
case SOUND:
sounds.add(new TagNode(t));
break;
case BINARY_DATA:
TagNode bt;
binaryData.add(bt = new TagNode(t));
DefineBinaryDataTag b=(DefineBinaryDataTag)t;
try {
SWF bswf=new SWF(new ByteArrayInputStream(b.binaryData),Configuration.parallelSpeedUp.get());
bswf.fileTitle = "(SWF Data)";
SWFNode snode=createSwfNode(bswf);
snode.binaryData = b;
bt.subNodes.add(snode);
} catch (IOException | InterruptedException ex) {
//ignore
}
break;
default:
if (!actionScriptTags.contains(t) && !ShowFrameTag.isNestedTagType(t.getId())) {
others.add(new TagNode(t));
}
break;
}
}
for (int i = 0; i < sounds.size(); i++) {
if (sounds.get(i).getItem() instanceof SoundStreamHeadTypeTag) {
List<SoundStreamBlockTag> blocks = ((SoundStreamHeadTypeTag) sounds.get(i).getItem()).getBlocks();
if (blocks.isEmpty()) {
sounds.remove(i);
i--;
}
}
}
for (TreeNode n : sprites) {
Tag tag = n.getItem() instanceof Tag ? (Tag) n.getItem() : null;
n.subNodes = createSubTagList(((DefineSpriteTag) n.getItem()).subTags, tag, swf, actionScriptTags);
}
StringNode textsNode = new StringNode(new StringItem(translate("node.texts"), FOLDER_TEXTS, swf));
textsNode.subNodes.addAll(texts);
StringNode imagesNode = new StringNode(new StringItem(translate("node.images"), FOLDER_IMAGES, swf));
imagesNode.subNodes.addAll(images);
StringNode moviesNode = new StringNode(new StringItem(translate("node.movies"), FOLDER_MOVIES, swf));
moviesNode.subNodes.addAll(movies);
StringNode soundsNode = new StringNode(new StringItem(translate("node.sounds"), FOLDER_SOUNDS, swf));
soundsNode.subNodes.addAll(sounds);
StringNode binaryDataNode = new StringNode(new StringItem(translate("node.binaryData"), FOLDER_BINARY_DATA, swf));
binaryDataNode.subNodes.addAll(binaryData);
StringNode fontsNode = new StringNode(new StringItem(translate("node.fonts"), FOLDER_FONTS, swf));
fontsNode.subNodes.addAll(fonts);
StringNode spritesNode = new StringNode(new StringItem(translate("node.sprites"), FOLDER_SPRITES, swf));
spritesNode.subNodes.addAll(sprites);
StringNode shapesNode = new StringNode(new StringItem(translate("node.shapes"), FOLDER_SHAPES, swf));
shapesNode.subNodes.addAll(shapes);
StringNode morphShapesNode = new StringNode(new StringItem(translate("node.morphshapes"), FOLDER_MORPHSHAPES, swf));
morphShapesNode.subNodes.addAll(morphShapes);
StringNode buttonsNode = new StringNode(new StringItem(translate("node.buttons"), FOLDER_BUTTONS, swf));
buttonsNode.subNodes.addAll(buttons);
StringNode framesNode = new StringNode(new StringItem(translate("node.frames"), FOLDER_FRAMES, swf));
framesNode.subNodes.addAll(frames);
StringNode otherNode = new StringNode(new StringItem(translate("node.others"), FOLDER_OTHERS, swf));
otherNode.subNodes.addAll(others);
TreeNode actionScriptNode;
if (hasAbc) {
actionScriptNode = new ClassesListNode(classTreeModel);
} else {
actionScriptNode = new StringNode(new StringItem(translate("node.scripts"), FOLDER_SCRIPTS, swf));
actionScriptNode.subNodes.addAll(actionScript);
}
swfNode.scriptsNode = actionScriptNode;
if (!shapesNode.subNodes.isEmpty()) {
ret.add(shapesNode);
}
if (!morphShapesNode.subNodes.isEmpty()) {
ret.add(morphShapesNode);
}
if (!spritesNode.subNodes.isEmpty()) {
ret.add(spritesNode);
}
if (!textsNode.subNodes.isEmpty()) {
ret.add(textsNode);
}
if (!imagesNode.subNodes.isEmpty()) {
ret.add(imagesNode);
}
if (!moviesNode.subNodes.isEmpty()) {
ret.add(moviesNode);
}
if (!soundsNode.subNodes.isEmpty()) {
ret.add(soundsNode);
}
if (!buttonsNode.subNodes.isEmpty()) {
ret.add(buttonsNode);
}
if (!fontsNode.subNodes.isEmpty()) {
ret.add(fontsNode);
}
if (!binaryDataNode.subNodes.isEmpty()) {
ret.add(binaryDataNode);
}
if (!framesNode.subNodes.isEmpty()) {
ret.add(framesNode);
}
if (!otherNode.subNodes.isEmpty()) {
ret.add(otherNode);
}
if ((!actionScriptNode.subNodes.isEmpty()) || hasAbc) {
ret.add(actionScriptNode);
}
return ret;
}
private List<TreeNode> createSubTagList(List<Tag> list, Tag parent, SWF swf, List<Tag> actionScriptTags) {
List<TreeNode> ret = new ArrayList<>();
List<TreeNode> frames = new ArrayList<>();
List<TreeNode> others = new ArrayList<>();
int frameCnt = 0;
for (Tag t : list) {
TreeNodeType ttype = TagTree.getTreeNodeType(t);
switch (ttype) {
case SHOW_FRAME:
ShowFrameTag showFrameTag = (ShowFrameTag) t;
frames.add(new FrameNode(new FrameNodeItem(t.getSwf(), ++frameCnt, parent, showFrameTag, true), showFrameTag.innerTags, false));
break;
default:
if (!actionScriptTags.contains(t) && !ShowFrameTag.isNestedTagType(t.getId())) {
if (!(t instanceof SoundStreamHeadTypeTag)) {
others.add(new TagNode(t));
}
}
break;
}
}
ret.addAll(frames);
if (!others.isEmpty()) {
StringNode otherNode = new StringNode(new StringItem(translate("node.others"), FOLDER_OTHERS, swf));
otherNode.subNodes.addAll(others);
ret.add(otherNode);
}
return ret;
}
private List<TreeNode> searchTag(TreeItem obj, TreeNode parent, List<TreeNode> path) {
List<TreeNode> ret = null;
int cnt = getChildCount(parent);
for (int i = 0; i < cnt; i++) {
TreeNode n = getChild(parent, i);
List<TreeNode> newPath = new ArrayList<>();
newPath.addAll(path);
newPath.add(n);
if (n instanceof TreeElement) {
TreeElement te = (TreeElement) n;
TreeElementItem it = te.getItem();
if (obj == it) {
return newPath;
}
}
if (n instanceof TreeNode) {
TreeNode nd = (TreeNode) n;
if (obj instanceof StringItem && nd.getItem() instanceof StringItem) {
// StringItems are always recreated, so compare them by name
StringItem nds = (StringItem) nd.getItem();
StringItem objs = (StringItem) obj;
if (objs.getName().equals(nds.getName())) {
return newPath;
}
} else {
if (nd.getItem() == obj) {
return newPath;
}
}
}
ret = searchTag(obj, n, newPath);
if (ret != null) {
return ret;
}
}
return ret;
}
public SWFNode getSwfNode(SWF swf) {
return swfToSwfNode.get(swf);
}
public TreePath getTagPath(TreeItem obj) {
List<TreeNode> path = new ArrayList<>();
path.add(getRoot());
path = searchTag(obj, getRoot(), path);
if (path == null) {
return null;
}
TreePath tp = new TreePath(path.toArray(new Object[path.size()]));
return tp;
}
@Override
public TreeNode getRoot() {
return root;
}
@Override
public TreeNode getChild(Object parent, int index) {
TreeNode parentNode = (TreeNode) parent;
if (parent instanceof TreeElement) {
return ((TreeElement) parent).getChild(index);
} else {
if (parentNode.getItem() instanceof ClassesListTreeModel) {
ClassesListTreeModel clt = (ClassesListTreeModel) parentNode.getItem();
return clt.getChild(clt.getRoot(), index);
}
}
if (parent == root) {
return swfs.get(index);
} else if (parent instanceof SWFBundleNode) {
return ((SWFBundleNode) parent).swfs.get(index);
} else if (parent instanceof SWFNode) {
return ((SWFNode) parent).list.get(index);
}
return parentNode.subNodes.get(index);
}
@Override
public int getChildCount(Object parent) {
TreeNode parentNode = (TreeNode) parent;
if (parent == root) {
return swfs.size();
} else if (parent instanceof TreeElement) {
return ((TreeElement) parent).getChildCount();
} else if (parent instanceof SWFBundleNode) {
return ((SWFBundleNode) parent).swfs.size();
} else if (parent instanceof SWFNode) {
return ((SWFNode) parent).list.size();
} else {
if (parentNode.getItem() instanceof ClassesListTreeModel) {
ClassesListTreeModel clt = (ClassesListTreeModel) parentNode.getItem();
return clt.getChildCount(clt.getRoot());
}
return parentNode.subNodes.size();
}
}
@Override
public boolean isLeaf(Object node) {
return (getChildCount(node) == 0);
}
@Override
public void valueForPathChanged(TreePath path, Object newValue) {
}
@Override
public int getIndexOfChild(Object parent, Object child) {
TreeNode parentNode = (TreeNode) parent;
if (parent == root) {
return swfs.indexOf(child);
} else if (parent instanceof TreeElement) {
return ((TreeElement) parent).getIndexOfChild((TreeElement) child);
} else if (parent instanceof SWFBundleNode) {
return ((SWFBundleNode) parent).swfs.indexOf(child);
} else if (parent instanceof SWFNode) {
return ((SWFNode) parent).list.indexOf(child);
} else {
if (parentNode.getItem() instanceof ClassesListTreeModel) {
ClassesListTreeModel clt = (ClassesListTreeModel) parentNode.getItem();
return clt.getIndexOfChild(clt.getRoot(), child);
}
return parentNode.subNodes.indexOf(child);
}
}
@Override
public void addTreeModelListener(TreeModelListener l) {
}
@Override
public void removeTreeModelListener(TreeModelListener l) {
}
}
/*
* Copyright (C) 2010-2014 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;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.gui.abc.ClassesListTreeModel;
import com.jpexs.decompiler.flash.gui.abc.treenodes.ClassesListNode;
import com.jpexs.decompiler.flash.gui.abc.treenodes.TreeElement;
import com.jpexs.decompiler.flash.gui.treenodes.SWFBundleNode;
import com.jpexs.decompiler.flash.gui.treenodes.SWFContainerNode;
import com.jpexs.decompiler.flash.gui.treenodes.SWFNode;
import com.jpexs.decompiler.flash.gui.treenodes.StringNode;
import com.jpexs.decompiler.flash.gui.treenodes.TagTreeRoot;
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
import com.jpexs.decompiler.flash.tags.ShowFrameTag;
import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag;
import com.jpexs.decompiler.flash.timeline.Timeline;
import com.jpexs.decompiler.flash.timeline.Timelined;
import com.jpexs.decompiler.flash.treeitems.FrameNodeItem;
import com.jpexs.decompiler.flash.treeitems.SWFList;
import com.jpexs.decompiler.flash.treeitems.StringItem;
import com.jpexs.decompiler.flash.treeitems.TreeElementItem;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
import com.jpexs.decompiler.flash.treenodes.FrameNode;
import com.jpexs.decompiler.flash.treenodes.TagNode;
import com.jpexs.decompiler.flash.treenodes.TreeNode;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
public class TagTreeModel implements TreeModel {
public static final String FOLDER_TEXTS = "texts";
public static final String FOLDER_IMAGES = "images";
public static final String FOLDER_MOVIES = "movies";
public static final String FOLDER_SOUNDS = "sounds";
public static final String FOLDER_BINARY_DATA = "binaryData";
public static final String FOLDER_FONTS = "fonts";
public static final String FOLDER_SPRITES = "sprites";
public static final String FOLDER_SHAPES = "shapes";
public static final String FOLDER_MORPHSHAPES = "morphshapes";
public static final String FOLDER_BUTTONS = "buttons";
public static final String FOLDER_FRAMES = "frames";
public static final String FOLDER_OTHERS = "others";
public static final String FOLDER_SCRIPTS = "scripts";
private final TagTreeRoot root = new TagTreeRoot();
private final List<SWFContainerNode> swfs;
private final Map<SWF, SWFNode> swfToSwfNode;
private final MainFrame mainFrame;
public TagTreeModel(MainFrame mainFrame, List<SWFList> swfs) {
this.mainFrame = mainFrame;
this.swfs = new ArrayList<>();
swfToSwfNode = new HashMap<>();
for (SWFList swfList : swfs) {
if (swfList.isBundle) {
SWFBundleNode bundleNode = new SWFBundleNode(swfList, swfList.name);
for (SWF swf : swfList) {
bundleNode.swfs.add(createSwfNode(swf));
}
this.swfs.add(bundleNode);
} else {
SWF swf = swfList.get(0);
this.swfs.add(createSwfNode(swf));
}
}
}
private SWFNode createSwfNode(SWF swf) {
ClassesListTreeModel classTreeModel = new ClassesListTreeModel(swf);
SWFNode swfNode = new SWFNode(swf, swf.getShortFileName());
swfNode.list = createTagList(swf.tags, null, swf, swfNode, classTreeModel);
swfToSwfNode.put(swf, swfNode);
return swfNode;
}
private String translate(String key) {
return mainFrame.translate(key);
}
private List<TreeNode> createTagList(List<Tag> list, Tag parent, SWF swf, SWFNode swfNode, ClassesListTreeModel classTreeModel) {
boolean hasAbc = swf.abcList != null && !swf.abcList.isEmpty();
List<TreeNode> ret = new ArrayList<>();
List<TreeNode> frames = new ArrayList<>();
List<TreeNode> shapes = new ArrayList<>();
List<TreeNode> morphShapes = new ArrayList<>();
List<TreeNode> sprites = new ArrayList<>();
List<TreeNode> buttons = new ArrayList<>();
List<TreeNode> images = new ArrayList<>();
List<TreeNode> fonts = new ArrayList<>();
List<TreeNode> texts = new ArrayList<>();
List<TreeNode> movies = new ArrayList<>();
List<TreeNode> sounds = new ArrayList<>();
List<TreeNode> binaryData = new ArrayList<>();
List<TreeNode> others = new ArrayList<>();
List<TreeNode> actionScript = SWF.createASTagList(list, null);
List<Tag> actionScriptTags = new ArrayList<>();
SWF.getTagsFromTreeNodes(actionScript, actionScriptTags);
for (Tag t : list) {
TreeNodeType ttype = TagTree.getTreeNodeType(t);
switch (ttype) {
case SHAPE:
shapes.add(new TagNode(t));
break;
case MORPH_SHAPE:
morphShapes.add(new TagNode(t));
break;
case SPRITE:
sprites.add(new TagNode(t));
break;
case BUTTON:
buttons.add(new TagNode(t));
break;
case IMAGE:
images.add(new TagNode(t));
break;
case FONT:
fonts.add(new TagNode(t));
break;
case TEXT:
texts.add(new TagNode(t));
break;
case MOVIE:
movies.add(new TagNode(t));
break;
case SOUND:
sounds.add(new TagNode(t));
break;
case BINARY_DATA:
TagNode bt;
binaryData.add(bt = new TagNode(t));
DefineBinaryDataTag b = (DefineBinaryDataTag) t;
try {
SWF bswf = new SWF(new ByteArrayInputStream(b.binaryData), Configuration.parallelSpeedUp.get());
bswf.fileTitle = "(SWF Data)";
SWFNode snode = createSwfNode(bswf);
snode.binaryData = b;
bt.subNodes.add(snode);
} catch (IOException | InterruptedException ex) {
//ignore
}
break;
default:
if (!actionScriptTags.contains(t) && !ShowFrameTag.isNestedTagType(t.getId())) {
others.add(new TagNode(t));
}
break;
}
}
Timeline timeline = swf.getTimeline();
for (int i = 0; i < timeline.getFrameCount(); i++) {
frames.add(new FrameNode(new FrameNodeItem(swf, i + 1, parent, true), timeline.frames.get(i).innerTags, false));
}
for (int i = 0; i < sounds.size(); i++) {
if (sounds.get(i).getItem() instanceof SoundStreamHeadTypeTag) {
List<SoundStreamBlockTag> blocks = ((SoundStreamHeadTypeTag) sounds.get(i).getItem()).getBlocks();
if (blocks.isEmpty()) {
sounds.remove(i);
i--;
}
}
}
for (TreeNode n : sprites) {
Tag tag = n.getItem() instanceof Tag ? (Tag) n.getItem() : null;
n.subNodes = createSubTagList(((DefineSpriteTag) n.getItem()).subTags, tag, swf, actionScriptTags);
}
StringNode textsNode = new StringNode(new StringItem(translate("node.texts"), FOLDER_TEXTS, swf));
textsNode.subNodes.addAll(texts);
StringNode imagesNode = new StringNode(new StringItem(translate("node.images"), FOLDER_IMAGES, swf));
imagesNode.subNodes.addAll(images);
StringNode moviesNode = new StringNode(new StringItem(translate("node.movies"), FOLDER_MOVIES, swf));
moviesNode.subNodes.addAll(movies);
StringNode soundsNode = new StringNode(new StringItem(translate("node.sounds"), FOLDER_SOUNDS, swf));
soundsNode.subNodes.addAll(sounds);
StringNode binaryDataNode = new StringNode(new StringItem(translate("node.binaryData"), FOLDER_BINARY_DATA, swf));
binaryDataNode.subNodes.addAll(binaryData);
StringNode fontsNode = new StringNode(new StringItem(translate("node.fonts"), FOLDER_FONTS, swf));
fontsNode.subNodes.addAll(fonts);
StringNode spritesNode = new StringNode(new StringItem(translate("node.sprites"), FOLDER_SPRITES, swf));
spritesNode.subNodes.addAll(sprites);
StringNode shapesNode = new StringNode(new StringItem(translate("node.shapes"), FOLDER_SHAPES, swf));
shapesNode.subNodes.addAll(shapes);
StringNode morphShapesNode = new StringNode(new StringItem(translate("node.morphshapes"), FOLDER_MORPHSHAPES, swf));
morphShapesNode.subNodes.addAll(morphShapes);
StringNode buttonsNode = new StringNode(new StringItem(translate("node.buttons"), FOLDER_BUTTONS, swf));
buttonsNode.subNodes.addAll(buttons);
StringNode framesNode = new StringNode(new StringItem(translate("node.frames"), FOLDER_FRAMES, swf));
framesNode.subNodes.addAll(frames);
StringNode otherNode = new StringNode(new StringItem(translate("node.others"), FOLDER_OTHERS, swf));
otherNode.subNodes.addAll(others);
TreeNode actionScriptNode;
if (hasAbc) {
actionScriptNode = new ClassesListNode(classTreeModel);
} else {
actionScriptNode = new StringNode(new StringItem(translate("node.scripts"), FOLDER_SCRIPTS, swf));
actionScriptNode.subNodes.addAll(actionScript);
}
swfNode.scriptsNode = actionScriptNode;
if (!shapesNode.subNodes.isEmpty()) {
ret.add(shapesNode);
}
if (!morphShapesNode.subNodes.isEmpty()) {
ret.add(morphShapesNode);
}
if (!spritesNode.subNodes.isEmpty()) {
ret.add(spritesNode);
}
if (!textsNode.subNodes.isEmpty()) {
ret.add(textsNode);
}
if (!imagesNode.subNodes.isEmpty()) {
ret.add(imagesNode);
}
if (!moviesNode.subNodes.isEmpty()) {
ret.add(moviesNode);
}
if (!soundsNode.subNodes.isEmpty()) {
ret.add(soundsNode);
}
if (!buttonsNode.subNodes.isEmpty()) {
ret.add(buttonsNode);
}
if (!fontsNode.subNodes.isEmpty()) {
ret.add(fontsNode);
}
if (!binaryDataNode.subNodes.isEmpty()) {
ret.add(binaryDataNode);
}
if (!framesNode.subNodes.isEmpty()) {
ret.add(framesNode);
}
if (!otherNode.subNodes.isEmpty()) {
ret.add(otherNode);
}
if ((!actionScriptNode.subNodes.isEmpty()) || hasAbc) {
ret.add(actionScriptNode);
}
return ret;
}
private List<TreeNode> createSubTagList(List<Tag> list, Tag parent, SWF swf, List<Tag> actionScriptTags) {
List<TreeNode> ret = new ArrayList<>();
List<TreeNode> frames = new ArrayList<>();
List<TreeNode> others = new ArrayList<>();
for (Tag t : list) {
TreeNodeType ttype = TagTree.getTreeNodeType(t);
switch (ttype) {
default:
if (!actionScriptTags.contains(t) && !ShowFrameTag.isNestedTagType(t.getId())) {
if (!(t instanceof SoundStreamHeadTypeTag)) {
others.add(new TagNode(t));
}
}
break;
}
}
if (parent instanceof Timelined) {
Timeline timeline = ((Timelined) parent).getTimeline();
for (int i = 0; i < timeline.getFrameCount(); i++) {
frames.add(new FrameNode(new FrameNodeItem(swf, i + 1, parent, true), timeline.frames.get(i).innerTags, false));
}
}
ret.addAll(frames);
if (!others.isEmpty()) {
StringNode otherNode = new StringNode(new StringItem(translate("node.others"), FOLDER_OTHERS, swf));
otherNode.subNodes.addAll(others);
ret.add(otherNode);
}
return ret;
}
private List<TreeNode> searchTag(TreeItem obj, TreeNode parent, List<TreeNode> path) {
List<TreeNode> ret = null;
int cnt = getChildCount(parent);
for (int i = 0; i < cnt; i++) {
TreeNode n = getChild(parent, i);
List<TreeNode> newPath = new ArrayList<>();
newPath.addAll(path);
newPath.add(n);
if (n instanceof TreeElement) {
TreeElement te = (TreeElement) n;
TreeElementItem it = te.getItem();
if (obj == it) {
return newPath;
}
}
if (n instanceof TreeNode) {
TreeNode nd = (TreeNode) n;
if (obj instanceof StringItem && nd.getItem() instanceof StringItem) {
// StringItems are always recreated, so compare them by name
StringItem nds = (StringItem) nd.getItem();
StringItem objs = (StringItem) obj;
if (objs.getName().equals(nds.getName())) {
return newPath;
}
} else {
if (nd.getItem() == obj) {
return newPath;
}
}
}
ret = searchTag(obj, n, newPath);
if (ret != null) {
return ret;
}
}
return ret;
}
public SWFNode getSwfNode(SWF swf) {
return swfToSwfNode.get(swf);
}
public TreePath getTagPath(TreeItem obj) {
List<TreeNode> path = new ArrayList<>();
path.add(getRoot());
path = searchTag(obj, getRoot(), path);
if (path == null) {
return null;
}
TreePath tp = new TreePath(path.toArray(new Object[path.size()]));
return tp;
}
@Override
public TreeNode getRoot() {
return root;
}
@Override
public TreeNode getChild(Object parent, int index) {
TreeNode parentNode = (TreeNode) parent;
if (parent instanceof TreeElement) {
return ((TreeElement) parent).getChild(index);
} else {
if (parentNode.getItem() instanceof ClassesListTreeModel) {
ClassesListTreeModel clt = (ClassesListTreeModel) parentNode.getItem();
return clt.getChild(clt.getRoot(), index);
}
}
if (parent == root) {
return swfs.get(index);
} else if (parent instanceof SWFBundleNode) {
return ((SWFBundleNode) parent).swfs.get(index);
} else if (parent instanceof SWFNode) {
return ((SWFNode) parent).list.get(index);
}
return parentNode.subNodes.get(index);
}
@Override
public int getChildCount(Object parent) {
TreeNode parentNode = (TreeNode) parent;
if (parent == root) {
return swfs.size();
} else if (parent instanceof TreeElement) {
return ((TreeElement) parent).getChildCount();
} else if (parent instanceof SWFBundleNode) {
return ((SWFBundleNode) parent).swfs.size();
} else if (parent instanceof SWFNode) {
return ((SWFNode) parent).list.size();
} else {
if (parentNode.getItem() instanceof ClassesListTreeModel) {
ClassesListTreeModel clt = (ClassesListTreeModel) parentNode.getItem();
return clt.getChildCount(clt.getRoot());
}
return parentNode.subNodes.size();
}
}
@Override
public boolean isLeaf(Object node) {
return (getChildCount(node) == 0);
}
@Override
public void valueForPathChanged(TreePath path, Object newValue) {
}
@Override
public int getIndexOfChild(Object parent, Object child) {
TreeNode parentNode = (TreeNode) parent;
if (parent == root) {
return swfs.indexOf(child);
} else if (parent instanceof TreeElement) {
return ((TreeElement) parent).getIndexOfChild((TreeElement) child);
} else if (parent instanceof SWFBundleNode) {
return ((SWFBundleNode) parent).swfs.indexOf(child);
} else if (parent instanceof SWFNode) {
return ((SWFNode) parent).list.indexOf(child);
} else {
if (parentNode.getItem() instanceof ClassesListTreeModel) {
ClassesListTreeModel clt = (ClassesListTreeModel) parentNode.getItem();
return clt.getIndexOfChild(clt.getRoot(), child);
}
return parentNode.subNodes.indexOf(child);
}
}
@Override
public void addTreeModelListener(TreeModelListener l) {
}
@Override
public void removeTreeModelListener(TreeModelListener l) {
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,487 +1,487 @@
/*
* Copyright (C) 2010-2014 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.player;
import com.jpexs.decompiler.flash.gui.FlashUnsupportedException;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.utf8.Utf8Helper;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.SHELLEXECUTEINFO;
import com.sun.jna.platform.win32.Shell32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.ptr.IntByReference;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public class FlashPlayerPanel extends Panel implements Closeable, MediaDisplay {
private boolean executed = false;
private String flash;
private HANDLE pipe;
private HANDLE process;
private WinDef.HWND hwnd;
private WinDef.HWND hwndFrame;
private Component frame;
private boolean stopped = true;
private static final int CMD_PLAY = 1;
private static final int CMD_RESIZE = 2;
private static final int CMD_BGCOLOR = 3;
private static final int CMD_CURRENT_FRAME = 4;
private static final int CMD_TOTAL_FRAMES = 5;
private static final int CMD_PAUSE = 6;
private static final int CMD_RESUME = 7;
private static final int CMD_PLAYING = 8;
private static final int CMD_REWIND = 9;
private static final int CMD_GOTO = 10;
private static final int CMD_CALL = 11;
private static final int CMD_GETVARIABLE = 12;
private static final int CMD_SETVARIABLE = 13;
private static final int PIPE_TIMEOUT_MS = 1000;
private int frameRate;
public boolean specialPlayback = false;
private boolean specialPlaying = false;
public synchronized String getVariable(String name) throws IOException {
if (pipe != null) {
writeToPipe(new byte[]{CMD_GETVARIABLE});
int nameLen = name.getBytes().length;
writeToPipe(new byte[]{(byte) ((nameLen >> 8) & 0xff), (byte) (nameLen & 0xff)});
writeToPipe(name.getBytes());
byte res[] = new byte[2];
readFromPipe(res);
int retLen = ((res[0] & 0xff) << 8) + (res[1] & 0xff);
res = new byte[retLen];
readFromPipe(res);
String ret = new String(res, 0, retLen);
return ret;
}
return null;
}
public synchronized void setVariable(String name, String value) throws IOException {
if (pipe != null) {
writeToPipe(new byte[]{CMD_SETVARIABLE});
int nameLen = name.getBytes().length;
writeToPipe(new byte[]{(byte) ((nameLen >> 8) & 0xff), (byte) (nameLen & 0xff)});
writeToPipe(name.getBytes());
int valLen = value.getBytes().length;
writeToPipe(new byte[]{(byte) ((valLen >> 8) & 0xff), (byte) (valLen & 0xff)});
writeToPipe(value.getBytes());
}
}
public synchronized String call(String callString) throws IOException {
if (pipe != null) {
writeToPipe(new byte[]{CMD_CALL});
int callLen = callString.getBytes().length;
writeToPipe(new byte[]{(byte) ((callLen >> 8) & 0xff), (byte) (callLen & 0xff)});
writeToPipe(callString.getBytes());
byte res[] = new byte[2];
readFromPipe(res);
int retLen = ((res[0] & 0xff) << 8) + (res[1] & 0xff);
res = new byte[retLen];
readFromPipe(res);
String ret = new String(res, 0, retLen);
return ret;
}
return null;
}
private synchronized void resize() throws IOException {
if (pipe != null) {
writeToPipe(new byte[]{CMD_RESIZE});
writeToPipe(new byte[]{
(byte) (getWidth() / 256), (byte) (getWidth() % 256),
(byte) (getHeight() / 256), (byte) (getHeight() % 256),});
}
}
private int __getCurrentFrame() throws IOException {
byte[] res = new byte[2];
writeToPipe(new byte[]{CMD_CURRENT_FRAME});
readFromPipe(res);
return ((res[0] & 0xff) << 8) + (res[1] & 0xff);
}
@Override
public synchronized int getCurrentFrame() {
try {
if (specialPlayback) {
if (!specialPlaying) {
return specialPosition;
}
String posStr = getVariable("_root.my_sound.position");
if (posStr != null) {
return Integer.parseInt(posStr);
}
}
return __getCurrentFrame();
} catch (IOException ex) {
return 0;
}
}
@Override
public synchronized int getTotalFrames() {
try {
if (specialPlayback) {
String durStr = getVariable("_root.my_sound.duration");
if (durStr != null) {
return Integer.parseInt(durStr);
}
}
byte[] res = new byte[2];
writeToPipe(new byte[]{CMD_TOTAL_FRAMES});
readFromPipe(res);
return ((res[0] & 0xff) << 8) + (res[1] & 0xff);
} catch (IOException ex) {
return 0;
}
}
@Override
public synchronized void setBackground(Color color) {
try {
writeToPipe(new byte[]{CMD_BGCOLOR});
writeToPipe(new byte[]{(byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()});
} catch (IOException ex) {
}
}
public FlashPlayerPanel(Component frame) {
if (!Platform.isWindows()) {
throw new FlashUnsupportedException();
}
this.frame = frame;
addComponentListener(new ComponentListener() {
@Override
public void componentResized(ComponentEvent e) {
try {
resize();
} catch (IOException ex) {
}
}
@Override
public void componentMoved(ComponentEvent e) {
}
@Override
public void componentShown(ComponentEvent e) {
componentResized(e);
}
@Override
public void componentHidden(ComponentEvent e) {
}
});
}
private synchronized void execute() {
if (!executed) {
hwnd = new WinDef.HWND();
hwnd.setPointer(Native.getComponentPointer(this));
hwndFrame = new WinDef.HWND();
hwndFrame.setPointer(Native.getComponentPointer(frame));
startFlashPlayer();
executed = true;
}
}
private void restartFlashPlayer() {
Kernel32.INSTANCE.TerminateProcess(process, 0);
Kernel32.INSTANCE.CloseHandle(pipe);
startFlashPlayer();
}
private void startFlashPlayer() {
String path = Utf8Helper.urlDecode(FlashPlayerPanel.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String appDir = new File(path).getParentFile().getAbsolutePath();
if (!appDir.endsWith("\\")) {
appDir += "\\";
}
String exePath = appDir + "lib\\FlashPlayer.exe";
File f = new File(exePath);
if (!f.exists()) {
Logger.getLogger(FlashPlayerPanel.class.getName()).log(Level.SEVERE, "FlashPlayer.exe not found: " + f.getPath());
return;
}
String pipeName = "\\\\.\\pipe\\ffdec_flashplayer_" + hwnd.getPointer().hashCode();
pipe = Kernel32.INSTANCE.CreateNamedPipe(pipeName, Kernel32.PIPE_ACCESS_DUPLEX, Kernel32.PIPE_TYPE_BYTE, 1, 4096, 4096, 0, null);
SHELLEXECUTEINFO sei = new SHELLEXECUTEINFO();
sei.fMask = 0x00000040;
sei.lpFile = new WString(exePath);
sei.lpParameters = new WString(hwnd.getPointer().hashCode() + " " + hwndFrame.getPointer().hashCode());
sei.nShow = WinUser.SW_NORMAL;
Shell32.INSTANCE.ShellExecuteEx(sei);
process = sei.hProcess;
Kernel32.INSTANCE.ConnectNamedPipe(pipe, null);
}
public synchronized void stopSWF() {
displaySWF("-", null, 1);
stopped = true;
}
public synchronized boolean isStopped() {
return stopped;
}
public synchronized void displaySWF(String flash, Color bgColor, int frameRate) {
try {
this.flash = flash;
repaint();
this.frameRate = frameRate;
execute();
if (bgColor != null) {
setBackground(bgColor);
}
resize();
if (pipe != null) {
writeToPipe(new byte[]{CMD_PLAY});
writeToPipe(new byte[]{(byte) flash.getBytes().length});
writeToPipe(flash.getBytes());
}
stopped = false;
specialPlaying = false;
specialPosition = 0;
if (specialPlayback) {
play();
}
} catch (IOException ex) {
}
}
@Override
public void close() throws IOException {
Kernel32.INSTANCE.CloseHandle(pipe);
Kernel32.INSTANCE.TerminateProcess(process, 0);
}
@Override
public void paint(Graphics g) {
if (flash != null) {
execute();
}
super.paint(g);
}
private int specialPosition = 0;
private synchronized void __pause() throws IOException {
writeToPipe(new byte[]{CMD_PAUSE});
}
@Override
public void pause() {
try {
if (specialPlayback) {
specialPosition = getCurrentFrame();
__gotoFrame(3);
__play();
specialPlaying = false;
return;
}
__pause();
} catch (IOException ex) {
}
}
@Override
public void rewind() {
try {
if (specialPlayback) {
boolean plays = specialPlaying;
pause();
specialPosition = 0;
if (plays) {
play();
}
return;
}
writeToPipe(new byte[]{CMD_REWIND});
} catch (IOException ex) {
}
}
private synchronized void __play() throws IOException {
writeToPipe(new byte[]{CMD_RESUME});
}
@Override
public void play() {
try {
if (specialPlayback) {
double p = (((double) specialPosition) / 1000.0);
setVariable("_root.execParam", "" + p);
__gotoFrame(1);
__play();
specialPlaying = true;
return;
}
__play();
} catch (IOException ex) {
}
}
@Override
public boolean isPlaying() {
try {
if (specialPlayback) {
return specialPlaying;
}
writeToPipe(new byte[]{CMD_PLAYING});
byte[] res = new byte[1];
readFromPipe(res);
return res[0] == 1;
} catch (IOException ex) {
return false;
}
}
private synchronized void __gotoFrame(int frame) throws IOException {
writeToPipe(new byte[]{CMD_GOTO});
writeToPipe(new byte[]{(byte) ((frame >> 8) & 0xff), (byte) (frame & 0xff)});
}
@Override
public void gotoFrame(int frame) {
try {
if (specialPlayback) {
if (specialPlaying) {
pause();
specialPosition = frame;
play();
} else {
specialPosition = frame;
}
return;
}
__gotoFrame(frame);
} catch (IOException ex) {
}
}
@Override
public int getFrameRate() {
if (specialPlayback) {
return 1000;
}
return frameRate;
}
@Override
public boolean isLoaded() {
return !isStopped();
}
private synchronized boolean writeToPipe(final byte[] data) throws IOException {
final IntByReference ibr = new IntByReference();
int result = -1;
try {
result = CancellableWorker.call(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
boolean result = Kernel32.INSTANCE.WriteFile(pipe, data, data.length, ibr, null);
if (!result) {
return Kernel32.INSTANCE.GetLastError();
}
if (ibr.getValue() != data.length) {
return -1;
}
return 0;
}
}, PIPE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
// ignore
}
if (result != 0) {
if (result == Kernel32.ERROR_NO_DATA || result == -1) {
restartFlashPlayer();
throw new IOException("Pipe write error.");
} else {
// System.out.println("pipe write failed. datalength: " + data.length + " error:" + result);
}
}
return result == 0;
}
private synchronized boolean readFromPipe(final byte[] res) throws IOException {
final IntByReference ibr = new IntByReference();
int result = -1;
try {
result = CancellableWorker.call(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int read = 0;
while (read < res.length) {
byte[] data = new byte[res.length - read];
boolean result = Kernel32.INSTANCE.ReadFile(pipe, data, data.length, ibr, null);
if (!result) {
return Kernel32.INSTANCE.GetLastError();
}
int readNow = ibr.getValue();
System.arraycopy(data, 0, res, read, readNow);
read += readNow;
}
return 0;
}
}, PIPE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
// ignore
}
if (result != 0) {
if (result == Kernel32.ERROR_BROKEN_PIPE || result == -1) {
restartFlashPlayer();
throw new IOException("Pipe read error.");
} else {
// System.out.println("pipe read failed. result: " + result + " datalength: " + res.length + " received: " + ibr.getValue() + " error: " + result);
}
}
return result == 0;
}
}
/*
* Copyright (C) 2010-2014 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.player;
import com.jpexs.decompiler.flash.gui.FlashUnsupportedException;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.utf8.Utf8Helper;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.SHELLEXECUTEINFO;
import com.sun.jna.platform.win32.Shell32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.ptr.IntByReference;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public class FlashPlayerPanel extends Panel implements Closeable, MediaDisplay {
private boolean executed = false;
private String flash;
private HANDLE pipe;
private HANDLE process;
private WinDef.HWND hwnd;
private WinDef.HWND hwndFrame;
private Component frame;
private boolean stopped = true;
private static final int CMD_PLAY = 1;
private static final int CMD_RESIZE = 2;
private static final int CMD_BGCOLOR = 3;
private static final int CMD_CURRENT_FRAME = 4;
private static final int CMD_TOTAL_FRAMES = 5;
private static final int CMD_PAUSE = 6;
private static final int CMD_RESUME = 7;
private static final int CMD_PLAYING = 8;
private static final int CMD_REWIND = 9;
private static final int CMD_GOTO = 10;
private static final int CMD_CALL = 11;
private static final int CMD_GETVARIABLE = 12;
private static final int CMD_SETVARIABLE = 13;
private static final int PIPE_TIMEOUT_MS = 1000;
private int frameRate;
public boolean specialPlayback = false;
private boolean specialPlaying = false;
public synchronized String getVariable(String name) throws IOException {
if (pipe != null) {
writeToPipe(new byte[]{CMD_GETVARIABLE});
int nameLen = name.getBytes().length;
writeToPipe(new byte[]{(byte) ((nameLen >> 8) & 0xff), (byte) (nameLen & 0xff)});
writeToPipe(name.getBytes());
byte res[] = new byte[2];
readFromPipe(res);
int retLen = ((res[0] & 0xff) << 8) + (res[1] & 0xff);
res = new byte[retLen];
readFromPipe(res);
String ret = new String(res, 0, retLen);
return ret;
}
return null;
}
public synchronized void setVariable(String name, String value) throws IOException {
if (pipe != null) {
writeToPipe(new byte[]{CMD_SETVARIABLE});
int nameLen = name.getBytes().length;
writeToPipe(new byte[]{(byte) ((nameLen >> 8) & 0xff), (byte) (nameLen & 0xff)});
writeToPipe(name.getBytes());
int valLen = value.getBytes().length;
writeToPipe(new byte[]{(byte) ((valLen >> 8) & 0xff), (byte) (valLen & 0xff)});
writeToPipe(value.getBytes());
}
}
public synchronized String call(String callString) throws IOException {
if (pipe != null) {
writeToPipe(new byte[]{CMD_CALL});
int callLen = callString.getBytes().length;
writeToPipe(new byte[]{(byte) ((callLen >> 8) & 0xff), (byte) (callLen & 0xff)});
writeToPipe(callString.getBytes());
byte res[] = new byte[2];
readFromPipe(res);
int retLen = ((res[0] & 0xff) << 8) + (res[1] & 0xff);
res = new byte[retLen];
readFromPipe(res);
String ret = new String(res, 0, retLen);
return ret;
}
return null;
}
private synchronized void resize() throws IOException {
if (pipe != null) {
writeToPipe(new byte[]{CMD_RESIZE});
writeToPipe(new byte[]{
(byte) (getWidth() / 256), (byte) (getWidth() % 256),
(byte) (getHeight() / 256), (byte) (getHeight() % 256),});
}
}
private int __getCurrentFrame() throws IOException {
byte[] res = new byte[2];
writeToPipe(new byte[]{CMD_CURRENT_FRAME});
readFromPipe(res);
return ((res[0] & 0xff) << 8) + (res[1] & 0xff);
}
@Override
public synchronized int getCurrentFrame() {
try {
if (specialPlayback) {
if (!specialPlaying) {
return specialPosition;
}
String posStr = getVariable("_root.my_sound.position");
if (posStr != null) {
return Integer.parseInt(posStr);
}
}
return __getCurrentFrame();
} catch (IOException ex) {
return 0;
}
}
@Override
public synchronized int getTotalFrames() {
try {
if (specialPlayback) {
String durStr = getVariable("_root.my_sound.duration");
if (durStr != null) {
return Integer.parseInt(durStr);
}
}
byte[] res = new byte[2];
writeToPipe(new byte[]{CMD_TOTAL_FRAMES});
readFromPipe(res);
return ((res[0] & 0xff) << 8) + (res[1] & 0xff);
} catch (IOException ex) {
return 0;
}
}
@Override
public synchronized void setBackground(Color color) {
try {
writeToPipe(new byte[]{CMD_BGCOLOR});
writeToPipe(new byte[]{(byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()});
} catch (IOException ex) {
}
}
public FlashPlayerPanel(Component frame) {
if (!Platform.isWindows()) {
throw new FlashUnsupportedException();
}
this.frame = frame;
addComponentListener(new ComponentListener() {
@Override
public void componentResized(ComponentEvent e) {
try {
resize();
} catch (IOException ex) {
}
}
@Override
public void componentMoved(ComponentEvent e) {
}
@Override
public void componentShown(ComponentEvent e) {
componentResized(e);
}
@Override
public void componentHidden(ComponentEvent e) {
}
});
}
private synchronized void execute() {
if (!executed) {
hwnd = new WinDef.HWND();
hwnd.setPointer(Native.getComponentPointer(this));
hwndFrame = new WinDef.HWND();
hwndFrame.setPointer(Native.getComponentPointer(frame));
startFlashPlayer();
executed = true;
}
}
private void restartFlashPlayer() {
Kernel32.INSTANCE.TerminateProcess(process, 0);
Kernel32.INSTANCE.CloseHandle(pipe);
startFlashPlayer();
}
private void startFlashPlayer() {
String path = Utf8Helper.urlDecode(FlashPlayerPanel.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String appDir = new File(path).getParentFile().getAbsolutePath();
if (!appDir.endsWith("\\")) {
appDir += "\\";
}
String exePath = appDir + "lib\\FlashPlayer.exe";
File f = new File(exePath);
if (!f.exists()) {
Logger.getLogger(FlashPlayerPanel.class.getName()).log(Level.SEVERE, "FlashPlayer.exe not found: " + f.getPath());
return;
}
String pipeName = "\\\\.\\pipe\\ffdec_flashplayer_" + hwnd.getPointer().hashCode();
pipe = Kernel32.INSTANCE.CreateNamedPipe(pipeName, Kernel32.PIPE_ACCESS_DUPLEX, Kernel32.PIPE_TYPE_BYTE, 1, 4096, 4096, 0, null);
SHELLEXECUTEINFO sei = new SHELLEXECUTEINFO();
sei.fMask = 0x00000040;
sei.lpFile = new WString(exePath);
sei.lpParameters = new WString(hwnd.getPointer().hashCode() + " " + hwndFrame.getPointer().hashCode());
sei.nShow = WinUser.SW_NORMAL;
Shell32.INSTANCE.ShellExecuteEx(sei);
process = sei.hProcess;
Kernel32.INSTANCE.ConnectNamedPipe(pipe, null);
}
public synchronized void stopSWF() {
displaySWF("-", null, 1);
stopped = true;
}
public synchronized boolean isStopped() {
return stopped;
}
public synchronized void displaySWF(String flash, Color bgColor, int frameRate) {
try {
this.flash = flash;
repaint();
this.frameRate = frameRate;
execute();
if (bgColor != null) {
setBackground(bgColor);
}
resize();
if (pipe != null) {
writeToPipe(new byte[]{CMD_PLAY});
writeToPipe(new byte[]{(byte) flash.getBytes().length});
writeToPipe(flash.getBytes());
}
stopped = false;
specialPlaying = false;
specialPosition = 0;
if (specialPlayback) {
play();
}
} catch (IOException ex) {
}
}
@Override
public void close() throws IOException {
Kernel32.INSTANCE.CloseHandle(pipe);
Kernel32.INSTANCE.TerminateProcess(process, 0);
}
@Override
public void paint(Graphics g) {
if (flash != null) {
execute();
}
super.paint(g);
}
private int specialPosition = 0;
private synchronized void __pause() throws IOException {
writeToPipe(new byte[]{CMD_PAUSE});
}
@Override
public void pause() {
try {
if (specialPlayback) {
specialPosition = getCurrentFrame();
__gotoFrame(3);
__play();
specialPlaying = false;
return;
}
__pause();
} catch (IOException ex) {
}
}
@Override
public void rewind() {
try {
if (specialPlayback) {
boolean plays = specialPlaying;
pause();
specialPosition = 0;
if (plays) {
play();
}
return;
}
writeToPipe(new byte[]{CMD_REWIND});
} catch (IOException ex) {
}
}
private synchronized void __play() throws IOException {
writeToPipe(new byte[]{CMD_RESUME});
}
@Override
public void play() {
try {
if (specialPlayback) {
double p = (((double) specialPosition) / 1000.0);
setVariable("_root.execParam", "" + p);
__gotoFrame(1);
__play();
specialPlaying = true;
return;
}
__play();
} catch (IOException ex) {
}
}
@Override
public boolean isPlaying() {
try {
if (specialPlayback) {
return specialPlaying;
}
writeToPipe(new byte[]{CMD_PLAYING});
byte[] res = new byte[1];
readFromPipe(res);
return res[0] == 1;
} catch (IOException ex) {
return false;
}
}
private synchronized void __gotoFrame(int frame) throws IOException {
writeToPipe(new byte[]{CMD_GOTO});
writeToPipe(new byte[]{(byte) ((frame >> 8) & 0xff), (byte) (frame & 0xff)});
}
@Override
public void gotoFrame(int frame) {
try {
if (specialPlayback) {
if (specialPlaying) {
pause();
specialPosition = frame;
play();
} else {
specialPosition = frame;
}
return;
}
__gotoFrame(frame);
} catch (IOException ex) {
}
}
@Override
public int getFrameRate() {
if (specialPlayback) {
return 1000;
}
return frameRate;
}
@Override
public boolean isLoaded() {
return !isStopped();
}
private synchronized boolean writeToPipe(final byte[] data) throws IOException {
final IntByReference ibr = new IntByReference();
int result = -1;
try {
result = CancellableWorker.call(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
boolean result = Kernel32.INSTANCE.WriteFile(pipe, data, data.length, ibr, null);
if (!result) {
return Kernel32.INSTANCE.GetLastError();
}
if (ibr.getValue() != data.length) {
return -1;
}
return 0;
}
}, PIPE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
// ignore
}
if (result != 0) {
if (result == Kernel32.ERROR_NO_DATA || result == -1) {
restartFlashPlayer();
throw new IOException("Pipe write error.");
} else {
// System.out.println("pipe write failed. datalength: " + data.length + " error:" + result);
}
}
return result == 0;
}
private synchronized boolean readFromPipe(final byte[] res) throws IOException {
final IntByReference ibr = new IntByReference();
int result = -1;
try {
result = CancellableWorker.call(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int read = 0;
while (read < res.length) {
byte[] data = new byte[res.length - read];
boolean result = Kernel32.INSTANCE.ReadFile(pipe, data, data.length, ibr, null);
if (!result) {
return Kernel32.INSTANCE.GetLastError();
}
int readNow = ibr.getValue();
System.arraycopy(data, 0, res, read, readNow);
read += readNow;
}
return 0;
}
}, PIPE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
// ignore
}
if (result != 0) {
if (result == Kernel32.ERROR_BROKEN_PIPE || result == -1) {
restartFlashPlayer();
throw new IOException("Pipe read error.");
} else {
// System.out.println("pipe read failed. result: " + result + " datalength: " + res.length + " received: " + ibr.getValue() + " error: " + result);
}
}
return result == 0;
}
}