From 2900dd90e05915dd46272f02bb8020cbc86c4d11 Mon Sep 17 00:00:00 2001 From: "honfika@gmail.com" Date: Sat, 25 Apr 2015 19:03:01 +0200 Subject: [PATCH] player control states fixed (when pressing next/prev button), refresh them in event driven way --- .../decompiler/flash/gui/ImagePanel.java | 54 +++++++++-- .../jpexs/decompiler/flash/gui/MainPanel.java | 1 + .../decompiler/flash/gui/SoundTagPlayer.java | 21 +++-- .../flash/gui/player/FlashPlayerPanel.java | 89 +++++++++++++++---- .../flash/gui/player/MediaDisplay.java | 10 ++- .../MediaDisplayListener.java} | 14 +-- .../flash/gui/player/PlayerControls.java | 65 ++++++++------ 7 files changed, 185 insertions(+), 69 deletions(-) rename src/com/jpexs/decompiler/flash/gui/{PlayerListener.java => player/MediaDisplayListener.java} (78%) diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index c4d8a5fdd..9a5208504 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.gui; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.gui.player.MediaDisplay; +import com.jpexs.decompiler.flash.gui.player.MediaDisplayListener; import com.jpexs.decompiler.flash.gui.player.Zoom; import com.jpexs.decompiler.flash.tags.DefineButtonSoundTag; import com.jpexs.decompiler.flash.tags.base.BoundedTag; @@ -72,6 +73,8 @@ import javax.swing.JPanel; public final class ImagePanel extends JPanel implements ActionListener, MediaDisplay { + private final List listeners = new ArrayList<>(); + private Timelined timelined; private boolean stillFrame = false; @@ -125,6 +128,22 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis hideMouseSelection(); } + public void fireMediaDisplayStateChanged() { + for (MediaDisplayListener l : listeners) { + l.mediaDisplayStateChanged(this); + } + } + + @Override + public void addEventListener(MediaDisplayListener listener) { + listeners.add(listener); + } + + @Override + public void removeEventListener(MediaDisplayListener listener) { + listeners.remove(listener); + } + private class IconPanel extends JPanel { private SerializableImage img; @@ -451,6 +470,8 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis if (textTag != null) { setText(textTag, newTextTag); } + + fireMediaDisplayStateChanged(); } } @@ -551,6 +572,8 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis clearImagePanel(); } } + + fireMediaDisplayStateChanged(); } public synchronized void setImage(SerializableImage image) { @@ -564,6 +587,8 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis iconPanel.setImg(image); iconPanel.setOutlines(new ArrayList<>(), new ArrayList<>()); drawReady = true; + + fireMediaDisplayStateChanged(); } public synchronized void setText(TextTag textTag, TextTag newTextTag) { @@ -598,6 +623,8 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis iconPanel.setImg(image); iconPanel.setOutlines(new ArrayList<>(), new ArrayList<>()); drawReady = true; + + fireMediaDisplayStateChanged(); } private synchronized void clearImagePanel() { @@ -638,6 +665,7 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis if (timer != null) { timer.cancel(); timer = null; + fireMediaDisplayStateChanged(); } textTag = null; @@ -663,6 +691,8 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis } } } + + fireMediaDisplayStateChanged(); } private static SerializableImage getFrame(SWF swf, int frame, int time, Timelined drawable, DepthState stateUnderCursor, int mouseButton, int selectedDepth, double zoom) { @@ -815,10 +845,14 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis final SoundTagPlayer sp; try { sp = new SoundTagPlayer(st, 1, false); - sp.addListener(new PlayerListener() { + sp.addEventListener(new MediaDisplayListener() { @Override - public void playingFinished() { + public void mediaDisplayStateChanged(MediaDisplay source) { + } + + @Override + public void playingFinished(MediaDisplay source) { synchronized (ImagePanel.class) { soundPlayers.remove(sp); } @@ -864,6 +898,8 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis clearImagePanel(); timelined = null; swf = null; + + fireMediaDisplayStateChanged(); } public synchronized void stop() { @@ -889,7 +925,7 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis private void startTimer(int cnt, boolean singleFrame, int msPerFrame) { TimerTask task = new TimerTask() { - public final int counter = cnt; + public final int taskCounter = cnt; public final boolean isSingleFrame = singleFrame; @@ -905,11 +941,15 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis } if (isSingleFrame) { - if (first.getAndSet(false)) { - drawFrame(counter); + drawFrame(taskCounter); + synchronized (ImagePanel.class) { + if (taskCounter == counter) { + timer = null; + } } + fireMediaDisplayStateChanged(); } else { - nextFrame(counter); + nextFrame(taskCounter); } } catch (Exception ex) { Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, null, ex); @@ -928,6 +968,7 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis @Override public synchronized void rewind() { frame = 0; + fireMediaDisplayStateChanged(); } @Override @@ -958,6 +999,7 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis stop(); shouldDraw.set(true); startTimer(counter, true, 0); + fireMediaDisplayStateChanged(); } @Override diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index c41437e8f..0a54d40e2 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -2385,6 +2385,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec if (flashPanel != null) { try { flashPanel.close(); + flashPanel.unload(); } catch (IOException ex) { // ignore } diff --git a/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java b/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java index bdd1bf524..ee7015e29 100644 --- a/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java +++ b/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.gui; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.gui.player.MediaDisplay; +import com.jpexs.decompiler.flash.gui.player.MediaDisplayListener; import com.jpexs.decompiler.flash.gui.player.Zoom; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.SoundTag; @@ -55,19 +56,21 @@ public class SoundTagPlayer implements MediaDisplay { private final SoundTag tag; - private final List listeners = new ArrayList<>(); + private final List listeners = new ArrayList<>(); - public void addListener(PlayerListener l) { - listeners.add(l); + @Override + public void addEventListener(MediaDisplayListener listener) { + listeners.add(listener); } - public void removeListener(PlayerListener l) { - listeners.remove(l); + @Override + public void removeEventListener(MediaDisplayListener listener) { + listeners.remove(listener); } - public void fireFinished() { - for (PlayerListener l : listeners) { - l.playingFinished(); + private void firePlayingFinished() { + for (MediaDisplayListener l : listeners) { + l.playingFinished(this); } } @@ -91,7 +94,7 @@ public class SoundTagPlayer implements MediaDisplay { clip.setFramePosition(0); clip.start(); } else { - fireFinished(); + firePlayingFinished(); } } } diff --git a/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java b/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java index 69c0f2947..6f66b3352 100644 --- a/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java @@ -20,7 +20,6 @@ import com.jpexs.decompiler.flash.gui.FlashUnsupportedException; import com.jpexs.decompiler.flash.gui.Main; import com.jpexs.javactivex.ActiveX; import com.jpexs.javactivex.ActiveXEvent; -import com.jpexs.javactivex.ActiveXEventListener; import com.jpexs.javactivex.ActiveXException; import com.jpexs.javactivex.example.controls.flash.ShockwaveFlash; import com.sun.jna.Platform; @@ -34,6 +33,10 @@ import java.awt.Robot; import java.awt.image.BufferedImage; import java.io.Closeable; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -41,9 +44,13 @@ import java.util.regex.Pattern; * * @author JPEXS */ -public class FlashPlayerPanel extends Panel implements Closeable, MediaDisplay { +public final class FlashPlayerPanel extends Panel implements Closeable, MediaDisplay { - private ShockwaveFlash flash; + private final List listeners = new ArrayList<>(); + + private final ShockwaveFlash flash; + + private final Timer timer; private boolean stopped = true; @@ -149,28 +156,58 @@ public class FlashPlayerPanel extends Panel implements Closeable, MediaDisplay { flash.setAllowScriptAccess("always"); flash.setAllowNetworking("all"); - flash.addFlashCallListener(new ActiveXEventListener() { + flash.addOnReadyStateChangeListener((ActiveXEvent axe) -> { + fireMediaDisplayStateChanged(); + }); - @Override - public void onEvent(ActiveXEvent axe) { - String req = (String) axe.args.get("request"); - Matcher m = Pattern.compile("(.*)").matcher(req); - if (m.matches()) { - String funname = m.group(1); - String msg = m.group(2); - if (funname.equals("alert") || funname.equals("console.log")) { - if (Main.debugDialog != null) { - Main.debugDialog.log(funname + ":" + msg); - } + flash.addFlashCallListener((ActiveXEvent axe) -> { + String req = (String) axe.args.get("request"); + Matcher m = Pattern.compile("(.*)").matcher(req); + if (m.matches()) { + String funname = m.group(1); + String msg = m.group(2); + if (funname.equals("alert") || funname.equals("console.log")) { + if (Main.debugDialog != null) { + Main.debugDialog.log(funname + ":" + msg); } } } }); + + timer = new Timer(); + timer.schedule(new TimerTask() { + + private boolean isPlaying = false; + + private int currentFrame = 0; + + @Override + public void run() { + + boolean changed = false; + + boolean isPlaying = flash.IsPlaying(); + if (this.isPlaying != isPlaying) { + this.isPlaying = isPlaying; + } + + int currentFrame = flash.CurrentFrame(); + if (this.currentFrame != currentFrame) { + this.currentFrame = currentFrame; + changed = true; + } + + if (changed) { + fireMediaDisplayStateChanged(); + } + } + }, 100, 100); } public synchronized void stopSWF() { displaySWF("-", null, 1); stopped = true; + fireMediaDisplayStateChanged(); } public synchronized boolean isStopped() { @@ -197,7 +234,7 @@ public class FlashPlayerPanel extends Panel implements Closeable, MediaDisplay { flash.setMovie(flashName); //play stopped = false; - + fireMediaDisplayStateChanged(); } @Override @@ -205,6 +242,10 @@ public class FlashPlayerPanel extends Panel implements Closeable, MediaDisplay { } + public void unload() { + timer.cancel(); + } + @Override public void pause() { try { @@ -261,4 +302,20 @@ public class FlashPlayerPanel extends Panel implements Closeable, MediaDisplay { public boolean isLoaded() { return !isStopped(); } + + public void fireMediaDisplayStateChanged() { + for (MediaDisplayListener l : listeners) { + l.mediaDisplayStateChanged(this); + } + } + + @Override + public void addEventListener(MediaDisplayListener listener) { + listeners.add(listener); + } + + @Override + public void removeEventListener(MediaDisplayListener listener) { + listeners.remove(listener); + } } diff --git a/src/com/jpexs/decompiler/flash/gui/player/MediaDisplay.java b/src/com/jpexs/decompiler/flash/gui/player/MediaDisplay.java index edb15a86f..4596ae4b2 100644 --- a/src/com/jpexs/decompiler/flash/gui/player/MediaDisplay.java +++ b/src/com/jpexs/decompiler/flash/gui/player/MediaDisplay.java @@ -1,16 +1,16 @@ /* * Copyright (C) 2010-2015 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 . */ @@ -56,4 +56,8 @@ public interface MediaDisplay { public double getZoomToFit(); public Zoom getZoom(); + + public void addEventListener(MediaDisplayListener listener); + + public void removeEventListener(MediaDisplayListener listener); } diff --git a/src/com/jpexs/decompiler/flash/gui/PlayerListener.java b/src/com/jpexs/decompiler/flash/gui/player/MediaDisplayListener.java similarity index 78% rename from src/com/jpexs/decompiler/flash/gui/PlayerListener.java rename to src/com/jpexs/decompiler/flash/gui/player/MediaDisplayListener.java index 7aae58115..67087c9b9 100644 --- a/src/com/jpexs/decompiler/flash/gui/PlayerListener.java +++ b/src/com/jpexs/decompiler/flash/gui/player/MediaDisplayListener.java @@ -1,26 +1,28 @@ /* * Copyright (C) 2010-2015 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; +package com.jpexs.decompiler.flash.gui.player; /** * * @author JPEXS */ -public interface PlayerListener { +public interface MediaDisplayListener { - public void playingFinished(); + void mediaDisplayStateChanged(MediaDisplay source); + + void playingFinished(MediaDisplay source); } diff --git a/src/com/jpexs/decompiler/flash/gui/player/PlayerControls.java b/src/com/jpexs/decompiler/flash/gui/player/PlayerControls.java index d52229543..36bb36000 100644 --- a/src/com/jpexs/decompiler/flash/gui/player/PlayerControls.java +++ b/src/com/jpexs/decompiler/flash/gui/player/PlayerControls.java @@ -44,8 +44,6 @@ import java.io.IOException; import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.JButton; @@ -63,7 +61,7 @@ import javax.swing.event.AncestorListener; * * @author JPEXS */ -public class PlayerControls extends JPanel implements ActionListener { +public class PlayerControls extends JPanel implements ActionListener, MediaDisplayListener { private static final String ACTION_PAUSE = "PAUSE"; @@ -95,8 +93,6 @@ public class PlayerControls extends JPanel implements ActionListener { private JProgressBar progress; - private final Timer timer; - private final JLabel timeLabel; private final JLabel frameLabel; @@ -313,14 +309,9 @@ public class PlayerControls extends JPanel implements ActionListener { }); playbackControls.add(progress); playbackControls.add(controlPanel); - timer = new Timer(); - timer.schedule(new TimerTask() { - @Override - public void run() { - update(); - } - }, 100, 100); + add(playbackControls); + this.display.addEventListener(this); } private String formatMs(long ms) { @@ -342,7 +333,12 @@ public class PlayerControls extends JPanel implements ActionListener { } public void setMedia(MediaDisplay media) { + if (this.display != null) { + this.display.removeEventListener(this); + } + this.display = media; + this.display.addEventListener(this); } private void update() { @@ -358,10 +354,11 @@ public class PlayerControls extends JPanel implements ActionListener { zoomFitButton.setVisible(zoom != null); percentLabel.setVisible(zoom != null); zoomPanel.setVisible(display.zoomAvailable()); - graphicControls.setVisible(display.screenAvailable()); - totalFrameLabel.setVisible(display.screenAvailable()); - frameLabel.setVisible(display.screenAvailable()); - frameControls.setVisible(display.screenAvailable()); + boolean screenAvailable = display.screenAvailable(); + graphicControls.setVisible(screenAvailable); + totalFrameLabel.setVisible(screenAvailable); + frameLabel.setVisible(screenAvailable); + frameControls.setVisible(screenAvailable); int totalFrames = display.getTotalFrames(); int currentFrame = display.getCurrentFrame(); if (currentFrame >= totalFrames) { @@ -388,16 +385,13 @@ public class PlayerControls extends JPanel implements ActionListener { if (totalFrames > 1 && !playbackControls.isVisible()) { playbackControls.setVisible(true); } - if (display.isPlaying() == paused) { - paused = !paused; - - if (paused) { - pauseButton.setToolTipText(AppStrings.translate("preview.play")); - pauseButton.setIcon(playIcon); - } else { - pauseButton.setToolTipText(AppStrings.translate("preview.pause")); - pauseButton.setIcon(pauseIcon); - } + boolean paused = !display.isPlaying(); + if (paused) { + pauseButton.setToolTipText(AppStrings.translate("preview.play")); + pauseButton.setIcon(playIcon); + } else { + pauseButton.setToolTipText(AppStrings.translate("preview.pause")); + pauseButton.setIcon(pauseIcon); } } }); @@ -440,10 +434,10 @@ public class PlayerControls extends JPanel implements ActionListener { public void actionPerformed(ActionEvent e) { switch (e.getActionCommand()) { case ACTION_PAUSE: - if (paused) { - display.play(); - } else { + if (display.isPlaying()) { display.pause(); + } else { + display.play(); } break; @@ -550,6 +544,19 @@ public class PlayerControls extends JPanel implements ActionListener { return realZoom; } + @Override + public void mediaDisplayStateChanged(MediaDisplay source) { + if (display != source) { + return; + } + + update(); + } + + @Override + public void playingFinished(MediaDisplay source) { + } + private class TransferableImage implements Transferable { Image img;