diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1fba159fbb..5b025a1893 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,18 @@
# Change Log
All notable changes to this project will be documented in this file.
+## [18.4.1] - 2023-04-05
+### Fixed
+- [#1993] Incorrect scroll position causing shapes to be hidden
+- [#1994] Replace command in commandline with three argument causing replacements file load
+- [#1477] Open file (Context menu) with unicode characters, unicode in paths, on Windows
+- Starting app with parameters causing wrong GUI init
+- [#1991] ConcurrentModificationException on clearing cache thread
+- [#1999] AS3 decompilation - XML constructor call with other than string argument
+
+### Changed
+- [#1996] Items are now exported in order of appearance in the tag tree (usually SWF order), previously was it in order of selection
+
## [18.4.0] - 2023-03-19
### Added
- AS3 support for logical AND/OR compound operator
@@ -2862,6 +2874,7 @@ All notable changes to this project will be documented in this file.
### Added
- Initial public release
+[18.4.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version18.4.0...version18.4.1
[18.4.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version18.3.6...version18.4.0
[18.3.6]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version18.3.5...version18.3.6
[18.3.5]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version18.3.4...version18.3.5
@@ -3008,6 +3021,12 @@ 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
+[#1993]: https://www.free-decompiler.com/flash/issues/1993
+[#1994]: https://www.free-decompiler.com/flash/issues/1994
+[#1477]: https://www.free-decompiler.com/flash/issues/1477
+[#1991]: https://www.free-decompiler.com/flash/issues/1991
+[#1999]: https://www.free-decompiler.com/flash/issues/1999
+[#1996]: https://www.free-decompiler.com/flash/issues/1996
[#1888]: https://www.free-decompiler.com/flash/issues/1888
[#1892]: https://www.free-decompiler.com/flash/issues/1892
[#355]: https://www.free-decompiler.com/flash/issues/355
diff --git a/build.xml b/build.xml
index db4a475887..94fc8df407 100644
--- a/build.xml
+++ b/build.xml
@@ -395,7 +395,7 @@
-
+
-Djava.net.preferIPv4Stack=true
-Djna.nosys=true
@@ -444,7 +443,7 @@
-
+ -->
@@ -487,18 +486,18 @@
-
-
+
+
-
-
+
+
diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructIns.java
index 13d7a5b87e..2d5efd275d 100644
--- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructIns.java
+++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructIns.java
@@ -80,7 +80,7 @@ public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instru
public static boolean walkXML(GraphTargetItem item, List list) {
boolean ret = walkXMLSub(item, list);
- if (list.size() == 1) {
+ if (list.size() == 1 && (list.get(0) instanceof StringAVM2Item)) {
return true;
}
return ret;
diff --git a/libsrc/ffdec_lib/src/com/jpexs/helpers/Cache.java b/libsrc/ffdec_lib/src/com/jpexs/helpers/Cache.java
index 7a928cc804..e4fb32b4b9 100644
--- a/libsrc/ffdec_lib/src/com/jpexs/helpers/Cache.java
+++ b/libsrc/ffdec_lib/src/com/jpexs/helpers/Cache.java
@@ -22,7 +22,6 @@
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -43,6 +42,8 @@ public class Cache implements Freed {
private Map cache;
private Map lastAccessed;
+ private static final Object instancesLock = new Object();
+
private static final List> instances = new ArrayList<>();
public static final int STORAGE_FILES = 1;
@@ -54,27 +55,28 @@ public class Cache implements Freed {
private final boolean memoryOnly;
private final String name;
-
+
private final boolean temporary;
-
+
private static final long CLEAN_INTERVAL = 5 * 1000; //5 seconds
-
- private static Thread oldCleaner = null;
+
+ private static Thread oldCleaner = null;
static {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
- for (WeakReference cw : instances) {
- Cache c = cw.get();
- if (c != null) {
- c.clear();
- c.free();
+ synchronized (instancesLock) {
+ for (WeakReference cw : instances) {
+ Cache c = cw.get();
+ if (c != null) {
+ c.clear();
+ c.free();
+ }
}
}
}
-
});
}
@@ -83,37 +85,41 @@ public static Cache getInstance(boolean weak, boolean memoryOnly, S
oldCleaner = new Thread("Old cache cleaner") {
@Override
public void run() {
- while(!Thread.interrupted()) {
+ while (!Thread.interrupted()) {
try {
Thread.sleep(CLEAN_INTERVAL);
} catch (InterruptedException ex) {
return;
}
try {
- clearAllOld();
+ clearAllOld();
} catch (Exception cme) {
Logger.getLogger(Cache.class.getSimpleName()).log(Level.SEVERE, "Error during clearing cache thread", cme);
}
}
- }
+ }
};
oldCleaner.setDaemon(true);
oldCleaner.setPriority(Thread.MIN_PRIORITY);
oldCleaner.start();
}
Cache instance = new Cache<>(weak, memoryOnly, name, temporary);
- instances.add(new WeakReference<>(instance));
+ synchronized (instancesLock) {
+ instances.add(new WeakReference<>(instance));
+ }
return instance;
}
private static int storageType = STORAGE_FILES;
public static void clearAll() {
- for (WeakReference cw : instances) {
- Cache c = cw.get();
- if (c != null) {
- c.clear();
- c.initCache();
+ synchronized (instancesLock) {
+ for (WeakReference cw : instances) {
+ Cache c = cw.get();
+ if (c != null) {
+ c.clear();
+ c.initCache();
+ }
}
}
}
@@ -174,7 +180,7 @@ private Cache(boolean weak, boolean memoryOnly, String name, boolean temporary)
initCache();
}
- public synchronized boolean contains(K key) {
+ public synchronized boolean contains(K key) {
boolean ret = cache.containsKey(key);
if (ret) {
lastAccessed.put(key, System.currentTimeMillis());
@@ -208,7 +214,7 @@ public synchronized void put(K key, V value) {
@Override
public boolean isFreeing() {
- throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ throw new UnsupportedOperationException("Not supported yet.");
}
@Override
@@ -223,7 +229,7 @@ public Set keys() {
ret.addAll(cache.keySet());
return ret;
}
-
+
private synchronized int clearOld() {
long currentTime = System.currentTimeMillis();
Set keys = new HashSet<>(lastAccessed.keySet());
@@ -232,26 +238,28 @@ private synchronized int clearOld() {
return 0;
}
int num = 0;
- for(K key:keys) {
+ for (K key : keys) {
long time = lastAccessed.get(key);
if (time < currentTime - temporaryThreshold) {
remove(key);
num++;
}
- }
+ }
return num;
}
-
+
private static void clearAllOld() {
int num = 0;
- for (WeakReference cw : instances) {
- Cache c = cw.get();
- if (c != null) {
- if (c.temporary) {
- num += c.clearOld();
+ synchronized (instancesLock) {
+ for (WeakReference cw : instances) {
+ Cache c = cw.get();
+ if (c != null) {
+ if (c.temporary) {
+ num += c.clearOld();
+ }
}
}
- }
+ }
if (num > 0) {
System.gc();
}
diff --git a/resources/com.jpexs.decompiler.flash.metainfo.xml b/resources/com.jpexs.decompiler.flash.metainfo.xml
index 5b92bb8509..bc1d62e388 100644
--- a/resources/com.jpexs.decompiler.flash.metainfo.xml
+++ b/resources/com.jpexs.decompiler.flash.metainfo.xml
@@ -63,6 +63,23 @@
+
+
+ Fixed
+
+ - #1993 Incorrect scroll position causing shapes to be hidden
+ - #1994 Replace command in commandline with three argument causing replacements file load
+ - #1477 Open file (Context menu) with unicode characters, unicode in paths, on Windows
+ - Starting app with parameters causing wrong GUI init
+ - #1991 ConcurrentModificationException on clearing cache thread
+ - #1999 AS3 decompilation - XML constructor call with other than string argument
+
+ Changed
+
+ - #1996 Items are now exported in order of appearance in the tag tree (usually SWF order), previously was it in order of selection
+
+
+
Added
diff --git a/resources/ffdec.exe b/resources/ffdec.exe
new file mode 100644
index 0000000000..308cc1cc35
Binary files /dev/null and b/resources/ffdec.exe differ
diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java
index 562f4ab575..c032bf9b5f 100644
--- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java
+++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java
@@ -3143,7 +3143,7 @@ private static void parseReplace(Stack args, String charset, boolean air
File inFile = new File(args.pop());
File outFile = new File(args.pop());
- if (args.size() == 3) {
+ if (args.size() == 1) {
System.out.println("Replacing - only single argument passed, taking it as file to load replacements from");
try {
List lines = Files.readAllLines(Paths.get(args.pop()), StandardCharsets.UTF_8);
diff --git a/src/com/jpexs/decompiler/flash/gui/FolderListPanel.java b/src/com/jpexs/decompiler/flash/gui/FolderListPanel.java
index fce2ec0b34..ac075ae4e6 100644
--- a/src/com/jpexs/decompiler/flash/gui/FolderListPanel.java
+++ b/src/com/jpexs/decompiler/flash/gui/FolderListPanel.java
@@ -33,11 +33,14 @@
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
import java.util.WeakHashMap;
import javax.swing.Icon;
import javax.swing.JLabel;
@@ -63,8 +66,7 @@ public class FolderListPanel extends JPanel {
private int selectedIndex = -1;
- public Map selectedItems = new HashMap<>();
-
+ private Map selectedItems = new TreeMap<>();
private static final int PREVIEW_SIZE = 150;
@@ -160,7 +162,7 @@ public void mousePressed(MouseEvent e) {
}
if (SwingUtilities.isRightMouseButton(e)) {
- mainPanel.getContextPopupMenu().update(new ArrayList<>(selectedItems.values()));
+ mainPanel.getContextPopupMenu().update(getSelectedItemsSorted());
mainPanel.getContextPopupMenu().show(FolderListPanel.this, e.getX(), e.getY());
}
repaint();
@@ -270,4 +272,12 @@ public void paint(Graphics g) {
}
}
}
+
+ public List getSelectedItemsSorted() {
+ return new ArrayList<>(selectedItems.values());
+ }
+
+ public boolean isSomethingSelected() {
+ return !selectedItems.isEmpty();
+ }
}
diff --git a/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java
index 430e93b241..476cb0154c 100644
--- a/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java
+++ b/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java
@@ -44,16 +44,20 @@
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.TreeMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
+import javax.swing.tree.TreePath;
import org.pushingpixels.substance.api.ColorSchemeAssociationKind;
import org.pushingpixels.substance.api.ComponentState;
import org.pushingpixels.substance.api.DecorationAreaType;
@@ -74,11 +78,7 @@ public class FolderPreviewPanel extends JPanel {
private boolean repaintQueued;
- private int lastWidth;
-
- private int lastHeight;
-
- public Map selectedItems = new LinkedHashMap<>();
+ private Map selectedItems = new TreeMap<>();
private Cache cachedPreviews;
@@ -156,7 +156,7 @@ public void mousePressed(MouseEvent e) {
}
if (SwingUtilities.isRightMouseButton(e)) {
- mainPanel.getContextPopupMenu().update(new ArrayList<>(selectedItems.values()));
+ mainPanel.getContextPopupMenu().update(getSelectedItemsSorted());
mainPanel.getContextPopupMenu().show(FolderPreviewPanel.this, e.getX(), e.getY());
}
repaint();
@@ -386,4 +386,22 @@ private SerializableImage renderImage(SWF swf, TreeItem treeItem) {
}
return image;
}
+
+ public List getSelectedItemsSorted() {
+ return new ArrayList<>(selectedItems.values());
+ }
+
+ public boolean isSomethingSelected() {
+ return !selectedItems.isEmpty();
+ }
+
+ public Map getSelectedItems() {
+ return selectedItems;
+ }
+
+ public void setSelectedItems(Map selectedItems) {
+ this.selectedItems = selectedItems;
+ }
+
+
}
diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java
index ad2bae256b..fd6a49a6ad 100644
--- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java
+++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java
@@ -296,14 +296,13 @@ public final class ImagePanel extends JPanel implements MediaDisplay {
private JScrollBar verticalScrollBar;
private boolean updatingScrollBars = false;
private final int SCROLL_SPACE_BEFORE = (int) SWF.unitDivisor * 500;
-
+
private List showPoints1 = new ArrayList<>();
-
+
private List showPoints2 = new ArrayList<>();
-
+
private int displayedFrame = 0;
-
public void setShowPoints(List showPoints1, List showPoints2) {
this.showPoints1 = showPoints1;
this.showPoints2 = showPoints2;
@@ -651,8 +650,9 @@ private void centerImage() {
double dw = rect.Xmin * zoomDouble / SWF.unitDivisor;
double dh = rect.Ymin * zoomDouble / SWF.unitDivisor;
offsetPoint.setLocation(
- iconPanel.getWidth() / 2 - w / 2 + dw,
- iconPanel.getHeight() / 2 - h / 2 + dh);
+ iconPanel.getWidth() / 2 - w / 2 - dw,
+ iconPanel.getHeight() / 2 - h / 2 - dh
+ );
/*Timer tim = new Timer();
tim.schedule(new TimerTask() {
@Override
@@ -819,7 +819,7 @@ public void render() {
RECT timRect = timelined.getRect();
double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value;
AffineTransform trans = new AffineTransform();
- trans.translate(offsetPoint.getX(),offsetPoint.getY());
+ trans.translate(offsetPoint.getX(), offsetPoint.getY());
trans.scale(1 / SWF.unitDivisor, 1 / SWF.unitDivisor);
trans.scale(zoomDouble, zoomDouble);
AffineTransform oldTransform = g2.getTransform();
@@ -931,7 +931,7 @@ public void render() {
}
}*/
}
-
+
for (int i = 0; i < showPoints1.size(); i++) {
int xt = showPoints1.get(i).x;
int pointSize = 3;
@@ -941,7 +941,7 @@ public void render() {
g2.setPaint(Color.blue);
g2.fill(pointShape);
}
-
+
for (int i = 0; i < showPoints2.size(); i++) {
int xt = showPoints2.get(i).x;
int pointSize = 3;
@@ -1195,14 +1195,14 @@ public void mouseReleased(MouseEvent e) {
positions.add(di.pathPoint);
splitPositions.add(di.pathPosition);
}*/
- for (DistanceItem di:pathPointsUnderCursor) {
+ for (DistanceItem di : pathPointsUnderCursor) {
fireEdgeSplit(di.pathPoint, di.pathPosition);
}
selectedPoints.clear();
pointsUnderCursor.clear();
pathPointsUnderCursor.clear();
repaint();
- }
+ }
updateScrollBarMinMax();
}
@@ -1218,7 +1218,6 @@ public void mouseReleased(MouseEvent e) {
registrationPoint = new Point2D.Double(registrationPointUpdated.getX(), registrationPointUpdated.getY());
transform = new Matrix(transformUpdated);
transformUpdated = null;
-
Rectangle2D transBoundsAfter = getTransformBounds();
Point2D transRegPointAfter = registrationPoint;
@@ -1236,7 +1235,7 @@ public void mouseReleased(MouseEvent e) {
|| mode == Cursor.W_RESIZE_CURSOR;
if (!isResize && mode != Cursor.DEFAULT_CURSOR && !transRegPointPercentBefore.equals(transRegPointPercentAfter)) {
registrationPointPosition = null;
- }
+ }
}
calcRect(); //do not put this inside synchronized block, it cause deadlock
fireBoundsChange(getTransformBounds(), registrationPoint, registrationPointPosition);
@@ -1771,7 +1770,7 @@ public void mouseDragged(MouseEvent e) {
repaint();
}
}
- }
+ }
@Override
public void mouseMoved(MouseEvent e) {
@@ -2062,8 +2061,8 @@ private void calcRect(Zoom z) {
} else {
w1 = (int) (timelined.getRect().getWidth() * zoomDouble / SWF.unitDivisor);
h1 = (int) (timelined.getRect().getHeight() * zoomDouble / SWF.unitDivisor);
- dx = (int)(timelined.getRect().Xmin * zoomDouble / SWF.unitDivisor);
- dy = (int)(timelined.getRect().Ymin * zoomDouble / SWF.unitDivisor);
+ dx = (int) (timelined.getRect().Xmin * zoomDouble / SWF.unitDivisor);
+ dy = (int) (timelined.getRect().Ymin * zoomDouble / SWF.unitDivisor);
}
//HERE
@@ -2217,7 +2216,7 @@ public void hideMouseSelection() {
debugLabel.setText(DEFAULT_DEBUG_LABEL_TEXT);
}
}
-
+
public ImagePanel() {
super(new BorderLayout());
//iconPanel.setHorizontalAlignment(JLabel.CENTER);
@@ -2286,7 +2285,7 @@ public void adjustmentValueChanged(AdjustmentEvent e) {
iconPanel.calcRect();
_viewRect = getViewRect();
updatingScrollBars = false;
- redraw();
+ redraw();
}
});
@@ -2432,8 +2431,6 @@ public synchronized void zoom(Zoom zoom) {
public Timelined getTimelined() {
return timelined;
}
-
-
private void updateScrollBarMinMax() {
@@ -2443,13 +2440,13 @@ private void updateScrollBarMinMax() {
return;
}
RECT timRect = timelined.getRect();
-
+
/*
int h_value = horizontalScrollBar.getValue();
int h_visibleAmount = horizontalScrollBar.getVisibleAmount();
*/
int h_maximum = timRect.Xmax;
-
+
if (hilightedPoints != null || freeTransformDepth > -1) {
h_maximum += SCROLL_SPACE_BEFORE;
}
@@ -2485,9 +2482,9 @@ private void updateScrollBarMinMax() {
verticalScrollBar.setMinimum(v_minimum);
verticalScrollBar.setMaximum(v_maximum);
-
+
horizontalScrollBar.setVisible(horizontalScrollBar.getVisibleAmount() < horizontalScrollBar.getMaximum() - horizontalScrollBar.getMinimum());
- verticalScrollBar.setVisible(verticalScrollBar.getVisibleAmount() < verticalScrollBar.getMaximum() - verticalScrollBar.getMinimum());
+ verticalScrollBar.setVisible(verticalScrollBar.getVisibleAmount() < verticalScrollBar.getMaximum() - verticalScrollBar.getMinimum());
}
private synchronized void updateScrollBars() {
@@ -2506,29 +2503,34 @@ public void run() {
int w = iconPanel.getWidth();
int h = iconPanel.getHeight();
-
int h_visibleAmount = (int) Math.round(w * SWF.unitDivisor / zoomDouble);
-
+
Point2D leftTop = toTransformPoint(new Point2D.Double(0, 0));
-
+
Point2D rightBottom = toTransformPoint(new Point2D.Double(w, h));
/*if (rightBottom.getX() > timRect.Xmax) {
h_visibleAmount = timRect.Xmax - (int)leftTop.getX();
}*/
-
- int h_value = (int)Math.round(leftTop.getX());//timRect.Xmin + (int) Math.round(-offsetPoint.getX() / zoomDouble * SWF.unitDivisor);
+
+ int h_value = (int) Math.round(leftTop.getX());//timRect.Xmin + (int) Math.round(-offsetPoint.getX() / zoomDouble * SWF.unitDivisor);
horizontalScrollBar.setVisibleAmount(h_visibleAmount);
horizontalScrollBar.setValue(h_value);
int v_visibleAmount = (int) Math.round(h * SWF.unitDivisor / zoomDouble);
- int v_value = (int)Math.round(leftTop.getY()); //timRect.Ymin + (int) Math.round(-offsetPoint.getY() / zoomDouble * SWF.unitDivisor);
+ int v_value = (int) Math.round(leftTop.getY()); //timRect.Ymin + (int) Math.round(-offsetPoint.getY() / zoomDouble * SWF.unitDivisor);
verticalScrollBar.setVisibleAmount(v_visibleAmount);
verticalScrollBar.setValue(v_value);
updateScrollBarMinMax();
-
- /*boolean hVisibleBefore = horizontalScrollBar.isVisible();
+
+ if (zoom.fit) {
+ verticalScrollBar.setVisible(false);
+ horizontalScrollBar.setVisible(false);
+ updatingScrollBars = false;
+ return;
+ }
+ boolean hVisibleBefore = horizontalScrollBar.isVisible();
horizontalScrollBar.setVisible(horizontalScrollBar.getVisibleAmount() < horizontalScrollBar.getMaximum() - horizontalScrollBar.getMinimum());
boolean hVisibleAfter = horizontalScrollBar.isVisible();
@@ -2536,15 +2538,11 @@ public void run() {
verticalScrollBar.setVisible(verticalScrollBar.getVisibleAmount() < verticalScrollBar.getMaximum() - verticalScrollBar.getMinimum());
boolean vVisibleAfter = verticalScrollBar.isVisible();
-
if (hVisibleAfter != hVisibleBefore || vVisibleAfter != vVisibleBefore) {
updateScrollBars();
- }*/
- updatingScrollBars = false;
- if (zoom.fit) {
- verticalScrollBar.setVisible(false);
- horizontalScrollBar.setVisible(false);
}
+ updatingScrollBars = false;
+
}
});
}
@@ -2633,6 +2631,8 @@ public synchronized boolean zoomAvailable() {
return zoomAvailable;
}
+ private Timer setTimelinedTimer = null;
+
public void setTimelined(final Timelined drawable, final SWF swf, int frame, boolean showObjectsUnderCursor, boolean autoPlay, boolean frozen, boolean alwaysDisplay, boolean muted, boolean mutable) {
Stage stage = new Stage(drawable) {
@Override
@@ -2690,7 +2690,8 @@ public void trace(Object... val) {
}
};
lda = new LocalDataArea(stage);
- synchronized (ImagePanel.this) {
+ synchronized (ImagePanel.this) {
+ updatingScrollBars = true;
stopInternal();
if (drawable instanceof ButtonTag) {
frame = ButtonTag.FRAME_UP;
@@ -2699,7 +2700,7 @@ public void trace(Object... val) {
bounds = null;
displayObjectCache.clear();
this.timelined = drawable;
- centerImage();
+ centerImage();
this.swf = swf;
zoomAvailable = true;
if (frame > -1) {
@@ -2874,7 +2875,7 @@ private synchronized void stopAllSounds() {
private void clear() {
Timer ptimer = timer;
-
+
if (ptimer != null) {
timer = null;
ptimer.cancel();
@@ -2886,7 +2887,7 @@ private void clear() {
displayObjectCache.clear();
}
- private void nextFrame(Timer thisTimer, final int cnt, final int timeShouldBe) {
+ private void nextFrame(Timer thisTimer, final int cnt, final int timeShouldBe) {
synchronized (ImagePanel.class) {
if (timelined != null && timer == thisTimer) {
int frameCount = timelined.getTimeline().getFrameCount();
@@ -3183,7 +3184,6 @@ private ExportRectangle getViewRect() {
viewRect.yMin += timRect.Ymin;
viewRect.xMax += timRect.Xmin;
viewRect.yMax += timRect.Ymin;*/
-
viewRect.xMax = viewRect.xMin + (int) (iconPanel.getWidth() * SWF.unitDivisor / zoomDouble);
viewRect.yMax = viewRect.yMin + (int) (iconPanel.getHeight() * SWF.unitDivisor / zoomDouble);
return viewRect;
@@ -3591,7 +3591,7 @@ public synchronized void play() {
frame = 0;
prevFrame = -1;
}
-
+
startTimer(timeline, true);
}
}
@@ -3652,7 +3652,7 @@ private void scheduleTask(boolean singleFrame, long msDelay, boolean first) {
TimerTask task = new TimerTask() {
public final Timer thisTimer = timer;
- public final boolean isSingleFrame = singleFrame;
+ public final boolean isSingleFrame = singleFrame;
@Override
public void run() {
@@ -3714,7 +3714,7 @@ public void run() {
if (frameCount == 1 || stillFrame) { //We have only one frame, so the ticks on that frame equal ticks on whole timeline
currentFrameTicks = ticksFromStart;
}
-
+
if (first) {
drawFrame(thisTimer, true);
} else {
@@ -3773,7 +3773,7 @@ public void run() {
}
timer = new Timer();
fpsShouldBe = timeline.frameRate;
- fpsIs = fpsShouldBe;
+ fpsIs = fpsShouldBe;
scheduleTask(singleFrame, 0, true);
}
@@ -3949,7 +3949,7 @@ private Point2D toImagePoint(Point2D point) {
double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value;
if (lowQuality) {
zoomDouble /= LQ_FACTOR;
- }
+ }
double rx = point.getX() * zoomDouble / SWF.unitDivisor + offsetPoint.getX(); // + offsetXRef.getVal();
double ry = point.getY() * zoomDouble / SWF.unitDivisor + offsetPoint.getY(); // + offsetYRef.getVal();
diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java
index 483530f2a0..aa85624e0b 100644
--- a/src/com/jpexs/decompiler/flash/gui/Main.java
+++ b/src/com/jpexs/decompiler/flash/gui/Main.java
@@ -107,6 +107,7 @@
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
+import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.nio.file.FileSystems;
import java.nio.file.StandardWatchEventKinds;
@@ -2649,11 +2650,28 @@ public boolean accept(File dir, String name) {
}
}
+ /**
+ * To bypass wrong encoded unicode characters coming from EXE,
+ * it Launch5j encodes characters using URLEncoder.
+ * @param args
+ */
+ private static void decodeLaunch5jArgs(String[] args) {
+ String encargs = System.getProperty("l5j.encargs");
+ if ("true".equals(encargs) || "1".equals(encargs)) {
+ for (int i = 0; i < args.length; ++i) {
+ try {
+ args[i] = URLDecoder.decode(args[i], "UTF-8");
+ } catch (Exception e) { }
+ }
+ }
+ }
+
/**
* @param args the command line arguments
* @throws IOException On error
*/
public static void main(String[] args) throws IOException {
+ decodeLaunch5jArgs(args);
setSessionLoaded(false);
clearTemp();
@@ -2686,13 +2704,13 @@ public static void main(String[] args) throws IOException {
reloadLastSession();
}
});
- } else {
+ } else {
checkLibraryVersion();
setSessionLoaded(true);
String[] filesToOpen = CommandLineArgumentParser.parseArguments(args);
if (filesToOpen != null && filesToOpen.length > 0) {
+ initGui();
View.execInEventDispatch(() -> {
- initGui();
shouldCloseWhenClosingLoadingDialog = true;
if (Configuration.allowOnlyOneInstance.get() && FirstInstance.openFiles(Arrays.asList(filesToOpen))) { //Try to open in first instance
Main.exit();
diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java
index e37e9717d4..bdb8aa76d7 100644
--- a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java
+++ b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java
@@ -1405,18 +1405,7 @@ public void createMenuBar() {
path = mainPath + "\\..\\..\\libsrc\\ffdec_lib\\testdata\\as3\\as3.swf";
sourceInfos[1] = new OpenableSourceInfo(null, path, null);
Main.openFile(sourceInfos);
- }, PRIORITY_MEDIUM, null, true, null, false);
- addMenuItem("/debug/createNewSwf", "Create new SWF", "continue16", e -> {
- SWF swf = new SWF();
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- swf.saveTo(baos);
- } catch (IOException ex) {
- Logger.getLogger(MainFrameMenu.class.getName()).log(Level.SEVERE, null, ex);
- }
-
- Main.openFile(new OpenableSourceInfo(new ByteArrayInputStream(baos.toByteArray()), "new.swf", "New SWF"));
- }, PRIORITY_MEDIUM, null, true, null, false);
+ }, PRIORITY_MEDIUM, null, true, null, false);
finishMenu("/debug");
}
diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java
index 6858804206..f50cf22be9 100644
--- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java
+++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java
@@ -491,12 +491,12 @@ private void handleKeyReleased(KeyEvent e) {
Object source = e.getSource();
List items = new ArrayList<>();
if (source == folderPreviewPanel) {
- items.addAll(folderPreviewPanel.selectedItems.values());
+ items.addAll(folderPreviewPanel.getSelectedItemsSorted());
} else if (source == folderListPanel) {
- items.addAll(folderListPanel.selectedItems.values());
+ items.addAll(folderListPanel.getSelectedItemsSorted());
} else {
AbstractTagTree tree = (AbstractTagTree) e.getSource();
- TreePath[] paths = tree.getSelectionPaths();
+ TreePath[] paths = tree.getSelectionPathsSorted();
if (paths != null) {
for (TreePath treePath : paths) {
TreeItem item = (TreeItem) treePath.getLastPathComponent();
@@ -578,12 +578,12 @@ private void handleKeyPressed(KeyEvent e) {
Object source = e.getSource();
List items = new ArrayList<>();
if (source == folderPreviewPanel) {
- items.addAll(folderPreviewPanel.selectedItems.values());
+ items.addAll(folderPreviewPanel.getSelectedItemsSorted());
} else if (source == folderListPanel) {
- items.addAll(folderListPanel.selectedItems.values());
+ items.addAll(folderListPanel.getSelectedItemsSorted());
} else {
AbstractTagTree tree = (AbstractTagTree) e.getSource();
- TreePath[] paths = tree.getSelectionPaths();
+ TreePath[] paths = tree.getSelectionPathsSorted();
if (paths != null) {
for (TreePath treePath : paths) {
TreeItem item = (TreeItem) treePath.getLastPathComponent();
@@ -5049,7 +5049,7 @@ public void reload(boolean forceReload, boolean scrollToVisible) {
JScrollBar folderPreviewScrollBar = ((JScrollPane)folderPreviewPanel.getParent().getParent()).getVerticalScrollBar();
int scrollValue = folderPreviewScrollBar.getValue();
- Map folderItems = new HashMap<>(folderPreviewPanel.selectedItems);
+ Map folderItems = new HashMap<>(folderPreviewPanel.getSelectedItems());
if (scrollToVisible) {
@@ -5269,7 +5269,7 @@ public void reload(boolean forceReload, boolean scrollToVisible) {
pinsPanel.setCurrent(oldItem);
}
- folderPreviewPanel.selectedItems = folderItems;
+ folderPreviewPanel.setSelectedItems(folderItems);
folderPreviewScrollBar.setValue(scrollValue);
View.execInEventDispatchLater(new Runnable(){
diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java b/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java
index 923bb30578..8340aad6f7 100644
--- a/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java
+++ b/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java
@@ -102,6 +102,7 @@
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -501,8 +502,7 @@ public void getAllSubs(TreeItem o, List ret) {
}
public List getAllSelected() {
- TreeSelectionModel tsm = getSelectionModel();
- TreePath[] tps = tsm.getSelectionPaths();
+ TreePath[] tps = getSelectionPathsSorted();
List ret = new ArrayList<>();
if (tps == null) {
return ret;
@@ -525,12 +525,25 @@ public List getAllSubsForItems(List items) {
return ret;
}
+ public TreePath[] getSelectionPathsSorted() {
+ TreePath[] paths = getSelectionPaths();
+ if (paths == null) {
+ return null;
+ }
+ Arrays.sort(paths, new Comparator(){
+ @Override
+ public int compare(TreePath o1, TreePath o2) {
+ return getRowForPath(o1) - getRowForPath(o2);
+ }
+ });
+ return paths;
+ }
+
public List getSelected() {
- if (!mainPanel.folderPreviewPanel.selectedItems.isEmpty()) {
- return new ArrayList<>(mainPanel.folderPreviewPanel.selectedItems.values());
+ if (mainPanel.folderPreviewPanel.isSomethingSelected()) {
+ return mainPanel.folderPreviewPanel.getSelectedItemsSorted();
}
- TreeSelectionModel tsm = getSelectionModel();
- TreePath[] tps = tsm.getSelectionPaths();
+ TreePath[] tps = getSelectionPathsSorted();
List ret = new ArrayList<>();
if (tps == null) {
return ret;
diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java
index 1bf76edb43..9545811d88 100644
--- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java
+++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java
@@ -312,12 +312,14 @@ public static List getSwfFolderItemNestedTagIds(String folderName, bool
@Override
public List getSelection(Openable openable) {
List sel;
- if (mainPanel.folderPreviewPanel.selectedItems.isEmpty()) {
+ if (!mainPanel.folderPreviewPanel.isSomethingSelected()) {
sel = getAllSelected();
} else {
sel = new ArrayList<>();
- for (TreeItem treeItem : mainPanel.folderPreviewPanel.selectedItems.values()) {
+ List siSorted = mainPanel.folderPreviewPanel.getSelectedItemsSorted();
+
+ for (TreeItem treeItem : siSorted) {
sel.add(treeItem);
getAllSubs(treeItem, sel);
}
diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java
index 4d1a4bdb2b..26dda40869 100644
--- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java
+++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java
@@ -645,7 +645,7 @@ public void mouseClicked(MouseEvent e) {
getTree().setSelectionRow(row);
}
- TreePath[] paths = getTree().getSelectionPaths();
+ TreePath[] paths = getTree().getSelectionPathsSorted();
if (paths == null || paths.length == 0) {
return;
}
@@ -2775,7 +2775,7 @@ public void tagRemoved(Tag tag) {
}
};
- if (mainPanel.folderPreviewPanel.selectedItems.isEmpty()) {
+ if (!mainPanel.folderPreviewPanel.isSomethingSelected()) {
mainPanel.treeOperation(r);
} else {
//current folder must stay selected