/**
* Created : July 4, 2012
*
* @author pquiring
*/
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
import javaforce.*;
import javaforce.media.*;
import javaforce.gl.*;
public class ProjectPanel extends javax.swing.JPanel implements MediaIO {
/**
* Creates new form ProjectPanel
*/
public ProjectPanel(String fn) {
initComponents();
tracks.setLayout(new TracksLayout());
folders.add(new File(JF.getUserPath() + "/Pictures"));
folders.add(new File(JF.getUserPath() + "/Music"));
folders.add(new File(JF.getUserPath() + "/Videos"));
reScan();
timeLine.add(new TimeLine());
homePath = JF.getUserPath();
if (!homePath.endsWith("" + File.separatorChar)) homePath += File.separatorChar;
addCamera();
if (fn != null) loadConfig(fn);
calcMaxLength();
if (JF.isWindows()) {
//requires jMedia : TODO : detect if installed in ..\jmedia
toolbar.remove(play);
toolbar.remove(playSeparator);
}
initDND();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
TrackPopupMenu = new javax.swing.JPopupMenu();
TEdit = new javax.swing.JMenuItem();
TDelete = new javax.swing.JMenuItem();
CameraPopupMenu = new javax.swing.JPopupMenu();
CAdd = new javax.swing.JMenuItem();
CEdit = new javax.swing.JMenuItem();
CDelete = new javax.swing.JMenuItem();
toolbar = new javax.swing.JToolBar();
jLabel1 = new javax.swing.JLabel();
jButton4 = new javax.swing.JButton();
jButton2 = new javax.swing.JButton();
jSeparator1 = new javax.swing.JToolBar.Separator();
jLabel2 = new javax.swing.JLabel();
addElement = new javax.swing.JButton();
editElement = new javax.swing.JButton();
deleteElement = new javax.swing.JButton();
jSeparator3 = new javax.swing.JToolBar.Separator();
jLabel3 = new javax.swing.JLabel();
addKey = new javax.swing.JButton();
editKey = new javax.swing.JButton();
deleteKey = new javax.swing.JButton();
jSeparator5 = new javax.swing.JToolBar.Separator();
render = new javax.swing.JButton();
jSeparator2 = new javax.swing.JToolBar.Separator();
play = new javax.swing.JButton();
playSeparator = new javax.swing.JToolBar.Separator();
props = new javax.swing.JButton();
jSeparator6 = new javax.swing.JToolBar.Separator();
zoomOut = new javax.swing.JButton();
zoomIn = new javax.swing.JButton();
jSplitPane1 = new javax.swing.JSplitPane();
jPanel1 = new javax.swing.JPanel();
jScrollPane1 = new javax.swing.JScrollPane();
tree = new javax.swing.JTree();
jPanel2 = new javax.swing.JPanel();
tracksScroll = new javax.swing.JScrollBar();
timeLine = new javax.swing.JPanel();
timeScroll = new javax.swing.JScrollBar();
tracks = new javax.swing.JPanel();
TEdit.setText("Edit");
TEdit.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
TEditActionPerformed(evt);
}
});
TrackPopupMenu.add(TEdit);
TDelete.setText("Delete");
TDelete.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
TDeleteActionPerformed(evt);
}
});
TrackPopupMenu.add(TDelete);
CAdd.setText("Add");
CAdd.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
CAddActionPerformed(evt);
}
});
CameraPopupMenu.add(CAdd);
CEdit.setText("Edit");
CEdit.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
CEditActionPerformed(evt);
}
});
CameraPopupMenu.add(CEdit);
CDelete.setText("Delete");
CDelete.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
CDeleteActionPerformed(evt);
}
});
CameraPopupMenu.add(CDelete);
toolbar.setFloatable(false);
toolbar.setRollover(true);
jLabel1.setText("Track:");
toolbar.add(jLabel1);
jButton4.setText("Add");
jButton4.setFocusable(false);
jButton4.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
jButton4.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
jButton4.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton4ActionPerformed(evt);
}
});
toolbar.add(jButton4);
jButton2.setText("Delete");
jButton2.setFocusable(false);
jButton2.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
jButton2.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton2ActionPerformed(evt);
}
});
toolbar.add(jButton2);
toolbar.add(jSeparator1);
jLabel2.setText("Element:");
toolbar.add(jLabel2);
addElement.setText("Add");
addElement.setFocusable(false);
addElement.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
addElement.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
addElement.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
addElementActionPerformed(evt);
}
});
toolbar.add(addElement);
editElement.setText("Edit");
editElement.setFocusable(false);
editElement.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
editElement.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
editElement.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
editElementActionPerformed(evt);
}
});
toolbar.add(editElement);
deleteElement.setText("Delete");
deleteElement.setFocusable(false);
deleteElement.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
deleteElement.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
deleteElement.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
deleteElementActionPerformed(evt);
}
});
toolbar.add(deleteElement);
toolbar.add(jSeparator3);
jLabel3.setText("Camera:");
toolbar.add(jLabel3);
addKey.setText("Add");
addKey.setFocusable(false);
addKey.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
addKey.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
addKey.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
addKeyActionPerformed(evt);
}
});
toolbar.add(addKey);
editKey.setText("Edit");
editKey.setFocusable(false);
editKey.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
editKey.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
editKey.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
editKeyActionPerformed(evt);
}
});
toolbar.add(editKey);
deleteKey.setText("Delete");
deleteKey.setFocusable(false);
deleteKey.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
deleteKey.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
deleteKey.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
deleteKeyActionPerformed(evt);
}
});
toolbar.add(deleteKey);
toolbar.add(jSeparator5);
render.setText("Render");
render.setFocusable(false);
render.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
render.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
render.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
renderActionPerformed(evt);
}
});
toolbar.add(render);
toolbar.add(jSeparator2);
play.setText("Play");
play.setFocusable(false);
play.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
play.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
play.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
playActionPerformed(evt);
}
});
toolbar.add(play);
toolbar.add(playSeparator);
props.setText("Properties");
props.setFocusable(false);
props.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
props.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
props.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
propsActionPerformed(evt);
}
});
toolbar.add(props);
toolbar.add(jSeparator6);
zoomOut.setText("Zoom-");
zoomOut.setFocusable(false);
zoomOut.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
zoomOut.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
zoomOut.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
zoomOutActionPerformed(evt);
}
});
toolbar.add(zoomOut);
zoomIn.setText("Zoom+");
zoomIn.setFocusable(false);
zoomIn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
zoomIn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
zoomIn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
zoomInActionPerformed(evt);
}
});
toolbar.add(zoomIn);
jSplitPane1.setDividerLocation(200);
jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
jSplitPane1.setResizeWeight(0.3);
tree.setDragEnabled(true);
jScrollPane1.setViewportView(tree);
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 811, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 199, Short.MAX_VALUE)
);
jSplitPane1.setTopComponent(jPanel1);
tracksScroll.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
public void adjustmentValueChanged(java.awt.event.AdjustmentEvent evt) {
tracksScrollAdjustmentValueChanged(evt);
}
});
timeLine.setLayout(new java.awt.GridLayout(1, 1));
timeScroll.setOrientation(javax.swing.JScrollBar.HORIZONTAL);
timeScroll.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
public void adjustmentValueChanged(java.awt.event.AdjustmentEvent evt) {
timeScrollAdjustmentValueChanged(evt);
}
});
tracks.addComponentListener(new java.awt.event.ComponentAdapter() {
public void componentResized(java.awt.event.ComponentEvent evt) {
tracksComponentResized(evt);
}
});
javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
jPanel2.setLayout(jPanel2Layout);
jPanel2Layout.setHorizontalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addComponent(tracks, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tracksScroll, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(timeLine, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(timeScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 811, Short.MAX_VALUE)
);
jPanel2Layout.setVerticalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(tracksScroll, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 409, Short.MAX_VALUE)
.addComponent(tracks, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(timeLine, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(timeScroll, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
);
jSplitPane1.setRightComponent(jPanel2);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(toolbar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jSplitPane1, javax.swing.GroupLayout.Alignment.TRAILING)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(toolbar, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSplitPane1))
);
}// </editor-fold>//GEN-END:initComponents
private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton4ActionPerformed
addTrack();
}//GEN-LAST:event_jButton4ActionPerformed
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
deleteTrack();
}//GEN-LAST:event_jButton2ActionPerformed
private void tracksScrollAdjustmentValueChanged(java.awt.event.AdjustmentEvent evt) {//GEN-FIRST:event_tracksScrollAdjustmentValueChanged
tracks.doLayout();
}//GEN-LAST:event_tracksScrollAdjustmentValueChanged
private void tracksComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_tracksComponentResized
resizeTracks();
}//GEN-LAST:event_tracksComponentResized
private void timeScrollAdjustmentValueChanged(java.awt.event.AdjustmentEvent evt) {//GEN-FIRST:event_timeScrollAdjustmentValueChanged
setOffset(timeScroll.getValue());
}//GEN-LAST:event_timeScrollAdjustmentValueChanged
private void addElementActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addElementActionPerformed
addElement();
calcMaxLength();
}//GEN-LAST:event_addElementActionPerformed
private void propsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_propsActionPerformed
props();
}//GEN-LAST:event_propsActionPerformed
private void editElementActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editElementActionPerformed
editElement();
}//GEN-LAST:event_editElementActionPerformed
private void deleteElementActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteElementActionPerformed
deleteElement();
}//GEN-LAST:event_deleteElementActionPerformed
private void renderActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_renderActionPerformed
render();
}//GEN-LAST:event_renderActionPerformed
private void zoomOutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomOutActionPerformed
if (scale == 1) return;
scale /= 2;
tracks.repaint();
timeLine.repaint();
calcMaxLength();
// redoPreview();
}//GEN-LAST:event_zoomOutActionPerformed
private void zoomInActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomInActionPerformed
if (scale == 128) return;
scale *= 2;
tracks.repaint();
timeLine.repaint();
calcMaxLength();
// redoPreview();
}//GEN-LAST:event_zoomInActionPerformed
private void playActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_playActionPerformed
if (renderFile == null || !new File(renderFile).exists()) {
JF.showError("Error", "Please render first");
return;
}
try {
Runtime.getRuntime().exec(new String[] {"jmedia", renderFile});
} catch (Exception e) {
JFLog.log(e);
}
}//GEN-LAST:event_playActionPerformed
private void addKeyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addKeyActionPerformed
addKey();
}//GEN-LAST:event_addKeyActionPerformed
private void editKeyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editKeyActionPerformed
editKey();
}//GEN-LAST:event_editKeyActionPerformed
private void deleteKeyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteKeyActionPerformed
deleteKey();
}//GEN-LAST:event_deleteKeyActionPerformed
private void TEditActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_TEditActionPerformed
editElement();
}//GEN-LAST:event_TEditActionPerformed
private void TDeleteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_TDeleteActionPerformed
deleteElement();
}//GEN-LAST:event_TDeleteActionPerformed
private void CAddActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_CAddActionPerformed
addKey();
}//GEN-LAST:event_CAddActionPerformed
private void CEditActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_CEditActionPerformed
editKey();
}//GEN-LAST:event_CEditActionPerformed
private void CDeleteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_CDeleteActionPerformed
deleteKey();
}//GEN-LAST:event_CDeleteActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JMenuItem CAdd;
private javax.swing.JMenuItem CDelete;
private javax.swing.JMenuItem CEdit;
private javax.swing.JPopupMenu CameraPopupMenu;
private javax.swing.JMenuItem TDelete;
private javax.swing.JMenuItem TEdit;
private javax.swing.JPopupMenu TrackPopupMenu;
private javax.swing.JButton addElement;
private javax.swing.JButton addKey;
private javax.swing.JButton deleteElement;
private javax.swing.JButton deleteKey;
private javax.swing.JButton editElement;
private javax.swing.JButton editKey;
private javax.swing.JButton jButton2;
private javax.swing.JButton jButton4;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JToolBar.Separator jSeparator1;
private javax.swing.JToolBar.Separator jSeparator2;
private javax.swing.JToolBar.Separator jSeparator3;
private javax.swing.JToolBar.Separator jSeparator5;
private javax.swing.JToolBar.Separator jSeparator6;
private javax.swing.JSplitPane jSplitPane1;
private javax.swing.JButton play;
private javax.swing.JToolBar.Separator playSeparator;
private javax.swing.JButton props;
private javax.swing.JButton render;
private javax.swing.JPanel timeLine;
private javax.swing.JScrollBar timeScroll;
private javax.swing.JToolBar toolbar;
private javax.swing.JPanel tracks;
private javax.swing.JScrollBar tracksScroll;
private javax.swing.JTree tree;
private javax.swing.JButton zoomIn;
private javax.swing.JButton zoomOut;
// End of variables declaration//GEN-END:variables
private XML xml;
private XML.XMLTag library, image, audio, video, special; //library sub-tags
private ArrayList<File> folders = new ArrayList<File>();
public int scale = 1; //time scale (# seconds per 16 pxs)
public int offset; //in seconds
public Config config = new Config();
private JPanel selectedTrack;
private String homePath;
private int maxLength; //in seconds
public String projectFile;
public Element dragElement;
public TrackPanel dragTrack, dragSrcTrack;
private CameraPanel camera;
public int read(MediaCoder coder, byte[] bytes) {
int read = 0;
try {
read = raf.read(bytes, 0, bytes.length);
} catch (Exception e) {
JFLog.log(e);
}
if (read == -1) read = 0;
return read;
}
public int write(MediaCoder coder, byte[] bytes) {
try {
raf.write(bytes, 0, bytes.length);
} catch (Exception e) {
JFLog.log(e);
return 0;
}
return bytes.length;
}
public long seek(MediaCoder coder, long pos, int how) {
try {
switch (how) {
case MediaCoder.SEEK_SET: break; //seek set
case MediaCoder.SEEK_CUR: pos += raf.getFilePointer(); break; //seek cur
case MediaCoder.SEEK_END: pos += raf.length(); break; //seek end
}
raf.seek(pos);
} catch (Exception e) {
JFLog.log(e);
}
return pos;
}
public void saveConfig() {
int noTracks = tracks.getComponentCount() - 1;
config.track = new Track[noTracks];
for(int a=0;a<noTracks;a++) {
config.track[a] = new Track();
TrackPanel track = (TrackPanel)tracks.getComponent(a+1);
config.track[a].element = track.list.toArray(new Element[0]);
}
config.cameraKey = camera.list.toArray(new CameraKey[0]);
XML projectXML = new XML();
projectXML.readClass("jfvideo", config);
projectXML.write(projectFile);
}
public void loadConfig(String fn) {
projectFile = fn;
XML projectXML = new XML();
projectXML.read(projectFile);
projectXML.writeClass(config);
for(int a=0;a<config.track.length;a++) {
TrackPanel track = this.addTrack();
int noElements = config.track[a].element.length;
for(int b=0;b<noElements;b++) {
Element e = config.track[a].element[b];
track.list.add(e);
}
}
if (config.cameraKey == null || config.cameraKey.length == 0) {
config.cameraKey = new CameraKey[1];
config.cameraKey[0] = new CameraKey();
}
camera.list.clear();
for(int a=0;a<config.cameraKey.length;a++) {
camera.list.add(config.cameraKey[a]);
}
if (config.preview) createPreviews();
repaint();
}
private boolean isMediaImage(String fn) {
fn = fn.toLowerCase();
if (fn.endsWith(".png")) return true;
if (fn.endsWith(".jpg")) return true;
if (fn.endsWith(".gif")) return true;
if (fn.endsWith(".bmp")) return true;
return false;
}
private boolean isMediaMusic(String fn) {
fn = fn.toLowerCase();
if (fn.endsWith(".wav")) return true;
if (fn.endsWith(".fla")) return true;
if (fn.endsWith(".flac")) return true;
if (fn.endsWith(".mp3")) return true;
if (fn.endsWith(".wma")) return true;
if (fn.endsWith(".oga")) return true;
if (fn.endsWith(".spx")) return true;
return false;
}
private boolean isMediaVideo(String fn) {
fn = fn.toLowerCase();
if (fn.endsWith(".ogg")) return true;
if (fn.endsWith(".ogv")) return true;
if (fn.endsWith(".avi")) return true;
if (fn.endsWith(".wmv")) return true;
if (fn.endsWith(".mpg")) return true;
if (fn.endsWith(".mpeg")) return true;
if (fn.endsWith(".mp4")) return true;
if (fn.endsWith(".mov")) return true;
if (fn.endsWith(".3gp")) return true;
if (fn.endsWith(".webm")) return true;
return false;
}
private int getMediaType(String fn) {
if (fn.startsWith("*")) return getSpecialType(fn);
if (isMediaImage(fn)) return Element.TYPE_IMAGE;
if (isMediaVideo(fn)) return Element.TYPE_VIDEO;
if (isMediaMusic(fn)) return Element.TYPE_AUDIO;
return 0;
}
private int getSpecialType(String fn) {
if (fn.equals("*cut")) return Element.TYPE_SPECIAL_CUT;
if (fn.equals("*blur")) return Element.TYPE_SPECIAL_BLUR;
if (fn.equals("*text")) return Element.TYPE_SPECIAL_TEXT;
return 0;
}
public void addFile(File file) {
String fn = file.getName().toLowerCase();
if (isMediaImage(fn)) {
xml.addTag(image, file.getName(), "", file.getAbsolutePath());
}
if (isMediaMusic(fn)) {
xml.addTag(audio, file.getName(), "", file.getAbsolutePath());
}
if (isMediaVideo(fn)) {
xml.addTag(video, file.getName(), "", file.getAbsolutePath());
}
}
private void addLibrary(File file) {
File files[] = file.listFiles();
if (files == null) return;
for(int a=0;a<files.length;a++) {
if (files[a].isDirectory()) {
addLibrary(files[a]);
} else {
addFile(files[a]);
}
}
}
public void addFolder() {
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setMultiSelectionEnabled(false);
chooser.setCurrentDirectory(new File(JF.getUserPath()));
if (chooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) return;
File folder = chooser.getSelectedFile();
if (!folder.isDirectory()) {
JFLog.log("Is not a folder");
return;
}
for(int a=0;a<folders.size();a++) {
File have = folders.get(a);
if (have.getAbsolutePath().equals(folder.getAbsoluteFile())) {
JFLog.log("Already have that folder");
return;
}
}
folders.add(folder);
addLibrary(folder);
}
public void reScan() {
xml = new XML();
xml.root.setName("Media");
library = xml.addTag(xml.root, "Library", "", "");
image = xml.addTag(library, "Images", "", "");
audio = xml.addTag(library, "Audio", "", "");
video = xml.addTag(library, "Video", "", "");
special = xml.addTag(library, "Special", "", "");
for(int a=0;a<folders.size();a++) {
addLibrary(folders.get(a));
}
xml.addTag(special, "Cut", "", "*cut");
xml.addTag(special, "Blur", "", "*blur");
xml.addTag(special, "Text", "", "*text");
tree.setModel(xml.getTreeModel());
tree.makeVisible(new TreePath(image.getPath()));
tree.makeVisible(new TreePath(audio.getPath()));
tree.makeVisible(new TreePath(video.getPath()));
}
public int getTracksWidth() {
return tracks.getWidth();
}
public void selectTrack(JPanel track) {
selectedTrack = track;
for(int a=0;a<tracks.getComponentCount();a++) {
JPanel panel = (JPanel)tracks.getComponent(a);
if (panel instanceof CameraPanel) {
CameraPanel cp = (CameraPanel)panel;
if (cp == track) {
if (cp.selected) continue;
cp.selected = true;
cp.repaint();
} else {
if (!cp.selected) continue;
cp.selected = false;
cp.repaint();
}
} else {
TrackPanel tp = (TrackPanel)panel;
if (tp == track) {
if (tp.selected) continue;
tp.selected = true;
tp.repaint();
} else {
if (!tp.selected) continue;
tp.selected = false;
tp.repaint();
}
}
}
}
private void addCamera() {
camera = new CameraPanel(this);
camera.setComponentPopupMenu(CameraPopupMenu);
tracks.add(camera);
resizeTracks();
tracks.revalidate();
tracks.repaint();
}
private TrackPanel addTrack() {
TrackPanel track = new TrackPanel(this);
track.setComponentPopupMenu(TrackPopupMenu);
tracks.add(track);
resizeTracks();
tracks.revalidate();
tracks.repaint();
return track;
}
private void deleteTrack() {
for(int a=1;a<tracks.getComponentCount();a++) {
TrackPanel track = (TrackPanel)tracks.getComponent(a);
if (track.selected) {
if (JF.showConfirm("Confirm", "Delete this track with " + track.list.size() + " elements?")) {
tracks.remove(track);
resizeTracks();
tracks.revalidate();
tracks.repaint();
if (selectedTrack == track) selectedTrack = null;
return;
}
}
}
}
private void resizeTracks() {
// JFLog.log("resizeTracks");
tracksScroll.setMinimum(0);
tracksScroll.setMaximum(totalTracksHeight());
tracksScroll.setVisibleAmount(tracks.getHeight());
}
public int totalTracksHeight() {
return 16 + ((tracks.getComponentCount()-1) * 64);
}
private Dimension layoutSize;
private class TracksLayout implements LayoutManager {
// private Vector<Component> list = new Vector<Component>();
public void addLayoutComponent(String string, Component cmp) {
// list.add(cmp);
}
public void removeLayoutComponent(Component cmp) {
// list.remove(cmp);
}
public Dimension preferredLayoutSize(Container c) {
if (layoutSize == null) layoutContainer(c);
return layoutSize;
}
public Dimension minimumLayoutSize(Container c) {
return new Dimension(1,1);
}
public void layoutContainer(Container c) {
int cnt = c.getComponentCount();
int x = tracks.getWidth();
int cx = 0;
int cy = -tracksScroll.getValue();
for(int a=0;a<cnt;a++) {
Component child = c.getComponent(a);
Dimension d = child.getPreferredSize();
child.setBounds(cx, cy, x, d.height);
cy += d.height;
}
c.setPreferredSize(new Dimension(x, cy));
layoutSize = new Dimension(x, cy);
}
}
public void calcMaxLength() {
maxLength = 0;
for(int a=1;a<tracks.getComponentCount();a++) {
TrackPanel track = (TrackPanel)tracks.getComponent(a);
int trackLength = track.totalLength(); //in seconds
if (trackLength > maxLength) maxLength = trackLength;
}
// JFLog.log("maxLength=" + maxLength);
int scaleLength = (maxLength + 10*scale) / scale; //+10 to show a bit beyond the end
int visibleLength = getWidth() / 16;
// JFLog.log("visibleLength=" + visibleLength);
if (scaleLength < visibleLength) scaleLength = visibleLength;
timeScroll.setMinimum(0);
timeScroll.setMaximum(scaleLength);
// timeScroll.setBlockIncrement(?);
timeScroll.setVisibleAmount(visibleLength);
}
public void setOffset(int value) {
offset = value * scale;
// JFLog.log("offset=" + offset + ":value=" + value);
repaint();
}
public void drag(MouseEvent evt, TrackPanel track) {
//pass to track
int x = evt.getX();
int y = evt.getY();
if (x < 0) return;
if (x > getTracksWidth()) return;
int idx = -1;
for(int a=1;a<tracks.getComponentCount();a++) {
if (tracks.getComponent(a) == track) {idx = a; break;}
}
if (idx == -1) return;
while (y < 0) {
idx--;
y += 64;
}
while (y >= 64) {
idx++;
y -= 64;
}
if (idx <= 0) return;
if (idx >= tracks.getComponentCount()) return;
track = (TrackPanel)tracks.getComponent(idx);
track.drag(evt);
if (dragTrack != null) dragTrack.repaint();
dragTrack = track;
if (dragSrcTrack == null) dragSrcTrack = track;
}
public void stopDrag() {
TrackPanel track = dragTrack;
if (dragElement != null) {
dragSrcTrack.deleteElement(dragElement);
if (!dragTrack.used(dragTrack.selectedOffset, dragElement.length)) {
dragSrcTrack.deleteElement(dragElement);
dragTrack.addElement(dragElement, true);
} else {
dragSrcTrack.addElement(dragElement, false);
}
}
dragElement = null;
dragTrack = null;
dragSrcTrack = null;
track.repaint();
calcMaxLength();
}
private class TimeLine extends JComponent {
public void paint(Graphics g) {
// JFLog.log("TimeLine:scale=" + scale);
int x = getWidth();
int y = getHeight();
g.setColor(Color.GRAY);
g.fillRect(0,0,x,y);
double point_n = scale;
double point_d = 16;
double toff = offset;
double toffDec = toff % point_n;
int poff = (int)(-scale * toffDec);
toff -= toffDec;
int h = getHeight();
g.setColor(Color.BLACK);
FontMetrics fm = this.getFontMetrics(this.getFont());
int fh = fm.getHeight();
String txt;
int cnt = 1;
while (poff < getWidth()) {
int min = (int)(toff / 60.0);
int sec = (int)(toff - (min * 60.0));
if (toff >= 60.0) {
txt = String.format("%d:%02d", min, sec);
} else {
txt = String.format("%ds", sec);
}
int fw = fm.stringWidth(txt) / 2;
cnt--;
if (cnt == 0) {
g.drawBytes(txt.getBytes(), 0, txt.length(), poff - fw, h/2 - 5);
g.drawLine(poff,h/2,poff,h);
cnt = 3;
}
/*
if (selectStart >= toff && selectStart < toff + point_n) {
int soff = poff + (int)((selectStart - toff) * scale);
g.drawLine(soff, 0, soff, h);
}
if (selectStop >= toff && selectStop < toff + point_n) {
int soff = poff + (int)((selectStop - toff) * scale);
g.drawLine(soff, 0, soff, h);
}
*/
toff += point_n;
poff += point_d;
}
}
public Dimension getPreferredSize() {
return new Dimension(ProjectPanel.this.getWidth(), 32);
}
public Dimension getMaximumSize() {
return getPreferredSize();
}
}
private ArrayList<String> getFiles(boolean prep) {
TreePath path[] = tree.getSelectionPaths();
ArrayList<String> files = new ArrayList<String>();
for(int a=0;a<path.length;a++) {
XML.XMLTag tag = xml.getTag(path[a]);
if (tag == null) continue;
String file = tag.getContent();
files.add(file);
}
return prep ? prepFiles(files) : files;
}
public ArrayList<String> prepFiles(ArrayList<String> files) {
int homeLength = homePath.length();
for(int a=0;a<files.size();) {
String file = files.get(a);
int idx = file.indexOf("*");
if (idx == -1) {
if (!new File(file).exists()) { JFLog.log("Ignore file does not exist:" + file); files.remove(a); continue; }
if (!file.substring(0, homeLength).equals(homePath)) { JFLog.log("Ignore file not in user profile:" + file); files.remove(a); continue; }
file = "./" + file.substring(homeLength);
if (a > 0 && getMediaType(file) != Element.TYPE_IMAGE) { files.remove(a); continue; } //can only load multiple images
} else {
if (idx > 0) file = file.substring(idx); //drag and drop will include homePath
if (a > 0) {files.remove(a); continue;} //can only add one special at a time
}
files.set(a, file);
a++;
}
return files;
}
public void addElement(ArrayList<String> files) {
JFLog.log("addElement:" + files.size());
if (files.size() == 0) return;
if (files.size() == 1) {
String file = files.get(0);
((TrackPanel)selectedTrack).addElement(new String[] {file}, getMediaType(file));
} else {
//multi-file selection (must all be images)
((TrackPanel)selectedTrack).addElement(files.toArray(new String[0]), Element.TYPE_IMAGE);
}
}
private void addElement() {
if (selectedTrack == null || !(selectedTrack instanceof TrackPanel)) {JF.showError("Error", "Select a track first"); return;}
addElement(getFiles(true));
}
private String renderFile;
private RandomAccessFile raf;
public class GLData {
public GLScene scene;
public GLRender render;
public GLModel model;
public GLObject object;
public JFImage image3d;
public GLOffscreen off;
}
private GLData gldata;
private boolean init3d() {
gldata = new GLData();
MainPanel.runGL(new Runnable() {
public void run() {
MainPanel.gl.pollEvents();
gldata.scene = new GLScene();
gldata.off = new GLOffscreen();
gldata.off.createOffscreen(config.width, config.height);
gldata.scene.init(GLVertexShader.source, GLFragmentShader.source);
gldata.render = new GLRender();
gldata.render.init(gldata.scene, config.width, config.height);
gldata.image3d = new JFImage(config.width, config.height);
gldata.model = new GLModel();
gldata.object = new GLObject();
float z = 5.0f;
float x = 2.0f;
float y = 2.0f;
GLUVMap map = gldata.object.createUVMap();
map.textureIndex = 0;
map.texloaded = true; //direct loaded
gldata.object.addVertex(new float[] {-x,-y,-z}, new float[] {0,1});
gldata.object.addVertex(new float[] {+x,-y,-z}, new float[] {1,1});
gldata.object.addVertex(new float[] {-x,+y,-z}, new float[] {0,0});
gldata.object.addVertex(new float[] {+x,+y,-z}, new float[] {1,0});
gldata.object.addPoly(new int[] {0,3,2});
gldata.object.addPoly(new int[] {0,1,3});
gldata.object.copyBuffers();
gldata.model.addObject(gldata.object);
gldata.model.addTexture("0");
gldata.scene.addModel(gldata.model);
}
});
return true;
}
private void uninit3d() {
gldata = null;
}
public void render() {
if (tracks.getComponentCount() == 1) {
JF.showError("Error", "Please add some tracks first");
return;
}
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
chooser.setMultiSelectionEnabled(false);
chooser.setCurrentDirectory(new File(JF.getUserPath() + "/Videos"));
/* javax.swing.filechooser.FileFilter ogg = new javax.swing.filechooser.FileFilter() {
public boolean accept(File file) {
if (file.isDirectory()) return true;
return file.getName().endsWith(".ogg");
}
public String getDescription() {
return "Ogg Videos (*.ogg)";
}
};
chooser.addChoosableFileFilter(ogg);*/
javax.swing.filechooser.FileFilter avi = new javax.swing.filechooser.FileFilter() {
public boolean accept(File file) {
if (file.isDirectory()) return true;
return file.getName().endsWith(".avi");
}
public String getDescription() {
return "AVI Videos (*.avi)";
}
};
chooser.addChoosableFileFilter(avi);
chooser.setFileFilter(avi);
if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) return;
calcMaxLength();
renderFile = chooser.getSelectedFile().getAbsolutePath();
if (!renderFile.endsWith(".avi")) renderFile += ".avi";
try {
raf = new RandomAccessFile(renderFile, "rw");
raf.setLength(0); //truncate file if exists
} catch (Exception e) {
JFLog.log(e);
JF.showError("Error", "Unable to create output file");
return;
}
JFTask task = new JFTask() {
public boolean work() {
this.setTitle("Rendering...");
this.setLabel("Rendering " + (maxLength * config.videoRate) + " frames...");
this.setProgress(0);
int audioLengthPerFrame = config.audioRate / config.videoRate;
int audioFraction = config.audioRate % config.videoRate;
MediaEncoder ff = new MediaEncoder();
ff.set1000over1001(config.v1001);
System.out.println("bitRates:" + config.videoBitRate + "," + config.audioBitRate);
ff.setVideoBitRate(config.videoBitRate);
ff.setAudioBitRate(config.audioBitRate);
if (!ff.start(ProjectPanel.this, config.width, config.height, config.videoRate, config.audioChannels
, config.audioRate, "avi", true, true))
{
this.setLabel("Error:Encoder failed");
return false;
}
int audioFractionCounter = 0;
short audio0[] = new short[audioLengthPerFrame * config.audioChannels];
short audio1[] = new short[(audioLengthPerFrame+1) * config.audioChannels];
short audio[];
JFImage image = new JFImage(config.width, config.height);
boolean cut;
init3d();
CameraKey keys[] = camera.list.toArray(new CameraKey[0]);
float delta_tx = 0, delta_ty = 0, delta_tz = 0;
float delta_rx = 0, delta_ry = 0, delta_rz = 0;
float delta_fov = 0;
boolean foundKey = false, delta = false;
for(int second=0;second<maxLength;second++) {
if (abort) break;
this.setProgress(second * 100 / maxLength);
for(int a=0;a<keys.length;a++) {
if (keys[a].offset == second) {
gldata.render.cameraReset();
gldata.render.cameraTranslate(keys[a].tx, keys[a].ty, keys[a].tz);
gldata.render.cameraRotate(keys[a].rx, 1.0f, 0.0f, 0.0f);
gldata.render.cameraRotate(keys[a].ry, 0.0f, 1.0f, 0.0f);
gldata.render.cameraRotate(keys[a].rz, 0.0f, 0.0f, 1.0f);
gldata.render.fovy = keys[a].fov;
foundKey = true;
//find next key and calc delta per frame (NOTE:keys are sorted)
if (a == keys.length-1) {
//last key - no delta
delta = false;
delta_tx = 0;
delta_ty = 0;
delta_tz = 0;
delta_rx = 0;
delta_ry = 0;
delta_rz = 0;
delta_fov = 0;
} else {
delta = true;
float delta_frames = (keys[a+1].offset - keys[a].offset) * config.videoRate;
delta_tx = (keys[a+1].tx - keys[a].tx) / delta_frames;
delta_ty = (keys[a+1].ty - keys[a].ty) / delta_frames;
delta_tz = (keys[a+1].tz - keys[a].tz) / delta_frames;
delta_rx = (keys[a+1].rx - keys[a].rx) / delta_frames;
delta_ry = (keys[a+1].ry - keys[a].ry) / delta_frames;
delta_rz = (keys[a+1].rz - keys[a].rz) / delta_frames;
delta_fov = (keys[a+1].fov - keys[a].fov) / delta_frames;
}
break;
}
} //keys
for(int frame=0;frame<config.videoRate;frame++) {
if (!foundKey) {
if (delta) {
gldata.render.cameraTranslate(delta_tx, delta_ty, delta_tz);
gldata.render.cameraRotate(delta_rx, 1.0f, 0.0f, 0.0f);
gldata.render.cameraRotate(delta_ry, 0.0f, 1.0f, 0.0f);
gldata.render.cameraRotate(delta_rz, 0.0f, 0.0f, 1.0f);
gldata.render.fovy += delta_fov;
}
} else {
foundKey = false;
}
audioFractionCounter += audioFraction;
if (audioFractionCounter > config.videoRate) {
audioFractionCounter -= config.videoRate;
audio = audio1;
} else{
audio = audio0;
}
Arrays.fill(audio, (short)0);
image.clear();
cut = false;
for(int trackNo=1;trackNo<tracks.getComponentCount();trackNo++) {
TrackPanel track = (TrackPanel)tracks.getComponent(trackNo);
track.renderVideo(gldata, image, second, frame);
track.renderAudio(audio, second, frame);
if (track.isCut()) cut = true;
} //track
if (cut) continue;
ff.addVideo(image.getBuffer());
ff.addAudio(audio);
} //frame
} //second
uninit3d();
ff.stop();
for(int trackNo=1;trackNo<tracks.getComponentCount();trackNo++) {
TrackPanel track = (TrackPanel)tracks.getComponent(trackNo);
track.stop();
}
JF.sleep(500);
this.setProgress(100);
return true;
}
};
ProgressDialog dialog = new ProgressDialog(null, true, task);
task.setProperty("dialog", dialog);
dialog.setVisible(true);
try {raf.close();} catch (Exception e) {}
}
private void createPreviews() {
JFTask task = new JFTask() {
public boolean work() {
this.setTitle("Creating Previews");
this.setLabel("Creating Previews");
this.setProgress(-1);
int noTracks = tracks.getComponentCount() - 1;
for(int a=0;a<noTracks;a++) {
this.setProgress(a * 100 / noTracks);
TrackPanel track = (TrackPanel)tracks.getComponent(a+1);
int noElements = track.list.size();
for(int b=0;b<noElements;b++) {
track.list.get(b).createPreview(this);
}
}
this.setProgress(100);
return true;
}
};
ProgressDialog dialog = new ProgressDialog(null, true, task);
dialog.setAutoClose(true);
dialog.setVisible(true);
}
private void editElement() {
if (selectedTrack == null) return;
if (selectedTrack instanceof TrackPanel) {
((TrackPanel)selectedTrack).editElement();
calcMaxLength();
}
}
private void deleteElement() {
if (selectedTrack == null) return;
if (selectedTrack instanceof TrackPanel) {
((TrackPanel)selectedTrack).deleteElement();
calcMaxLength();
}
}
private void addKey() {
camera.addKey();
}
private void editKey() {
camera.editKey();
}
private void deleteKey() {
camera.deleteKey();
}
public void props() {
EditProjectProperties dialog = new EditProjectProperties(null, true, this);
dialog.setVisible(true);
calcMaxLength();
}
private void initDND() {
tree.setTransferHandler(new TransferHandler() {
public boolean canImport(TransferHandler.TransferSupport info) {
// we only import Files
if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
return false;
}
TransferHandler.DropLocation dl = (TransferHandler.DropLocation) info.getDropLocation();
Point pt = dl.getDropPoint();
JComponent c = (JComponent)tree.getComponentAt(pt);
return true;
}
public boolean importData(TransferHandler.TransferSupport info) {
if (!info.isDrop()) {
return false;
}
// Check for file flavor
if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
return false;
}
TransferHandler.DropLocation dl = info.getDropLocation();
Point pt = dl.getDropPoint();
JComponent c = (JComponent)tree.getComponentAt(pt);
// Get the file(s) that are being dropped.
Transferable t = info.getTransferable();
java.util.List<File> data;
try {
data = (java.util.List<File>) t.getTransferData(DataFlavor.javaFileListFlavor);
} catch (Exception e) {
JFLog.log(e);
return false;
}
// Perform the actual import.
for(int a=0;a<data.size();a++) {
switch (info.getDropAction()) {
case COPY:
case MOVE:
addFile(data.get(a));
break;
case LINK:
return false; //BUG : not supported : ???
}
}
return true;
}
public int getSourceActions(JComponent c) {
return COPY;
}
protected Transferable createTransferable(JComponent c) {
ArrayList<String> filenames = getFiles(false);
final ArrayList<File> files = new ArrayList<File>();
for (int i = 0; i < filenames.size(); i++) {
String file = filenames.get(i);
if (file.startsWith("*")) {
files.add(new File(JF.getUserPath(), filenames.get(i)));
} else {
files.add(new File(filenames.get(i)));
}
}
return new Transferable() {
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] {DataFlavor.javaFileListFlavor};
}
public boolean isDataFlavorSupported(DataFlavor df) {
return (df == DataFlavor.javaFileListFlavor);
}
public Object getTransferData(DataFlavor df) throws UnsupportedFlavorException, IOException {
return files;
}
};
}
protected void exportDone(JComponent source, Transferable data, int action) {
}
});
}
}