/** * 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) { } }); } }