diff --git a/CHANGELOG.md b/CHANGELOG.md index eddc91b54..39392cda5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ### Added - [#1414] Cancelling in-progress exportation - [#1755] Copy tags to tag clipboard and paste them elsewhere +- [#1460] Bulk importing images ### Fixed - FLA export printing xxx string on exporting character with id 320 @@ -2514,6 +2515,7 @@ All notable changes to this project will be documented in this file. [alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7 [#1414]: https://www.free-decompiler.com/flash/issues/1414 [#1755]: https://www.free-decompiler.com/flash/issues/1755 +[#1460]: https://www.free-decompiler.com/flash/issues/1460 [#1459]: https://www.free-decompiler.com/flash/issues/1459 [#1832]: https://www.free-decompiler.com/flash/issues/1832 [#1849]: https://www.free-decompiler.com/flash/issues/1849 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index 4bfbd8991..a62004fe0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -755,6 +755,10 @@ public final class Configuration { @ConfigurationDefaultBoolean(true) @ConfigurationCategory("ui") public static ConfigurationItem showImportXmlInfo = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("ui") + public static ConfigurationItem showImportImageInfo = null; private enum OSId { WINDOWS, OSX, UNIX diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ImageExportMode.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ImageExportMode.java index 9dcb9c9c5..f036fe627 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ImageExportMode.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ImageExportMode.java @@ -20,7 +20,7 @@ package com.jpexs.decompiler.flash.exporters.modes; * * @author JPEXS */ -public enum ImageExportMode { - +public enum ImageExportMode { + PNG_GIF_JPEG, PNG, JPEG, BMP } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java index f67639249..eaa18a7b9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java @@ -97,8 +97,9 @@ public class ImageImporter extends TagImporter { } imageTag.setModified(true); - swf.replaceTag(it, imageTag); + it.getTimelined().replaceTag(it, imageTag); swf.updateCharacters(); + swf.resetTimelines(swf); return imageTag; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java index 9c42a20b5..7ae843c11 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java @@ -441,6 +441,14 @@ public class DefineSpriteTag extends DrawableTag implements Timelined { removeTag(index); addTag(index, newTag); } + + @Override + public void replaceTag(Tag oldTag, Tag newTag) { + int index = indexOfTag(oldTag); + if (index != -1) { + replaceTag(index, newTag); + } + } @Override public RECT getRectWithStrokes() { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java index 210c2d757..e85c3240b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java @@ -183,4 +183,13 @@ public abstract class ButtonTag extends DrawableTag implements Timelined { removeTag(index); addTag(index, newTag); } + + @Override + public void replaceTag(Tag oldTag, Tag newTag) { + setModified(true); + int index = indexOfTag(oldTag); + if (index != -1) { + replaceTag(index, newTag); + } + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timelined.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timelined.java index be2526118..162e58b1e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timelined.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timelined.java @@ -44,5 +44,7 @@ public interface Timelined extends BoundedTag { public void replaceTag(int index, Tag newTag); + public void replaceTag(Tag oldTag, Tag newTag); + public int indexOfTag(Tag tag); } diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java index 63a5ff809..a329ee7c3 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java @@ -266,6 +266,13 @@ public abstract class MainFrameMenu implements MenuBuilder { mainFrame.getPanel().importScript(swf); } + + protected void importImagesActionPerformed(ActionEvent evt) { + if (Main.isWorking()) { + return; + } + mainFrame.getPanel().importImage(swf); + } protected void importSymbolClassActionPerformed(ActionEvent evt) { if (Main.isWorking()) { @@ -758,7 +765,7 @@ public abstract class MainFrameMenu implements MenuBuilder { setMenuEnabled("/file/import", swfSelected); setMenuEnabled("/file/import/importText", swfSelected && !isWorking); setMenuEnabled("/file/import/importScript", swfSelected && !isWorking); - setMenuEnabled("/file/import/importSymbolClass", swfSelected && !isWorking); + setMenuEnabled("/file/import/importOther", swfSelected && !isWorking); setMenuEnabled("/file/import/importXml", swfSelected && !isWorking); setMenuEnabled("/tools/deobfuscation", swfSelected); @@ -885,7 +892,10 @@ public abstract class MainFrameMenu implements MenuBuilder { addMenuItem("/file/import/importXml", translate("menu.file.import.xml"), "importxml32", this::importXmlActionPerformed, PRIORITY_TOP, null, true, null, false); addMenuItem("/file/import/importText", translate("menu.file.import.text"), "importtext32", this::importTextActionPerformed, PRIORITY_MEDIUM, null, true, null, false); addMenuItem("/file/import/importScript", translate("menu.file.import.script"), "importscript32", this::importScriptActionPerformed, PRIORITY_MEDIUM, null, true, null, false); - addMenuItem("/file/import/importSymbolClass", translate("menu.file.import.symbolClass"), "importsymbolclass32", this::importSymbolClassActionPerformed, PRIORITY_MEDIUM, null, true, null, false); + addMenuItem("/file/import/importOther", translate("menu.file.import.other"), "importother32", null, PRIORITY_MEDIUM, null, false, null, false); + addMenuItem("/file/import/importOther/importImages", translate("menu.file.import.images"), "importimage32", this::importImagesActionPerformed, PRIORITY_MEDIUM, null, true, null, false); + addMenuItem("/file/import/importOther/importSymbolClass", translate("menu.file.import.symbolClass"), "importsymbolclass32", this::importSymbolClassActionPerformed, PRIORITY_MEDIUM, null, true, null, false); + finishMenu("/file/import/importOther"); finishMenu("/file/import"); addMenuItem("/file/start", translate("menu.file.start"), null, null, 0, null, false, null, false); diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java index ec150c902..70bfacf86 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java @@ -22,27 +22,36 @@ import com.jpexs.decompiler.flash.search.ScriptSearchResult; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ItemListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.swing.ButtonGroup; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; +import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JToggleButton; import javax.swing.SwingUtilities; import javax.swing.UIManager; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.basic.BasicPopupMenuUI; import org.pushingpixels.flamingo.api.common.AbstractCommandButton; import org.pushingpixels.flamingo.api.common.CommandButtonDisplayState; import org.pushingpixels.flamingo.api.common.CommandToggleButtonGroup; import org.pushingpixels.flamingo.api.common.JCommandButton; import org.pushingpixels.flamingo.api.common.JCommandButtonPanel; import org.pushingpixels.flamingo.api.common.JCommandToggleButton; +import org.pushingpixels.flamingo.api.common.PopupActionListener; +import org.pushingpixels.flamingo.api.common.model.PopupButtonModel; import org.pushingpixels.flamingo.api.common.popup.JPopupPanel; import org.pushingpixels.flamingo.api.common.popup.PopupPanelCallback; import org.pushingpixels.flamingo.api.ribbon.AbstractRibbonBand; @@ -373,30 +382,41 @@ public class MainFrameRibbonMenu extends MainFrameMenu { final ActionListener subLoader = menuLoaders.get(sub); AbstractCommandButton but = null; if (subType == TYPE_MENUITEM || (subType == TYPE_MENU && subAction != null)) { - JCommandButton cbut; - if (subIcon != null) { - cbut = new JCommandButton(fixCommandTitle(subTitle), View.getResizableIcon(subIcon, subPriority == PRIORITY_TOP ? 32 : 16)); + if (parts.length == 4) { + JMenuItem menuItem = new JMenuItem(subTitle); + if (subIcon != null) { + menuItem.setIcon(View.getIcon(subIcon, 16)); + } + if (subAction != null) { + menuItem.addActionListener(subAction); + } + menuItems.put(sub, menuItem); } else { - cbut = new JCommandButton(fixCommandTitle(subTitle)); - } - if (subKey != null) { - //cbut.setActionRichTooltip(new RichTooltip(subTitle, subKey.toString())); - } - if (subLoader != null) { - cbut.setCommandButtonKind(JCommandButton.CommandButtonKind.ACTION_AND_POPUP_MAIN_ACTION); - cbut.setPopupCallback(new PopupPanelCallback() { + JCommandButton cbut; + if (subIcon != null) { + cbut = new JCommandButton(fixCommandTitle(subTitle), View.getResizableIcon(subIcon, subPriority == PRIORITY_TOP ? 32 : 16)); + } else { + cbut = new JCommandButton(fixCommandTitle(subTitle)); + } + if (subKey != null) { + //cbut.setActionRichTooltip(new RichTooltip(subTitle, subKey.toString())); + } + if (subLoader != null) { + cbut.setCommandButtonKind(JCommandButton.CommandButtonKind.ACTION_AND_POPUP_MAIN_ACTION); + cbut.setPopupCallback(new PopupPanelCallback() { - @Override - public JPopupPanel getPopupPanel(JCommandButton jcb) { - JPopupPanel jp = new JPopupPanel() { - }; + @Override + public JPopupPanel getPopupPanel(JCommandButton jcb) { + JPopupPanel jp = new JPopupPanel() { + }; - subLoader.actionPerformed(new ActionEvent(jp, 0, "load:" + sub)); - return jp; - } - }); + subLoader.actionPerformed(new ActionEvent(jp, 0, "load:" + sub)); + return jp; + } + }); + } + but = cbut; } - but = cbut; } else if (subType == TYPE_TOGGLEMENUITEM) { if (onlyCheckboxes) { JCheckBox cb = new JCheckBox(subTitle); @@ -422,6 +442,44 @@ public class MainFrameRibbonMenu extends MainFrameMenu { } //if (parts.length == 3) + if (parts.length == 4) + { + JCommandButton popupButton; + if (icon != null) { + popupButton = new JCommandButton(fixCommandTitle(title), View.getResizableIcon(icon, priority == PRIORITY_TOP ? 32 : 16)); + } else { + popupButton = new JCommandButton(fixCommandTitle(title)); + } + JPopupMenu popupMenu = new JPopupMenu(); + popupButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + popupMenu.show(popupButton, 0, popupButton.getHeight()); + } + }); + int cnt = 0; + for (String sub : subs) { + if (sub.equals("-")) { + continue; + } + + Object o = menuItems.get(sub); + int subPriority = menuPriorities.get(sub); + int subType = menuType.get(sub); + ActionListener subAction = menuActions.get(sub); + if (subType != TYPE_MENU || (subAction != null)) { + if (o instanceof JMenuItem) { + JMenuItem mi = (JMenuItem)o; + popupMenu.add((JMenuItem) o); + cnt++; + } + } + } + if (cnt > 0) { + menuItems.put(path, popupButton); + } + } + else { //3rd level - it's a Band! JRibbonBand band = new JRibbonBand(title, icon != null ? View.getResizableIcon(icon, 16) : null, null); band.setResizePolicies(getResizePolicies(band)); @@ -435,7 +493,8 @@ public class MainFrameRibbonMenu extends MainFrameMenu { int subPriority = menuPriorities.get(sub); int subType = menuType.get(sub); ActionListener subAction = menuActions.get(sub); - if (subType != TYPE_MENU || (subAction != null)) { + //if (subType != TYPE_MENU || (subAction != null)) + { if (o instanceof AbstractCommandButton) { RibbonElementPriority ribbonPriority = RibbonElementPriority.MEDIUM; switch (subPriority) { @@ -452,6 +511,8 @@ public class MainFrameRibbonMenu extends MainFrameMenu { band.addCommandButton((AbstractCommandButton) o, ribbonPriority); cnt++; + } else if (o instanceof JRibbonBand) { + //ignore } else if (o instanceof JComponent) { band.addRibbonComponent(new JRibbonComponent((JComponent) o)); cnt++; diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 52f46e531..e9d035e5a 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -377,16 +377,16 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se private TagTreeContextMenu contextPopupMenu; private static final Logger logger = Logger.getLogger(MainPanel.class.getName()); - + private Map> missingNeededCharacters = new WeakHashMap<>(); - + private Thread calculateMissingNeededThread; private List> orderedClipboard = new ArrayList<>(); private Map clipboard = new WeakHashMap<>(); - + private boolean clipboardCut = false; - + public void gcClipboard() { for (int i = orderedClipboard.size() - 1; i >= 0; i--) { WeakReference ref = orderedClipboard.get(i); @@ -399,11 +399,11 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } } } - + public void emptyClipboard() { copyToClipboard(new ArrayList<>()); } - + public void copyToClipboard(Collection items) { orderedClipboard.clear(); clipboard.clear(); @@ -413,20 +413,20 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } clipboardCut = false; } - + public void cutToClipboard(Collection items) { copyToClipboard(items); - clipboardCut = true; + clipboardCut = true; } - + public boolean clipboardContains(TreeItem item) { return clipboard.containsKey(item); } - + public boolean clipboardEmpty() { return clipboard.isEmpty(); } - + public Set getClipboardContents() { Set ret = new LinkedHashSet<>(); for (WeakReference ref : orderedClipboard) { @@ -440,9 +440,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se public boolean isClipboardCut() { return clipboardCut; - } - - + } + private class MyTreeSelectionModel extends DefaultTreeSelectionModel { private boolean isModified() { @@ -593,7 +592,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se statusPanel.setWorkStatus(s, worker); mainMenu.updateComponents(); } - + public CancellableWorker getCurrentWorker() { return statusPanel.getCurrentWorker(); } @@ -778,9 +777,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se dumpTree = new DumpTree(null, this); dumpTree.addTreeSelectionListener(this); dumpTree.createContextMenu(); - + currentView = Configuration.lastView.get(); - + statusPanel = new MainFrameStatusPanel(this); add(statusPanel, BorderLayout.SOUTH); @@ -958,7 +957,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se calculateMissingNeededThread = new Thread("calculateMissingNeededThread") { @Override public void run() { - while(true) { + while (true) { calculateMissingNeededCharacters(); try { Thread.sleep(1000); @@ -966,7 +965,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se return; } } - } + } }; calculateMissingNeededThread.start(); } @@ -1020,7 +1019,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se if (swf != null) { updateUi(swf); } - + gcClipboard(); doFilter(); @@ -1221,7 +1220,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se refreshTree(); gcClipboard(); - + mainMenu.updateComponents(null); previewPanel.clear(); dumpPreviewPanel.clear(); @@ -2510,7 +2509,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se fc.setCurrentDirectory(new File(selDir)); if (!selDir.endsWith(File.separator)) { selDir += File.separator; - } + } String swfShortName = swf.getShortFileName(); if ("".equals(swfShortName)) { swfShortName = "untitled.swf"; @@ -2522,7 +2521,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se fileName = swfShortName + ".fla"; } final String fSwfShortName = swfShortName; - + fc.setSelectedFile(new File(selDir + fileName)); List flaFilters = new ArrayList<>(); List xflFilters = new ArrayList<>(); @@ -2621,6 +2620,96 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } } + public void importImage(final SWF swf) { + ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importImages"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportImageInfo); + JFileChooser chooser = new JFileChooser(); + chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get())); + chooser.setDialogTitle(translate("import.select.directory")); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setAcceptAllFileFilterUsed(false); + if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath(); + File imagesDir = new File(Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME)); + ImageImporter imageImporter = new ImageImporter(); + + final long timeBefore = System.currentTimeMillis(); + new CancellableWorker() { + + private int count = 0; + + @Override + public Void doInBackground() throws Exception { + try { + Map characters = swf.getCharacters(); + List extensions = Arrays.asList("png", "jpg", "jpeg", "gif", "bmp"); + for (int characterId : characters.keySet()) { + CharacterTag tag = characters.get(characterId); + if (tag instanceof ImageTag) { + ImageTag imageTag = (ImageTag) tag; + if (!imageTag.importSupported()) { + continue; + } + List existingFilesForImageTag = new ArrayList<>(); + for (String ext : extensions) { + File sourceFile = new File(Path.combine(imagesDir.getPath(), "" + characterId + "." + ext)); + if (sourceFile.exists()) { + existingFilesForImageTag.add(sourceFile); + } + } + + if (existingFilesForImageTag.isEmpty()) { + continue; + } + + if (existingFilesForImageTag.size() > 1) { + Logger.getLogger(MainPanel.class.getName()).log(Level.WARNING, "Multiple matching files for image tag {0} exists, {1} selected", new Object[]{characterId, existingFilesForImageTag.get(0).getName()}); + } + File sourceFile = existingFilesForImageTag.get(0); + try { + imageImporter.importImage(imageTag, Helper.readFile(sourceFile.getPath())); + count++; + } catch (IOException ex) { + Logger.getLogger(MainPanel.class.getName()).log(Level.WARNING, "Cannot import image " + characterId + " from file " + sourceFile.getName(), ex); + } + if (Thread.currentThread().isInterrupted()) { + break; + } + } + } + swf.clearImageCache(); + } catch (Exception ex) { + logger.log(Level.SEVERE, "Error during import", ex); + ViewMessages.showMessageDialog(null, translate("error.import") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage()); + } + return null; + } + + @Override + protected void onStart() { + Main.startWork(translate("work.importing") + "...", this); + } + + @Override + protected void done() { + Main.stopWork(); + long timeAfter = System.currentTimeMillis(); + final long timeMs = timeAfter - timeBefore; + + + View.execInEventDispatch(() -> { + refreshTree(swf); + setStatus(translate("import.finishedin").replace("%time%", Helper.formatTimeSec(timeMs))); + + ViewMessages.showMessageDialog(MainPanel.this, translate("import.image.result").replace("%count%", Integer.toString(count))); + if (count != 0) { + reload(true); + } + }); + } + }.execute(); + } + } + public void importText(final SWF swf) { ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importTexts"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportTextInfo); JFileChooser chooser = new JFileChooser(); @@ -2868,8 +2957,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se swfs.add(item.getSwf()); } } - - + for (SWF item : swfs) { SWF swf = (SWF) item; final String selFile = selectExportDir(); @@ -2883,7 +2971,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se logger.log(Level.SEVERE, null, ex); } } - } + } } public void exportSwfXml() { @@ -3257,7 +3345,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se public boolean nextTag() { JTree tree = getCurrentTree(); - + if (tree != null) { if (tree.getSelectionRows().length > 0) { int row = tree.getSelectionRows()[0]; @@ -3636,24 +3724,24 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se if (treeItem == null) { return -1; } - if (currentView == VIEW_DUMP){ + if (currentView == VIEW_DUMP) { if (treeItem instanceof Tag) { Tag t = (Tag) treeItem; ReadOnlyTagList tags = t.getTimelined().getTags(); - int frame = 0; + int frame = 0; for (int i = 0; i < tags.size(); i++) { if (tags.get(i) == t) { return frame; } if (tags.get(i) instanceof ShowFrameTag) { frame++; - } - } + } + } } return -1; } - - if(currentView == VIEW_TIMELINE) { + + if (currentView == VIEW_TIMELINE) { return -1; } TreePath path = getCurrentTree().getModel().getTreePath(treeItem); @@ -3673,17 +3761,17 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se if (treeItem == null) { return null; } - + if (currentView == VIEW_DUMP) { if (treeItem instanceof Tag) { Tag t = (Tag) treeItem; return t.getTimelined(); } - return null; + return null; } if (currentView == VIEW_TIMELINE) { return null; - } + } TreePath path = getCurrentTree().getModel().getTreePath(treeItem); if (path == null) { @@ -3763,14 +3851,14 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se dumpTree.expandFirstLevelNodes(); } break; - case VIEW_RESOURCES: + case VIEW_RESOURCES: case VIEW_TAGLIST: if (tagTree.getModel() == null) { TagTreeModel ttm = new TagTreeModel(swfs, Configuration.tagTreeShowEmptyFolders.get()); tagTree.setModel(ttm); tagTree.expandFirstLevelNodes(); - } - + } + if (tagListTree.getModel() == null) { TagListTreeModel ttm = new TagListTreeModel(swfs); tagListTree.setModel(ttm); @@ -3844,7 +3932,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se reload(true); return true; - case VIEW_TIMELINE: + case VIEW_TIMELINE: currentView = view; Configuration.lastView.set(currentView); final SWF swf = getCurrentSwf(); @@ -3920,7 +4008,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } catch (IOException ex) { //ignore } - } + } } catch (InterruptedException ex) { //ignore } @@ -4078,8 +4166,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se SwfSpecificCustomConfiguration swfCustomConf = Configuration.getOrCreateSwfSpecificCustomConfiguration(swf.getShortFileName()); //swfConf.lastSelectedPath = tagTree.getSelectionPathString(); swfCustomConf.setCustomData(SwfSpecificCustomConfiguration.KEY_LAST_SELECTED_PATH_RESOURCES, tagTree.getSelectionPathString()); - swfCustomConf.setCustomData(SwfSpecificCustomConfiguration.KEY_LAST_SELECTED_PATH_TAGLIST, tagListTree.getSelectionPathString()); - + swfCustomConf.setCustomData(SwfSpecificCustomConfiguration.KEY_LAST_SELECTED_PATH_TAGLIST, tagListTree.getSelectionPathString()); + } } @@ -4106,7 +4194,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se stopFlashPlayer(); previewPanel.setImageReplaceButtonVisible(false, false, false, false); - + boolean internalViewer = !isAdobeFlashPlayerEnabled(); if (treeItem instanceof ScriptPack) { @@ -4253,7 +4341,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se for (Tag tag : timelined.getTags()) { if (tag instanceof DefineSpriteTag) { folderPreviewItems.add(tag); - addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag); + addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag); } } break; @@ -4304,7 +4392,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se break; } } - + private void showFolderPreview(FolderItem item) { List folderPreviewItems = new ArrayList<>(); String folderName = item.getName(); @@ -4560,6 +4648,10 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se public void replaceTag(int index, Tag newTag) { } + @Override + public void replaceTag(Tag oldTag, Tag newTag) { + } + @Override public int indexOfTag(Tag tag) { return -1; @@ -4593,18 +4685,18 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } setDropTarget(null); disposeInner(this); - Helper.emptyObject(this); + Helper.emptyObject(this); } - + private static void calculateMissingNeededCharacters(Map> missingNeededCharacters, Timelined tim) { - for (Tag t: tim.getTags()) { + for (Tag t : tim.getTags()) { missingNeededCharacters.put(t, t.getMissingNeededCharacters()); if (t instanceof DefineSpriteTag) { calculateMissingNeededCharacters(missingNeededCharacters, (DefineSpriteTag) t); } - } + } } - + public void calculateMissingNeededCharacters() { Map> missingNeededCharacters = new WeakHashMap<>(); List swfsLists = new ArrayList<>(swfs); @@ -4617,5 +4709,5 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se tagTree.setMissingNeededCharacters(missingNeededCharacters); tagListTree.setMissingNeededCharacters(missingNeededCharacters); } - + } diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/importimage16.png b/src/com/jpexs/decompiler/flash/gui/graphics/importimage16.png new file mode 100644 index 000000000..73aa03365 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/importimage16.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/importimage32.png b/src/com/jpexs/decompiler/flash/gui/graphics/importimage32.png new file mode 100644 index 000000000..63048ab02 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/importimage32.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/importother16.png b/src/com/jpexs/decompiler/flash/gui/graphics/importother16.png new file mode 100644 index 000000000..4e90b4d70 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/importother16.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/importother32.png b/src/com/jpexs/decompiler/flash/gui/graphics/importother32.png new file mode 100644 index 000000000..2dc0e38cf Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/importother32.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties index 39504a19a..562f9a99b 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties @@ -573,3 +573,8 @@ config.description.swfSpecificCustomConfigs = Contains the SWF specific configur config.name.warningOpeningReadOnly = Warn on opening readonly SWF config.description.warningOpeningReadOnly = Show warning when opening SWF from readonly source + +# after 16.1.0 +config.name.showImportImageInfo = Show information before importing images +config.description.showImportImageInfo = Displays some info about how importing images works after clicking Import images in the menu. + diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties index 2e56690cc..7034d1dee 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties @@ -547,3 +547,20 @@ config.description.showImportSymbolClassInfo = Zobraz\u00ed n\u011bjak\u00e9 inf config.name.showImportXmlInfo = Zobrazit informaci p\u0159ed importem XML config.description.showImportXmlInfo = Zobraz\u00ed n\u011bjak\u00e9 informace o tom jak import XML funguje po kliku na import XML v menu. + +#after 15.1.1 +config.name.lastSessionTagListSelection = V\u00fdb\u011br ze seznamu tag z posledn\u00ed session +config.description.lastSessionTagListSelection = Obsahuje v\u00fdb\u011br z posledn\u00ed sessiony v zobrazen\u00ed seznamu tag\u016f + +config.name.lastView = Posledn\u00ed m\u00f3d zobrazen\u00ed +config.description.lastView = Naposledy zvolen\u00fd m\u00f3d zobrazen\u00ed + +config.name.swfSpecificCustomConfigs = Vlastn\u00ed konfigurace specifick\u00e1 pro jednotliv\u00e9 SWF +config.description.swfSpecificCustomConfigs = Obsahuje konfiguraci specifickou pro jednotliv\u00e1 SWF ve vlastn\u00edm form\u00e1tu + +config.name.warningOpeningReadOnly = Varovat p\u0159i otev\u00edr\u00e1n\u00ed SWF co jsou jen ke \u010dten\u00ed +config.description.warningOpeningReadOnly = Zobrazovat varov\u00e1n\u00ed p\u0159i otev\u00edr\u00e1n\u00ed SWF ze zdroj\u016f co jsou jen ke \u010dten\u00ed + +# after 16.1.0 +config.name.showImportImageInfo = Zobrazit informaci p\u0159ed importem obr\u00e1zk\u016f +config.description.showImportImageInfo = Zobraz\u00ed n\u011bjak\u00e9 informace o tom jak import obr\u00e1zk\u016f funguje po kliku na import obr\u00e1zk\u016f v menu. diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index 5bcd2efe4..561481439 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -924,4 +924,17 @@ contextmenu.cutTagWithDependencies = Cut to tag clipboard with dependencies contextmenu.paste = Paste contextmenu.pasteBefore = Paste before contextmenu.pasteAfter = Paste after -contextmenu.pasteInside = Paste inside \ No newline at end of file +contextmenu.pasteInside = Paste inside + +menu.file.import.other = Import other... +menu.file.import.images = Import images + +message.info.importImages = During importing images, you need to select a FOLDER.\r\n \ + The folder must contain "images" subfolder and filenames inside must match existing images in current selected SWF.\r\n \ + The best way to get the structure right is to export images in current SWF file first. + +work.importing = Importing +import.finishedin = Imported in %time% +error.import = Error during import + +import.image.result = %count% images imported. \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties index 2507673a9..3bcf6c97f 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -894,4 +894,19 @@ contextmenu.cutTagWithDependencies = Vyjmout do tagov\u00e9 schr\u00e1nky se z\u contextmenu.paste = Vlo\u017eit contextmenu.pasteBefore = Vlo\u017eit p\u0159ed contextmenu.pasteAfter = Vlo\u017eit za -contextmenu.pasteInside = Vlo\u017eit dovnit\u0159 \ No newline at end of file +contextmenu.pasteInside = Vlo\u017eit dovnit\u0159 + + +menu.file.import.other = Importovat jin\u00e9... +menu.file.import.images = Importovat obr\u00e1zky + +message.info.importImages = B\u011bhem importu text\u016f mus\u00edte vybrat SLO\u017dKU.\r\n \ + Slo\u017eka mus\u00ed obsahovat podslo\u017eku "images" a n\u00e1zvy soubor\u016f v n\u00ed mus\u00ed souhlasit s existuj\u00edc\u00edmi obr\u00e1zky v pr\u00e1v\u011b vybran\u00e9m SWF.\r\n \ + Nejlep\u0161\u00ed zp\u016fsob jak m\u00edt tuto strukturu spr\u00e1vn\u011b je nejprve exportovat obr\u00e1zky v aktu\u00e1ln\u00edm SWF souboru. + + +work.importing = Importov\u00e1n\u00ed +import.finishedin = Importov\u00e1no za %time% +error.import = Chyba b\u011bhem importu + +import.image.result = %count% obr\u00e1zk\u016f importov\u00e1no. \ No newline at end of file