player control states fixed (when pressing next/prev button), refresh them in event driven way

This commit is contained in:
2015-04-25 19:03:01 +02:00
parent 59f8113fc8
commit 2900dd90e0
7 changed files with 185 additions and 69 deletions
@@ -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<MediaDisplayListener> 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
@@ -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
}
@@ -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<PlayerListener> listeners = new ArrayList<>();
private final List<MediaDisplayListener> 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();
}
}
}
@@ -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<MediaDisplayListener> 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("<invoke name=\"([^\"]+)\" returntype=\"xml\"><arguments><string>(.*)</string></arguments></invoke>").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("<invoke name=\"([^\"]+)\" returntype=\"xml\"><arguments><string>(.*)</string></arguments></invoke>").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);
}
}
@@ -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 <http://www.gnu.org/licenses/>.
*/
@@ -56,4 +56,8 @@ public interface MediaDisplay {
public double getZoomToFit();
public Zoom getZoom();
public void addEventListener(MediaDisplayListener listener);
public void removeEventListener(MediaDisplayListener listener);
}
@@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}
@@ -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;