Package com.tulskiy.musique.gui.dialogs

Source Code of com.tulskiy.musique.gui.dialogs.FileOperations

/*
* Copyright (c) 2008, 2009, 2010, 2011 Denis Tulskiy
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with this work.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.tulskiy.musique.gui.dialogs;

import com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel;
import com.tulskiy.musique.gui.components.GroupTable;
import com.tulskiy.musique.playlist.Playlist;
import com.tulskiy.musique.playlist.Track;
import com.tulskiy.musique.playlist.formatting.Parser;
import com.tulskiy.musique.playlist.formatting.tokens.Expression;
import com.tulskiy.musique.system.Application;
import com.tulskiy.musique.system.configuration.Configuration;
import com.tulskiy.musique.system.configuration.FileOperationsConfiguration;
import com.tulskiy.musique.util.FileUtils;
import com.tulskiy.musique.util.Util;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel;
import java.util.*;
import java.util.List;

/**
* Author: Denis Tulskiy
* Date: Aug 1, 2010
*/
public class FileOperations extends JDialog {
    private static final ArrayList<String> DEFAULT_PATTERNS = new ArrayList<String>(Arrays.asList(
            "%fileName%", "[%artist% - ]%title%",
            "[%trackNumber% - ]%title%",
            "[%year% - ]%album%/%fileName%")
    );

    private JComboBox namePattern;
    private PathChooser folder;
    private DefaultTableModel previewModel;
    private HashMap<Track, File> paths = new LinkedHashMap<Track, File>();
    private Application app = Application.getInstance();
    private Configuration config = app.getConfiguration();

    public enum Operation {
        Copy,
        Move,
        Rename
    }

    private Operation mode;
    private List<Track> tracks;

    public FileOperations(final JComponent owner, Operation mode, List<Track> tracks) {
        super(SwingUtilities.windowForComponent(owner), "File Operations");
        this.mode = mode;
        this.tracks = tracks;
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        JPanel top = new JPanel(new GridLayout(3, 2, 5, 5));
        top.setBorder(BorderFactory.createTitledBorder("Options"));
        final JComboBox op = new JComboBox(Operation.values());
        top.add(new JLabel("Operation"));
        top.add(op);

        folder = new PathChooser("");
        folder.addPropertyChangeListener("path", new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                updatePreview();
            }
        });
        top.add(new JLabel("Destination"));
        top.add(folder);

        final List<String> patterns = FileOperationsConfiguration.getPatterns(DEFAULT_PATTERNS);
        namePattern = new JComboBox(patterns.toArray());
        namePattern.setEditable(true);
        top.add(new JLabel("File name pattern"));
        top.add(namePattern);

        JPanel main = new JPanel(new BorderLayout());
        main.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        main.add(top, BorderLayout.NORTH);

        GroupTable preview = new GroupTable() {
            public Component prepareRenderer(final TableCellRenderer renderer,
                                             final int row, final int column) {
                final Component prepareRenderer = super
                        .prepareRenderer(renderer, row, column);
                final TableColumn tableColumn = getColumnModel().getColumn(column);

                tableColumn.setPreferredWidth(Math.max(
                        prepareRenderer.getPreferredSize().width,
                        tableColumn.getPreferredWidth()));

                return prepareRenderer;
            }
        };
        previewModel = new DefaultTableModel(new Object[]{"Source", "Destination"}, 10) {
            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };
        preview.setModel(previewModel);
        preview.setFont(preview.getFont().deriveFont(11f));
        preview.setGridColor(Color.lightGray);
        preview.setShowVerticalLines(true);
        preview.setIntercellSpacing(new Dimension(1, 1));

        JScrollPane scroll = new JScrollPane(preview);
        scroll.setBorder(BorderFactory.createTitledBorder("Preview"));
        main.add(scroll, BorderLayout.CENTER);

        op.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                FileOperations.this.mode = (Operation) op.getSelectedItem();
                if (FileOperations.this.mode == Operation.Rename) {
                    folder.setEnabled(false);
                } else {
                    folder.setEnabled(true);
                }

                updatePreview();
            }
        });
        op.setSelectedItem(mode);

        JTextComponent textComp = (JTextComponent) namePattern.getEditor().getEditorComponent();
        textComp.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                updatePreview();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                updatePreview();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                updatePreview();
            }
        });

        namePattern.setSelectedItem(config.getString("fileOperations.selectedPattern", patterns.get(0)));
        folder.setPath(config.getString("fileOperations.path", ""));

        Box buttons = Box.createHorizontalBox();
        buttons.add(Box.createHorizontalGlue());
        JButton ok = new JButton(" Start ");
        buttons.add(ok);
        ok.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                config.setString("fileOperations.path", folder.getPath());
                String selectedItem = (String) namePattern.getSelectedItem();
                config.setString("fileOperations.selectedPattern", selectedItem);
                if (!patterns.contains(selectedItem))
                    patterns.add(selectedItem);
                FileOperationsConfiguration.setPatterns(patterns);
                setVisible(false);
                dispose();

                ProgressDialog progress = new ProgressDialog(owner, "File Operations");
                progress.show(new CopyTask());
            }
        });
        buttons.add(Box.createHorizontalStrut(3));
        JButton cancel = new JButton("Cancel");
        cancel.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                setVisible(false);
                dispose();
            }
        });
        buttons.add(cancel);
        buttons.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        main.add(buttons, BorderLayout.PAGE_END);
        updatePreview();
        setContentPane(main);
        setSize(700, 500);
        setLocationRelativeTo(null);
    }

    public void updatePreview() {
        String text = (String) namePattern.getEditor().getItem();
        previewModel.setRowCount(0);
        paths.clear();
        if (!Util.isEmpty(text)) {
            text = text.replaceAll("%([\\w]+)%", "\\$escape($0)");
            Expression expression = Parser.parse(text);
            for (Track track : tracks) {
                Object key;
                if (track.getTrackData().isFile() && !track.getTrackData().isCue()) {
                    File file = track.getTrackData().getFile();
                    key = file.getName();
                    StringBuilder sb = new StringBuilder();
                    Object o = expression.eval(track);
                    if (o == null)
                        continue;
                    sb.append(o);
                    sb.append(".").append(Util.getFileExt(file));
                    File output = null;
                    if (mode == Operation.Rename) {
                        output = new File(file.getParent(), sb.toString());
                    } else {
                        File path = new File(folder.getPath());
                        if (path.exists() && path.isDirectory())
                            output = new File(folder.getPath(), sb.toString());
                    }

                    if (output != null) {
                        previewModel.addRow(new Object[]{key, output.getAbsolutePath()});
                        paths.put(track, output);
                    }
                }
            }
        }
    }

    class CopyTask extends Task {
        private File src;
        private File dest;
        private long processed;
        private long totalSize;
        private boolean abort = false;

        @Override
        public String getStatus() {
            StringBuilder sb = new StringBuilder();
            switch (mode) {
                case Copy:
                    sb.append("Copying: ");
                    break;
                case Move:
                    sb.append("Moving: ");
                    break;
                case Rename:
                    sb.append("Renaming: ");
            }

            sb.append(src).append("\n");
            sb.append("Destination: ").append(dest);
            return sb.toString();
        }

        @Override
        public void abort() {
            abort = true;
        }

        @SuppressWarnings({"ResultOfMethodCallIgnored"})
        @Override
        public void start() {
            totalSize = 0;
            for (Track track : paths.keySet()) {
                totalSize += track.getTrackData().getFile().length();
            }

            ArrayList<String> log = new ArrayList<String>();
            processed = 0;
            for (Map.Entry<Track, File> entry : paths.entrySet()) {
                if (abort)
                    break;
                src = entry.getKey().getTrackData().getFile();
                dest = entry.getValue();
                dest.getParentFile().mkdirs();

                if (mode == Operation.Rename) {
                    if (!src.renameTo(dest))
                        log.add("Failed to rename " + src + " to " + dest);
                    processed += src.length();
                } else {
                    if (mode == Operation.Move) {
                        //try to rename first

                        if (src.renameTo(dest)) {
                            processed += src.length();
                            entry.getKey().getTrackData().setLocation(dest.toURI().toString());
                            // TODO "delete yes/no" decision to be remembered
                            FileUtils.deleteEmptyParentFolders(src, true);
                            continue;
                        }
                    }

                    //now copy
                    try {
                        if (src.canRead() || dest.canWrite()) {
                            FileChannel from = new FileInputStream(src).getChannel();
                            FileChannel to = new FileOutputStream(dest).getChannel();
                            long transferred = 0;
                            long length = from.size();
                            int chunkSize = 10000000;
                            while (transferred < length) {
                                if (abort)
                                    break;
                                long len = from.transferTo(
                                        transferred, chunkSize, to);
                                transferred += len;
                                processed += len;
                            }
                            from.close();
                            to.close();
                        } else {
                            log.add("Not enough permissions to copy/move " + src + " to " + dest);
                        }
                    } catch (ClosedChannelException ignore) {
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    if (abort) {
                        dest.delete();
                    } else if (mode == Operation.Move) {
                        if (src.delete()) {
                            // TODO "delete yes/no" decision to be remembered
                            FileUtils.deleteEmptyParentFolders(src, true);
                        } else {
                            log.add("Failed to remove " + src);
                        }
                    }


                }

                if ((mode == Operation.Move || mode == Operation.Rename)
                        && dest.exists()) {
                    entry.getKey().getTrackData().setLocation(dest.toURI().toString());
                }
            }
        }

        @Override
        public boolean isIndeterminate() {
            return false;
        }

        @Override
        public float getProgress() {
            return (float) processed / totalSize;
        }
    }

    public static void main(String[] args) {
        Application app = Application.getInstance();
        app.load();
        try {
            UIManager.setLookAndFeel(new NimbusLookAndFeel());
        } catch (UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }
        Playlist pl = new Playlist();
        JLabel label = new JLabel();
        pl.insertItem("/windows/Users/tulskiy/Music/Avril Lavigne", 0, true, null);
        FileOperations dialog = new FileOperations(label, Operation.Rename, pl);
        dialog.setVisible(true);
    }
}

TOP

Related Classes of com.tulskiy.musique.gui.dialogs.FileOperations

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.