package de.zigapeda.flowspring.gui; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.LinkedList; import javax.imageio.ImageIO; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import org.hsqldb.types.Types; import de.zigapeda.flowspring.Main; import de.zigapeda.flowspring.controller.Compare; import de.zigapeda.flowspring.controller.Rename; import de.zigapeda.flowspring.controller.Settings; import de.zigapeda.flowspring.controller.Tagreader; import de.zigapeda.flowspring.data.DataNode; import de.zigapeda.flowspring.data.ReadTableModel; import de.zigapeda.flowspring.data.Title; public class ReadWindow extends JFrame implements WindowListener, ActionListener { private static final long serialVersionUID = 3800673403668208662L; private JTextField directorytextfield; private JButton directorybrowse; private JButton directorystart; private ReadTableModel readtablemodel; private JTable readtable; private FileWalker fw; private JLabel description; private JButton readfiles; private JButton copyfiles; private JButton movefiles; private String path; private JCheckBox avoiddoubles; public ReadWindow() { super("flowspring - Add files to library"); BufferedImage image; try { image = ImageIO.read(Main.class.getClass().getResource("/de/zigapeda/flowspring/res/icon.png")); this.setIconImage(image); } catch (IOException e) { e.printStackTrace(); } this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); GridBagConstraints c = new GridBagConstraints(); this.setLayout(new GridBagLayout()); JPanel directorylayout = new JPanel(); directorylayout.setLayout(new GridBagLayout()); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.fill = GridBagConstraints.HORIZONTAL; String path = Settings.loadSettings("readwindow.path"); if(path == null) { path = Settings.loadSettings("defaultdir"); } else if(path.length() == 0) { path = Settings.loadSettings("defaultdir"); } directorytextfield = new JTextField(path); directorylayout.add(directorytextfield,c); c.weightx = 0; c.gridx = 1; c.fill = GridBagConstraints.NONE; directorybrowse = new JButton("Browse..."); directorybrowse.addActionListener(this); directorylayout.add(directorybrowse,c); c.gridx = 2; directorystart = new JButton("Start"); directorystart.addActionListener(this); directorylayout.add(directorystart,c); c.gridx = 0; c.gridy = 0; c.anchor = GridBagConstraints.WEST; c.weightx = 1; c.fill = GridBagConstraints.HORIZONTAL; this.add(directorylayout,c); c.gridy = 1; c.fill = GridBagConstraints.BOTH; c.weighty = 1; setReadtablemodel(new ReadTableModel()); readtable = new JTable(getReadtablemodel()); ReadtableRenderer rtr = new ReadtableRenderer(this); readtable.getColumnModel().getColumn(0).setCellRenderer(rtr); this.add(new JScrollPane(readtable),c); c.gridy = 2; c.fill = GridBagConstraints.HORIZONTAL; c.weighty = 0; description = new JLabel("<html><body><br></body></html>"); this.add(description,c); JPanel buttonlayout = new JPanel(); c.gridy = 3; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.EAST; this.add(buttonlayout,c); buttonlayout.setLayout(new GridBagLayout()); this.setReadfiles(new JButton("Read files")); this.setCopyfiles(new JButton("Read and copy to music directory")); this.setMovefiles(new JButton("Read and move to music directory")); this.getCopyfiles().setEnabled(Rename.isRenameAvailable()); this.getMovefiles().setEnabled(Rename.isRenameAvailable()); this.avoiddoubles = new JCheckBox("Avoid doubles (takes more time)"); this.getReadfiles().addActionListener(this); this.getCopyfiles().addActionListener(this); this.getMovefiles().addActionListener(this); c.gridx = 0; c.gridy = 0; buttonlayout.add(this.avoiddoubles,c); c.gridx = 1; buttonlayout.add(this.getReadfiles(),c); c.gridx = 2; buttonlayout.add(this.getCopyfiles(),c); c.gridx = 3; buttonlayout.add(this.getMovefiles(),c); this.addWindowListener(this); readtable.getColumnModel().getColumn(0).setPreferredWidth(300); readtable.getTableHeader().setReorderingAllowed(false); String windowbounds = Settings.loadSettings("readwindow.bounds"); if(windowbounds != null) { String[] wba = windowbounds.split(","); this.setBounds(Integer.valueOf(wba[2]), Integer.valueOf(wba[3]), Integer.valueOf(wba[0]), Integer.valueOf(wba[1])); if(Integer.valueOf(wba[4]) != JFrame.ICONIFIED) { this.setExtendedState(Integer.valueOf(wba[4])); } } else { Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize(); this.setBounds(screensize.width/2 - 400, screensize.height/2 - 300, 800, 600); } this.setMinimumSize(new Dimension(800, 600)); this.setVisible(true); } private String getPositionString() { String temp = new String(); int ext = this.getExtendedState(); this.setExtendedState(0); temp = temp + String.valueOf(this.getWidth()) + ","; temp = temp + String.valueOf(this.getHeight()) + ","; temp = temp + String.valueOf(this.getX()) + ","; temp = temp + String.valueOf(this.getY()) + ","; temp = temp + String.valueOf(ext); return temp; } public String getPath() { return this.path; } public void windowOpened(WindowEvent e) { } public void windowClosing(WindowEvent evt) { Settings.saveSettings("readwindow.bounds", this.getPositionString()); } public void windowClosed(WindowEvent e) { Main.setReadWindow(null); } public void windowIconified(WindowEvent e) { } public void windowDeiconified(WindowEvent e) { } public void windowActivated(WindowEvent e) { } public void windowDeactivated(WindowEvent e) { } public void actionPerformed(ActionEvent evt) { if(evt.getSource() == this.directorybrowse) { File file = new File(this.directorytextfield.getText()); if(file.exists()) { if(file.isDirectory()) { JFileChooser fc = new JFileChooser(file); fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int returnVal = fc.showOpenDialog(this.directorybrowse); if (returnVal == JFileChooser.APPROVE_OPTION) { this.directorytextfield.setText(fc.getSelectedFile().getAbsolutePath()); } } else { JFileChooser fc = new JFileChooser(); fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int returnVal = fc.showOpenDialog(this.directorybrowse); if (returnVal == JFileChooser.APPROVE_OPTION) { this.directorytextfield.setText(fc.getSelectedFile().getAbsolutePath()); } } } else { JFileChooser fc = new JFileChooser(); fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int returnVal = fc.showOpenDialog(this.directorybrowse); if (returnVal == JFileChooser.APPROVE_OPTION) { this.directorytextfield.setText(fc.getSelectedFile().getAbsolutePath()); } } } else if(evt.getSource() == this.directorystart) { if(fw != null) { fw.requestStop(); fw = null; this.directorystart.setText("Start"); } else { if(this.getReadtablemodel().getRowCount() > 0) { this.getReadtablemodel().removeAllRows(); } File tmp = new File(this.directorytextfield.getText()); if(tmp.exists()) { if(tmp.isDirectory()) { this.path = tmp.getAbsolutePath(); Settings.saveSettings("readwindow.path", this.path); fw = new FileWalker(path, this); fw.start(); this.directorystart.setText("Stop"); } } } } else if(evt.getSource() == this.getReadfiles() || evt.getSource() == this.getCopyfiles() || evt.getSource() == this.getMovefiles()) { ReadFiles rf = new ReadFiles((JButton) evt.getSource(),this); rf.start(); } } public ReadTableModel getTableModel() { return this.getReadtablemodel(); } public JTable getTable() { return this.readtable; } public void setStartbuttonText(String text) { this.directorystart.setText(text); } public void setReadtext(int counter, int size) { this.description.setText("<html><body>" + String.valueOf(counter) + " from " + String.valueOf(size) + " titles added to library yet</body></html>"); } public void setSearchtext(int counter) { this.description.setText("<html><body>" + String.valueOf(counter) + " titles found until now!</body></html>"); } public void setFinishtext(int counter) { this.description.setText("<html><body>" + String.valueOf(counter) + " titles found at this location!</body></html>"); } public ReadTableModel getReadtablemodel() { return readtablemodel; } public void setReadtablemodel(ReadTableModel readtablemodel) { this.readtablemodel = readtablemodel; } public JButton getReadfiles() { return readfiles; } public void setReadfiles(JButton readfiles) { this.readfiles = readfiles; } public JButton getCopyfiles() { return copyfiles; } public void setCopyfiles(JButton copyfiles) { this.copyfiles = copyfiles; } public JButton getMovefiles() { return movefiles; } public void setMovefiles(JButton movefiles) { this.movefiles = movefiles; } public boolean isAvoidDoubles() { return this.avoiddoubles.isSelected(); } } class ReadFiles extends Thread { private JButton button; private ReadWindow parent; private Connection c; public ReadFiles(JButton button, ReadWindow parent) { this.button = button; this.parent = parent; } public void run() { if(this.parent.getReadtablemodel().getRowCount() > 0) { this.c = Main.getDatabase(); LinkedList<Title> list = this.parent.getReadtablemodel().getData(); for(int i = 0; i < list.size(); i++) { Title t = list.get(i); if(this.button == this.parent.getReadfiles()) { insertTitle(t); } else if (this.button == this.parent.getCopyfiles()) { String path = Rename.createPath(t); if(Rename.isFile(path) == false) { int id = insertTitle(t); if(id > -1) { try { File newfile = new File(path); newfile.getParentFile().mkdirs(); Files.copy(new File(t.getPath()).toPath(), newfile.toPath()); Title.changePath(id, path); } catch(IOException e) { e.printStackTrace(); } } } } else if (this.button == this.parent.getMovefiles()) { String path = Rename.createPath(t); if(Rename.isFile(path) == false) { int id = insertTitle(t); if(id > -1) { try { File newfile = new File(path); newfile.getParentFile().mkdirs(); Files.move(new File(t.getPath()).toPath(), newfile.toPath()); Title.changePath(id, path); } catch(IOException e) { e.printStackTrace(); } } } } this.parent.setReadtext(i + 1, list.size()); } DataNode.refreshMedialib(Main.getWindow().getControlllayout().getTypeOrder().getFirst()); Main.getWindow().refreshMedialib(); } } private int insertTitle(Title t) { int[] status = this.insertTitleIntoDB(t.getArtist(), t.getAlbum(), t.getName(), t.getComment(), t.getGenre(), t.getTrack(), t.getYear(), t.getInt(), t.getRating(), t.getPlaycount(), t.getPath()); if((status[0] & 32) == 32) { if((status[0] & 64) == 0) { if(this.parent.isAvoidDoubles() == true) { String pathstring = Title.getTitlePathById(status[1]); if(pathstring != null) { File titleindb = new File(pathstring); if(titleindb.exists()) { if(Compare.getMD5(titleindb).equals(Compare.getMD5(new File(t.getPath()))) == false) { String newname; do { int nextval = this.getNextUnique(); if(nextval > -1) { newname = t.getName() + "_" + String.valueOf(nextval); } else { return -1; } status = this.insertTitleIntoDB(t.getArtist(), t.getAlbum(), newname, t.getComment(), t.getGenre(), t.getTrack(), t.getYear(), t.getInt(), t.getRating(), t.getPlaycount(), t.getPath()); } while((status[0] & 32) == 0); } } } } else { String newname; do { int nextval = this.getNextUnique(); if(nextval > -1) { newname = t.getName() + "_" + String.valueOf(nextval); } else { return -1; } status = this.insertTitleIntoDB(t.getArtist(), t.getAlbum(), newname, t.getComment(), t.getGenre(), t.getTrack(), t.getYear(), t.getInt(), t.getRating(), t.getPlaycount(), t.getPath()); } while((status[0] & 32) == 0); } } } return status[1]; } /** * Try to insert the Title into the database by checking Interpret, Album, Genre and Comment * if they exists and create them if not. * * @return an array with two integers, first one is the status, second one is the new titleid * status is a binary switch with values * <ul> * <li>1 = new Interpret</li> * <li>2 = new Album</li> * <li>4 = new Genre</li> * <li>8 = new Comment</li> * <li>16 = new Title</li> * <li>32 = Title not inserted</li> * <li>64 = Path exists</li> * </ul> */ private int[] insertTitleIntoDB(String interpret, String album, String name, String comment, String genre, String track, String year, Integer duration, String rating, String playcount, String path) { int ret = 0; int id = 0; try { CallableStatement s = c.prepareCall("call inserttitle(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"); this.setParameters(s, interpret, Compare.getComparableString(interpret), album, Compare.getComparableString(album), name, Compare.getComparableString(name), comment, Compare.getMD5(comment), genre, Compare.getComparableString(genre), getInt(track), getInt(year), duration, getIntNN(rating), getIntNN(playcount), path); s.registerOutParameter(17, Types.INTEGER); s.registerOutParameter(18, Types.INTEGER); s.execute(); ret = s.getInt(17); id = s.getInt(18); s.close(); } catch (SQLException e) { e.printStackTrace(); } return new int[] {ret, id}; } private int getNextUnique() { Statement s; try { s = c.createStatement(); ResultSet r = s.executeQuery("select next value for unq_gen from dual"); if(r.next()) { return r.getInt(1); } else { return -1; } } catch(SQLException e) { e.printStackTrace(); } return -1; } private Integer getInt(String string) { if(string != null) { try { return Integer.valueOf(string); } catch (NumberFormatException e) { } } return null; } private Integer getIntNN(String string) { if(string != null) { try { return Integer.valueOf(string); } catch (NumberFormatException e) { } } return 0; } private void setParameters(PreparedStatement s, Object...objects) { int i = 1; for(Object o: objects) { try { if(o == null) { s.setNull(i, java.sql.Types.NULL); } else if (o instanceof String) { s.setString(i, (String)o); } else if (o instanceof Integer) { s.setInt(i, (Integer)o); } } catch (SQLException e) { e.printStackTrace(); } i++; } } } class FileWalker extends Thread { private String path; private ReadWindow readwindow; private volatile boolean stop = false; public FileWalker(String path, ReadWindow readwindow) { this.path = path; this.readwindow = readwindow; } public void requestStop() { this.stop = true; } public void run() { try { Files.walkFileTree(Paths.get(this.path), new SimpleFileVisitor<Path>() { public FileVisitResult visitFileFailed(Path file, IOException exc) { return FileVisitResult.CONTINUE; } public FileVisitResult visitFile( Path filepath, BasicFileAttributes attribs ) { Title temp = new Tagreader(filepath).getTitle(); if(temp != null) { FileWalker.this.readwindow.getTableModel().addRow(temp); JTable table = FileWalker.this.readwindow.getTable(); table.scrollRectToVisible(table.getCellRect(table.getRowCount() -1, 0, true)); } if(stop) { return FileVisitResult.TERMINATE; } FileWalker.this.readwindow.setFinishtext(FileWalker.this.readwindow.getTableModel().getRowCount()); return FileVisitResult.CONTINUE; } }); this.readwindow.setStartbuttonText("Start"); } catch (IOException e) { e.printStackTrace(); } } }