From dd95e20d047d9e8fdf4fca0b02089111b2917290 Mon Sep 17 00:00:00 2001 From: honfika Date: Thu, 29 May 2014 21:25:53 +0200 Subject: [PATCH] remove character without the dependencies (remove only the place/remove object tags) --- src/com/jpexs/decompiler/flash/SWF.java | 133 +++-- .../jpexs/decompiler/flash/gui/MainPanel.java | 19 +- .../decompiler/flash/gui/PreviewImage.java | 524 +++++++++--------- .../flash/gui/locales/MainFrame.properties | 4 +- .../flash/tags/DefineSpriteTag.java | 10 +- .../decompiler/flash/timeline/Timeline.java | 43 ++ .../decompiler/flash/types/LINESTYLE2.java | 5 +- .../types/shaperecords/StyleChangeRecord.java | 5 +- 8 files changed, 415 insertions(+), 328 deletions(-) diff --git a/src/com/jpexs/decompiler/flash/SWF.java b/src/com/jpexs/decompiler/flash/SWF.java index b667adf3d..8180bade2 100644 --- a/src/com/jpexs/decompiler/flash/SWF.java +++ b/src/com/jpexs/decompiler/flash/SWF.java @@ -272,9 +272,21 @@ public final class SWF implements TreeItem, Timelined { private Timeline timeline; public void updateCharacters() { + characters.clear(); parseCharacters(new ArrayList(tags)); } + public void resetTimelines(Timelined timelined) { + timelined.resetTimeline(); + List tags = timelined.getTimeline().tags; + for (int i = 0; i < tags.size(); i++) { + Tag t = tags.get(i); + if (t instanceof Timelined) { + resetTimelines((Timelined) t); + } + } + } + private void parseCharacters(List list) { for (ContainerItem t : list) { if (t instanceof CharacterTag) { @@ -1477,7 +1489,7 @@ public final class SWF implements TreeItem, Timelined { try (FileOutputStream fos = new FileOutputStream(f)) { fos.write(Utf8Helper.getBytes("\r\n")); Set library = new HashSet<>(); - getNeededCharacters(ftim, fframes, library); + ftim.getNeededCharacters(fframes, library); writeLibrary(fswf, library, fos); @@ -2213,29 +2225,6 @@ public final class SWF implements TreeItem, Timelined { return ret; } - private static void getNeededCharacters(Timeline timeline, List frames, Set usedCharacters) { - if (frames == null) { - frames = new ArrayList<>(); - for (int i = 0; i < timeline.getFrameCount(); i++) { - frames.add(i); - } - } - for (int frame = 0; frame < frames.size(); frame++) { - Frame frameObj = timeline.frames.get(frame); - for (int depth : frameObj.layers.keySet()) { - DepthState layer = frameObj.layers.get(depth); - if (layer.characterId != -1) { - if (!timeline.swf.characters.containsKey(layer.characterId)) { - continue; - } - usedCharacters.add(layer.characterId); - timeline.swf.characters.get(layer.characterId).getNeededCharactersDeep(usedCharacters); - } - } - } - - } - private static String jsArrColor(RGB rgb) { return "[" + rgb.red + "," + rgb.green + "," + rgb.blue + "," + ((rgb instanceof RGBA) ? ((RGBA) rgb).getAlphaFloat() : 1) + "]"; } @@ -2831,7 +2820,7 @@ public final class SWF implements TreeItem, Timelined { g.setTransform(AffineTransform.getScaleInstance(1, 1)); } - public void removeTagFromTimeline(Tag toRemove, List timeline) { + private void removeTagWithDependenciesFromTimeline(Tag toRemove, Timeline timeline) { int characterId = 0; if (toRemove instanceof CharacterTag) { characterId = ((CharacterTag) toRemove).getCharacterId(); @@ -2841,8 +2830,8 @@ public final class SWF implements TreeItem, Timelined { Set dependingChars = new HashSet<>(); if (characterId != 0) { dependingChars.add(characterId); - for (int i = 0; i < timeline.size(); i++) { - Tag t = timeline.get(i); + for (int i = 0; i < timeline.tags.size(); i++) { + Tag t = timeline.tags.get(i); if (t instanceof CharacterIdTag) { CharacterIdTag c = (CharacterIdTag) t; Set needed = new HashSet<>(); @@ -2851,18 +2840,18 @@ public final class SWF implements TreeItem, Timelined { dependingChars.add(c.getCharacterId()); } } - } } - for (int i = 0; i < timeline.size(); i++) { - Tag t = timeline.get(i); + for (int i = 0; i < timeline.tags.size(); i++) { + Tag t = timeline.tags.get(i); if (t instanceof RemoveTag) { RemoveTag rt = (RemoveTag) t; - int currentCharId = stage.get(rt.getDepth()); - stage.remove(rt.getDepth()); + int depth = rt.getDepth(); + int currentCharId = stage.get(depth); + stage.remove(depth); if (dependingChars.contains(currentCharId)) { - timeline.remove(i); + timeline.tags.remove(i); i--; continue; } @@ -2870,13 +2859,13 @@ public final class SWF implements TreeItem, Timelined { if (t instanceof PlaceObjectTypeTag) { PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; int placeCharId = po.getCharacterId(); - int placeDepth = po.getDepth(); + int depth = po.getDepth(); if (placeCharId != 0) { - stage.put(placeDepth, placeCharId); + stage.put(depth, placeCharId); } - int currentCharId = stage.get(placeDepth); + int currentCharId = stage.get(depth); if (dependingChars.contains(currentCharId)) { - timeline.remove(i); + timeline.tags.remove(i); i--; continue; } @@ -2884,7 +2873,7 @@ public final class SWF implements TreeItem, Timelined { if (t instanceof CharacterIdTag) { CharacterIdTag c = (CharacterIdTag) t; if (dependingChars.contains(c.getCharacterId())) { - timeline.remove(i); + timeline.tags.remove(i); i--; continue; } @@ -2893,38 +2882,78 @@ public final class SWF implements TreeItem, Timelined { t.getNeededCharacters(needed); for (int dep : dependingChars) { if (needed.contains(dep)) { - timeline.remove(i); + timeline.tags.remove(i); i--; continue; } } if (t == toRemove) { - timeline.remove(i); + timeline.tags.remove(i); i--; continue; } - if (t instanceof DefineSpriteTag) { - DefineSpriteTag spr = (DefineSpriteTag) t; - removeTagFromTimeline(toRemove, spr.subTags); + if (t instanceof Timelined) { + removeTagWithDependenciesFromTimeline(toRemove, ((Timelined) t).getTimeline()); } - } } - public void removeTag(Tag t) { - List tags; - Timelined timelined = t.getTimelined(); - if (timelined instanceof DefineSpriteTag) { - tags = ((DefineSpriteTag) timelined).getSubTags(); - } else { - tags = this.tags; + private boolean removeTagFromTimeline(Tag toRemove, Timeline timeline) { + boolean modified = false; + int characterId = -1; + if (toRemove instanceof CharacterTag) { + characterId = ((CharacterTag) toRemove).getCharacterId(); + modified = timeline.removeCharacter(characterId); } + for (int i = 0; i < timeline.tags.size(); i++) { + Tag t = timeline.tags.get(i); + if (t == toRemove) { + timeline.tags.remove(t); + i--; + continue; + } + + if (toRemove instanceof CharacterTag){ + if (t.removeCharacter(characterId)) { + modified = true; + i = -1; + continue; + } + } + + if (t instanceof DefineSpriteTag) { + DefineSpriteTag spr = (DefineSpriteTag) t; + boolean sprModified = removeTagFromTimeline(toRemove, spr.getTimeline()); + if (sprModified) { + spr.setModified(true); + } + modified |= sprModified; + } + } + return modified; + } + + public void removeTag(Tag t, boolean removeDependencies) { + Timelined timelined = t.getTimelined(); if (t instanceof ShowFrameTag || ShowFrameTag.isNestedTagType(t.getId())) { + List tags; + if (timelined instanceof DefineSpriteTag) { + tags = ((DefineSpriteTag) timelined).getSubTags(); + } else { + tags = this.tags; + } tags.remove(t); timelined.resetTimeline(); } else { - removeTagFromTimeline(t, tags); + // timeline shuold be always the swf here + if (removeDependencies) { + removeTagWithDependenciesFromTimeline(t, timelined.getTimeline()); + } else { + removeTagFromTimeline(t, timeline); + } } + resetTimelines(timelined); + updateCharacters(); clearImageCache(); } } diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 149ba6063..f9bc09117 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -250,6 +250,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec public static final String ACTION_SELECT_BKCOLOR = "SELECTCOLOR"; public static final String ACTION_REPLACE = "REPLACE"; private static final String ACTION_REMOVE_ITEM = "REMOVEITEM"; + private static final String ACTION_REMOVE_ITEM_WITH_DEPENDENCIES = "REMOVEITEMWITHDEPENDENCIES"; private static final String ACTION_CLOSE_SWF = "CLOSESWF"; private static final String ACTION_EXPAND_RECURSIVE = "EXPANDRECURSIVE"; @@ -311,6 +312,11 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec removeMenuItem.setActionCommand(ACTION_REMOVE_ITEM); contextPopupMenu.add(removeMenuItem); + final JMenuItem removeWithDependenciesMenuItem = new JMenuItem(translate("contextmenu.removeWithDependencies")); + removeWithDependenciesMenuItem.addActionListener(this); + removeWithDependenciesMenuItem.setActionCommand(ACTION_REMOVE_ITEM_WITH_DEPENDENCIES); + contextPopupMenu.add(removeWithDependenciesMenuItem); + final JMenuItem exportSelectionMenuItem = new JMenuItem(translate("menu.file.export.selection")); exportSelectionMenuItem.setActionCommand(MainFrameRibbonMenu.ACTION_EXPORT_SEL); exportSelectionMenuItem.addActionListener(this); @@ -2028,7 +2034,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec for (Tag tag : tags) { System.out.println(tag.getClass()); if (!(tag instanceof ABCContainerTag || tag instanceof ASMSource)) { - swf.removeTag(tag); + swf.removeTag(tag, true); } } refreshTree(); @@ -2082,11 +2088,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec return false; } - public void removeTag(Tag tag) { - tag.getSwf().removeTag(tag); - refreshTree(); - } - @Override public void actionPerformed(ActionEvent e) { switch (e.getActionCommand()) { @@ -2242,6 +2243,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } break; case ACTION_REMOVE_ITEM: + case ACTION_REMOVE_ITEM_WITH_DEPENDENCIES: List sel = getSelected(tagTree); List tagsToRemove = new ArrayList<>(); @@ -2256,16 +2258,17 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } } + boolean removeDependencies = e.getActionCommand().equals(ACTION_REMOVE_ITEM_WITH_DEPENDENCIES); if (tagsToRemove.size() == 1) { Tag tag = tagsToRemove.get(0); if (View.showConfirmDialog(this, translate("message.confirm.remove").replace("%item%", tag.toString()), translate("message.confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { - tag.getSwf().removeTag(tag); + tag.getSwf().removeTag(tag, removeDependencies); refreshTree(); } } else if (tagsToRemove.size() > 1) { if (View.showConfirmDialog(this, translate("message.confirm.removemultiple").replace("%count%", Integer.toString(tagsToRemove.size())), translate("message.confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { for (Tag tag : tagsToRemove) { - tag.getSwf().removeTag(tag); + tag.getSwf().removeTag(tag, removeDependencies); } refreshTree(); } diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewImage.java b/src/com/jpexs/decompiler/flash/gui/PreviewImage.java index 86fbf2ec5..da26f5898 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewImage.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewImage.java @@ -1,256 +1,268 @@ -/* - * 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 . - */ -package com.jpexs.decompiler.flash.gui; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.tags.base.DrawableTag; -import com.jpexs.decompiler.flash.tags.base.ImageTag; -import com.jpexs.decompiler.flash.treeitems.FrameNodeItem; -import com.jpexs.decompiler.flash.treeitems.TreeItem; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.helpers.SerializableImage; -import java.awt.AlphaComposite; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.geom.AffineTransform; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import javax.swing.AbstractAction; -import javax.swing.BorderFactory; -import javax.swing.JLabel; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; - -/** - * - * @author JPEXS - */ -public class PreviewImage extends JPanel { - - private static final ExecutorService executor; - private static final int PREVIEW_SIZE = 150; - private static final int BORDER_SIZE = 5; - private Image image; - private boolean rendering; - private final MainPanel mainPanel; - private final TreeItem treeItem; - - static { - executor = Executors.newFixedThreadPool(Configuration.parallelSpeedUp.get() ? Configuration.parallelThreadCount.get() : 1); - } - - /** - * - * @param mainPanel - * @param treeItem - */ - public PreviewImage(final MainPanel mainPanel, final TreeItem treeItem) { - this.mainPanel = mainPanel; - this.treeItem = treeItem; - Dimension dim = new Dimension(PREVIEW_SIZE + 2 * BORDER_SIZE, PREVIEW_SIZE + 2 * BORDER_SIZE); - setMinimumSize(dim); - setMaximumSize(dim); - setPreferredSize(dim); - setSize(dim); - setLayout(null); - setBorder(BorderFactory.createLineBorder(Color.black)); - - if (treeItem instanceof Tag) { - JPopupMenu contextMenu = new JPopupMenu(); - final JMenuItem removeMenuItem = new JMenuItem(mainPanel.translate("contextmenu.remove")); - removeMenuItem.addActionListener(new AbstractAction() { - - @Override - public void actionPerformed(ActionEvent e) { - mainPanel.removeTag((Tag) treeItem); - mainPanel.refreshTree(); - } - }); - contextMenu.add(removeMenuItem); - this.setComponentPopupMenu(contextMenu); - } - - this.addMouseListener(new MouseListener() { - - @Override - public void mouseClicked(MouseEvent e) { - - if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() >= 2) { - mainPanel.setTreeItem(treeItem); - } - } - - @Override - public void mousePressed(MouseEvent e) { - } - - @Override - public void mouseReleased(MouseEvent e) { - } - - @Override - public void mouseEntered(MouseEvent e) { - } - - @Override - public void mouseExited(MouseEvent e) { - } - }); - } - - private synchronized void renderImageTask(final TreeItem treeItem) { - if (rendering) { - return; - } - rendering = true; - executor.submit(new Callable() { - - @Override - public Void call() throws Exception { - image = renderImage(treeItem.getSwf(), treeItem); - View.execInEventDispatch(new Runnable() { - - @Override - public void run() { - revalidate(); - repaint(); - } - }); - return null; - } - - }); - - } - - private Image renderImage(SWF swf, TreeItem treeItem) { - - double scale = 1; - int width = 0; - int height = 0; - SerializableImage imgSrc = null; - Matrix m = new Matrix(); - if (treeItem instanceof FrameNodeItem) { - FrameNodeItem fn = (FrameNodeItem) treeItem; - RECT rect = swf.displayRect; - imgSrc = SWF.frameToImageGet(swf.getTimeline(), fn.getFrame() - 1, 0, null, 0, rect, Matrix.getScaleInstance(1 / SWF.unitDivisor), new ColorTransform(), null); - width = (imgSrc.getWidth()); - height = (imgSrc.getHeight()); - } else if (treeItem instanceof ImageTag) { - imgSrc = ((ImageTag) treeItem).getImage(); - width = (imgSrc.getWidth()); - height = (imgSrc.getHeight()); - } else if (treeItem instanceof BoundedTag) { - BoundedTag boundedTag = (BoundedTag) treeItem; - RECT rect = boundedTag.getRect(); - width = (int) (rect.getWidth() / SWF.unitDivisor); - height = (int) (rect.getHeight() / SWF.unitDivisor); - m.translate(-rect.Xmin, -rect.Ymin); - } - - int w1 = width; - int h1 = height; - int w2 = PREVIEW_SIZE; - int h2 = PREVIEW_SIZE; - - int w; - int h = h1 * w2 / w1; - if (h > h2) { - w = w1 * h2 / h1; - h = h2; - } else { - w = w2; - } - - scale = (double) w / (double) w1; - if (w1 <= w2 && h1 <= h2) { - scale = 1; - } - - m = m.preConcatenate(Matrix.getScaleInstance(scale)); - width = (int) (scale * width); - height = (int) (scale * height); - if (width == 0 || height == 0) { - return null; - } - - SerializableImage image = new SerializableImage(width, height, SerializableImage.TYPE_INT_ARGB); - image.fillTransparent(); - if (imgSrc == null) { - DrawableTag drawable = (DrawableTag) treeItem; - drawable.toImage(0, 0, 0, null, 0, image, m, new ColorTransform()); - } else { - Graphics2D g = (Graphics2D) image.getGraphics(); - g.setTransform(m.toTransform()); - g.drawImage(imgSrc.getBufferedImage(), 0, 0, null); - } - return image.getBufferedImage(); - } - - public static Component createFolderPreviewImage(MainPanel mainPanel, TreeItem treeItem) { - JPanel pan = new JPanel(new BorderLayout()); - PreviewImage imagePanel = new PreviewImage(mainPanel, treeItem); - pan.add(imagePanel, BorderLayout.CENTER); - String s; - if (treeItem instanceof Tag) { - s = ((Tag) treeItem).getTagName(); - if (treeItem instanceof CharacterTag) { - s = s + " (" + ((CharacterTag) treeItem).getCharacterId() + ")"; - } - } else { - s = treeItem.toString(); - } - JLabel lab = new JLabel(s); - lab.setFont(lab.getFont().deriveFont(AffineTransform.getScaleInstance(0.8, 0.8))); - pan.add(lab, BorderLayout.SOUTH); - return pan; - } - - @Override - protected void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - g2d.setPaint(View.transparentPaint); - g2d.fill(new Rectangle(0, 0, getWidth(), getHeight())); - g2d.setComposite(AlphaComposite.SrcOver); - g2d.setPaint(View.swfBackgroundColor); - g2d.fill(new Rectangle(0, 0, getWidth(), getHeight())); - if (image != null) { - int x = (getWidth() / 2) - (image.getWidth(this) / 2); - int y = (getHeight() / 2) - (image.getHeight(this) / 2); - g.drawImage(image, x, y, null); - } else { - renderImageTask(treeItem); - } - } -} +/* + * 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 . + */ +package com.jpexs.decompiler.flash.gui; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.DrawableTag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.treeitems.FrameNodeItem; +import com.jpexs.decompiler.flash.treeitems.TreeItem; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.helpers.SerializableImage; +import java.awt.AlphaComposite; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.geom.AffineTransform; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; + +/** + * + * @author JPEXS + */ +public class PreviewImage extends JPanel { + + private static final ExecutorService executor; + private static final int PREVIEW_SIZE = 150; + private static final int BORDER_SIZE = 5; + private Image image; + private boolean rendering; + private final MainPanel mainPanel; + private final TreeItem treeItem; + + static { + executor = Executors.newFixedThreadPool(Configuration.parallelSpeedUp.get() ? Configuration.parallelThreadCount.get() : 1); + } + + /** + * + * @param mainPanel + * @param treeItem + */ + public PreviewImage(final MainPanel mainPanel, final TreeItem treeItem) { + this.mainPanel = mainPanel; + this.treeItem = treeItem; + Dimension dim = new Dimension(PREVIEW_SIZE + 2 * BORDER_SIZE, PREVIEW_SIZE + 2 * BORDER_SIZE); + setMinimumSize(dim); + setMaximumSize(dim); + setPreferredSize(dim); + setSize(dim); + setLayout(null); + setBorder(BorderFactory.createLineBorder(Color.black)); + + if (treeItem instanceof Tag) { + JPopupMenu contextMenu = new JPopupMenu(); + final JMenuItem removeMenuItem = new JMenuItem(mainPanel.translate("contextmenu.remove")); + removeMenuItem.addActionListener(new AbstractAction() { + + @Override + public void actionPerformed(ActionEvent e) { + Tag tag = (Tag) treeItem; + tag.getSwf().removeTag(tag, false); + mainPanel.refreshTree(); + } + }); + contextMenu.add(removeMenuItem); + final JMenuItem removeWithDependenciesMenuItem = new JMenuItem(mainPanel.translate("contextmenu.removeWithDependencies")); + removeWithDependenciesMenuItem.addActionListener(new AbstractAction() { + + @Override + public void actionPerformed(ActionEvent e) { + Tag tag = (Tag) treeItem; + tag.getSwf().removeTag(tag, true); + mainPanel.refreshTree(); + } + }); + contextMenu.add(removeWithDependenciesMenuItem); + this.setComponentPopupMenu(contextMenu); + } + + this.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) { + + if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() >= 2) { + mainPanel.setTreeItem(treeItem); + } + } + + @Override + public void mousePressed(MouseEvent e) { + } + + @Override + public void mouseReleased(MouseEvent e) { + } + + @Override + public void mouseEntered(MouseEvent e) { + } + + @Override + public void mouseExited(MouseEvent e) { + } + }); + } + + private synchronized void renderImageTask(final TreeItem treeItem) { + if (rendering) { + return; + } + rendering = true; + executor.submit(new Callable() { + + @Override + public Void call() throws Exception { + image = renderImage(treeItem.getSwf(), treeItem); + View.execInEventDispatch(new Runnable() { + + @Override + public void run() { + revalidate(); + repaint(); + } + }); + return null; + } + + }); + + } + + private Image renderImage(SWF swf, TreeItem treeItem) { + + double scale = 1; + int width = 0; + int height = 0; + SerializableImage imgSrc = null; + Matrix m = new Matrix(); + if (treeItem instanceof FrameNodeItem) { + FrameNodeItem fn = (FrameNodeItem) treeItem; + RECT rect = swf.displayRect; + imgSrc = SWF.frameToImageGet(swf.getTimeline(), fn.getFrame() - 1, 0, null, 0, rect, Matrix.getScaleInstance(1 / SWF.unitDivisor), new ColorTransform(), null); + width = (imgSrc.getWidth()); + height = (imgSrc.getHeight()); + } else if (treeItem instanceof ImageTag) { + imgSrc = ((ImageTag) treeItem).getImage(); + width = (imgSrc.getWidth()); + height = (imgSrc.getHeight()); + } else if (treeItem instanceof BoundedTag) { + BoundedTag boundedTag = (BoundedTag) treeItem; + RECT rect = boundedTag.getRect(); + width = (int) (rect.getWidth() / SWF.unitDivisor); + height = (int) (rect.getHeight() / SWF.unitDivisor); + m.translate(-rect.Xmin, -rect.Ymin); + } + + int w1 = width; + int h1 = height; + int w2 = PREVIEW_SIZE; + int h2 = PREVIEW_SIZE; + + int w; + int h = h1 * w2 / w1; + if (h > h2) { + w = w1 * h2 / h1; + h = h2; + } else { + w = w2; + } + + scale = (double) w / (double) w1; + if (w1 <= w2 && h1 <= h2) { + scale = 1; + } + + m = m.preConcatenate(Matrix.getScaleInstance(scale)); + width = (int) (scale * width); + height = (int) (scale * height); + if (width == 0 || height == 0) { + return null; + } + + SerializableImage image = new SerializableImage(width, height, SerializableImage.TYPE_INT_ARGB); + image.fillTransparent(); + if (imgSrc == null) { + DrawableTag drawable = (DrawableTag) treeItem; + drawable.toImage(0, 0, 0, null, 0, image, m, new ColorTransform()); + } else { + Graphics2D g = (Graphics2D) image.getGraphics(); + g.setTransform(m.toTransform()); + g.drawImage(imgSrc.getBufferedImage(), 0, 0, null); + } + return image.getBufferedImage(); + } + + public static Component createFolderPreviewImage(MainPanel mainPanel, TreeItem treeItem) { + JPanel pan = new JPanel(new BorderLayout()); + PreviewImage imagePanel = new PreviewImage(mainPanel, treeItem); + pan.add(imagePanel, BorderLayout.CENTER); + String s; + if (treeItem instanceof Tag) { + s = ((Tag) treeItem).getTagName(); + if (treeItem instanceof CharacterTag) { + s = s + " (" + ((CharacterTag) treeItem).getCharacterId() + ")"; + } + } else { + s = treeItem.toString(); + } + JLabel lab = new JLabel(s); + lab.setFont(lab.getFont().deriveFont(AffineTransform.getScaleInstance(0.8, 0.8))); + pan.add(lab, BorderLayout.SOUTH); + return pan; + } + + @Override + protected void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setPaint(View.transparentPaint); + g2d.fill(new Rectangle(0, 0, getWidth(), getHeight())); + g2d.setComposite(AlphaComposite.SrcOver); + g2d.setPaint(View.swfBackgroundColor); + g2d.fill(new Rectangle(0, 0, getWidth(), getHeight())); + if (image != null) { + int x = (getWidth() / 2) - (image.getWidth(this) / 2); + int y = (getHeight() / 2) - (image.getHeight(this) / 2); + g.drawImage(image, x, y, null); + } else { + renderImageTask(treeItem); + } + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index f83d5b53c..c55f06ee9 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -475,4 +475,6 @@ message.confirm.donotshowagain = Do not show again menu.import = Import menu.file.import.text = Import text import.select.directory = Select directory to import -error.text.import = Error during text import. Do you want to continue? \ No newline at end of file +error.text.import = Error during text import. Do you want to continue? + +contextmenu.removeWithDependencies = Remove with dependencies diff --git a/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java b/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java index 2432b7db9..b60169c6d 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java @@ -284,15 +284,7 @@ public class DefineSpriteTag extends CharacterTag implements Container, Drawable @Override public boolean removeCharacter(int characterId) { - boolean modified = false; - for (int i = 0; i < subTags.size(); i++) { - Tag t = subTags.get(i); - if (t instanceof CharacterIdTag && ((CharacterIdTag) t).getCharacterId() == characterId) { - subTags.remove(i); - i--; - modified = true; - } - } + boolean modified = getTimeline().removeCharacter(characterId); if (modified) { setModified(true); } diff --git a/src/com/jpexs/decompiler/flash/timeline/Timeline.java b/src/com/jpexs/decompiler/flash/timeline/Timeline.java index 8b4005893..33f2aa284 100644 --- a/src/com/jpexs/decompiler/flash/timeline/Timeline.java +++ b/src/com/jpexs/decompiler/flash/timeline/Timeline.java @@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.tags.StartSound2Tag; import com.jpexs.decompiler.flash.tags.StartSoundTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ButtonTag; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.DrawableTag; import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; @@ -40,6 +41,7 @@ import java.awt.Shape; import java.awt.geom.Area; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.Stack; /** @@ -53,6 +55,7 @@ public class Timeline { public SWF swf; public RECT displayRect; public int frameRate; + public List tags; public int getMaxDepth() { int max_depth = 0; @@ -82,6 +85,7 @@ public class Timeline { this.swf = swf; this.displayRect = displayRect; this.frameRate = swf.frameRate; + this.tags = tags; Frame frame = new Frame(this); boolean tagAdded = false; for (Tag t : tags) { @@ -184,6 +188,45 @@ public class Timeline { } } + public void getNeededCharacters(Set usedCharacters) { + for (int i = 0; i < getFrameCount(); i++) { + getNeededCharacters(i, usedCharacters); + } + } + + public void getNeededCharacters(List frames, Set usedCharacters) { + for (int frame = 0; frame < frames.size(); frame++) { + getNeededCharacters(frame, usedCharacters); + } + } + + public void getNeededCharacters(int frame, Set usedCharacters) { + Frame frameObj = frames.get(frame); + for (int depth : frameObj.layers.keySet()) { + DepthState layer = frameObj.layers.get(depth); + if (layer.characterId != -1) { + if (!swf.characters.containsKey(layer.characterId)) { + continue; + } + usedCharacters.add(layer.characterId); + swf.characters.get(layer.characterId).getNeededCharactersDeep(usedCharacters); + } + } + } + + public boolean removeCharacter(int characterId) { + boolean modified = false; + for (int i = 0; i < tags.size(); i++) { + Tag t = tags.get(i); + if (t instanceof CharacterIdTag && ((CharacterIdTag) t).getCharacterId() == characterId) { + tags.remove(i); + i--; + modified = true; + } + } + return modified; + } + public void toImage(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { SWF.frameToImage(this, frame, time, stateUnderCursor, mouseButton, image, transformation, colorTransform); } diff --git a/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java b/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java index 50fd4e160..52646a55e 100644 --- a/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java +++ b/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java @@ -63,6 +63,9 @@ public class LINESTYLE2 extends LINESTYLE implements Serializable { @Override public boolean removeCharacter(int characterId) { - return fillType.removeCharacter(characterId); + if (fillType != null) { + return fillType.removeCharacter(characterId); + } + return false; } } diff --git a/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java b/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java index fac590918..21093e99a 100644 --- a/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java +++ b/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java @@ -88,7 +88,10 @@ public class StyleChangeRecord extends SHAPERECORD implements Cloneable { @Override public boolean removeCharacter(int characterId) { - return fillStyles.removeCharacter(characterId); + if (fillStyles != null){ + return fillStyles.removeCharacter(characterId); + } + return false; } @Override