streamme.visuals.Main.java Source code

Java tutorial

Introduction

Here is the source code for streamme.visuals.Main.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package streamme.visuals;

import java.awt.AWTException;
import static java.awt.Frame.ICONIFIED;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowStateListener;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.text.DecimalFormat;
import java.util.Enumeration;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javazoom.jlgui.basicplayer.BasicPlayerEvent;
import streamme.control.Client;
import org.json.JSONObject;
import org.json.JSONArray;
import org.keymaster.common.HotKey;
import org.keymaster.common.HotKeyListener;
import org.keymaster.common.Provider;
import streamme.StreamMe;
import static streamme.StreamMe.OPTIONS;
import streamme.control.Options;
import streamme.control.Server;
import streamme.data.DataNode;
import streamme.data.FileLink;
import streamme.data.PlaylistManager;
import streamme.player.CustomPlayerInterface;
import streamme.player.Player;

/**
 *
 * @author Scop
 */
public class Main extends javax.swing.JFrame implements CustomPlayerInterface {
    public static int MAX_SLIDER_VAL = 1000000;
    private Client client;
    DefaultTreeModel tree_model;
    private Player player;

    private boolean sliderDragging = false;
    private KeyListener renamePlaylistKeyListener;

    private JPopupMenu treeMenu;

    private SystemTray tray;
    private TrayIcon trayIcon;
    private Provider hotkeyProvider;

    /**
     * Creates new form Main
     */
    public Main() {
        player = Player.getInstance();
        player.setListener(this);

        setIconImage(
                Toolkit.getDefaultToolkit().getImage(getClass().getClassLoader().getResource("res/icon32.png")));
        loadTray();

        hotkeyProvider = Provider.getCurrentProvider(false);
        hotkeyProvider.register(KeyStroke.getKeyStroke("alt UP"), new HotKeyListener() {
            public void onHotKey(HotKey hotKey) {
                btn_playPauseActionPerformed(null);
            }
        });
        hotkeyProvider.register(KeyStroke.getKeyStroke("alt RIGHT"), new HotKeyListener() {
            public void onHotKey(HotKey hotKey) {
                btn_nextActionPerformed(null);
            }
        });
        hotkeyProvider.register(KeyStroke.getKeyStroke("alt LEFT"), new HotKeyListener() {
            public void onHotKey(HotKey hotKey) {
                btn_prevActionPerformed(null);
            }
        });
        hotkeyProvider.register(KeyStroke.getKeyStroke("alt DOWN"), new HotKeyListener() {
            public void onHotKey(HotKey hotKey) {
                btn_stopActionPerformed(null);
            }
        });

        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Windows".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }

        initComponents();
        //getContentPane().setBackground(new java.awt.Color(123,161,214));
        PlaylistManager.get().setFrame(this);

        this.setLocationRelativeTo(null);

        treeMenu = new JPopupMenu();

        JMenuItem itemOpenToNew = new JMenuItem("Open to a new playlist");
        itemOpenToNew.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree_files.getLastSelectedPathComponent();
                if (node == null)
                    return;
                DataNode dn = (DataNode) node.getUserObject();
                int idx = PlaylistManager.get().addPlaylist(dn.getName());
                addToPlaylist(node, idx, true);
            }
        });

        JMenuItem itemAdd = new JMenuItem("Add to selected playlist...");
        itemAdd.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree_files.getLastSelectedPathComponent();
                if (node == null)
                    return;
                addToPlaylist(node, playlistsPanel.getSelectedIndex(), true);
            }
        });

        treeMenu.add(itemOpenToNew);
        treeMenu.add(itemAdd);
        //tree_files.setComponentPopupMenu(menu);

        renamePlaylistKeyListener = new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {
            }

            @Override
            public void keyPressed(KeyEvent e) {
            }

            @Override
            public void keyReleased(KeyEvent e) {
                if (e.getKeyCode() == 113) { // F2
                    int idx = playlistsPanel.getSelectedIndex();
                    if (idx < 0)
                        return;
                    String oldTitle = playlistsPanel.getTitleAt(idx);
                    String s = (String) JOptionPane.showInputDialog(Main.this, "Rename playlist:",
                            "Rename playlist", JOptionPane.PLAIN_MESSAGE, null, null, oldTitle);
                    if (s != null) {
                        PlaylistManager.get().renameTab(idx, s);
                    }
                }
            }
        };

        playlistsPanel.addKeyListener(renamePlaylistKeyListener);
    }

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

        jSplitPane1 = new javax.swing.JSplitPane();
        treePanel = new javax.swing.JScrollPane();
        tree_files = new javax.swing.JTree();
        playlistsPanel = new PlaylistPane();
        controlsPanel = new javax.swing.JPanel();
        btn_prev = new javax.swing.JButton();
        btn_playPause = new javax.swing.JButton();
        btn_stop = new javax.swing.JButton();
        btn_next = new javax.swing.JButton();
        slider = new javax.swing.JSlider();
        message = new javax.swing.JLabel();
        download_progress = new javax.swing.JLabel();
        btn_shuffle = new javax.swing.JToggleButton();
        menubar = new javax.swing.JMenuBar();
        meFile = new javax.swing.JMenu();
        meExit = new javax.swing.JMenuItem();
        meServer = new javax.swing.JMenu();
        meServerStart = new javax.swing.JMenuItem();
        meServerStop = new javax.swing.JMenuItem();
        meClient = new javax.swing.JMenu();
        meConnect = new javax.swing.JMenuItem();
        meConnectTo = new javax.swing.JMenuItem();
        meSettings = new javax.swing.JMenu();
        meConfigIni = new javax.swing.JMenuItem();
        meConfigReload = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("StreamMe");
        setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));

        jSplitPane1.setResizeWeight(0.5);

        treePanel.setBorder(null);

        javax.swing.tree.DefaultMutableTreeNode treeNode1 = new javax.swing.tree.DefaultMutableTreeNode("root");
        tree_files.setModel(new javax.swing.tree.DefaultTreeModel(treeNode1));
        tree_files.setRootVisible(false);
        tree_files.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                tree_filesMousePressed(evt);
            }
        });
        treePanel.setViewportView(tree_files);

        jSplitPane1.setLeftComponent(treePanel);

        playlistsPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, -1, -3, -3));
        playlistsPanel.setMinimumSize(new java.awt.Dimension(23, 23));
        playlistsPanel.setOpaque(true);
        jSplitPane1.setRightComponent(playlistsPanel);

        controlsPanel.setOpaque(false);
        controlsPanel.setPreferredSize(new java.awt.Dimension(232, 30));

        btn_prev.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/controls/16/prev.png"))); // NOI18N
        btn_prev.setContentAreaFilled(false);
        btn_prev.setFocusable(false);
        btn_prev.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btn_prevActionPerformed(evt);
            }
        });

        btn_playPause.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/controls/24/play.png"))); // NOI18N
        btn_playPause.setContentAreaFilled(false);
        btn_playPause.setFocusable(false);
        btn_playPause.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btn_playPauseActionPerformed(evt);
            }
        });

        btn_stop.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/controls/16/stop.png"))); // NOI18N
        btn_stop.setContentAreaFilled(false);
        btn_stop.setFocusable(false);
        btn_stop.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btn_stopActionPerformed(evt);
            }
        });

        btn_next.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/controls/16/next.png"))); // NOI18N
        btn_next.setContentAreaFilled(false);
        btn_next.setFocusable(false);
        btn_next.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btn_nextActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout controlsPanelLayout = new javax.swing.GroupLayout(controlsPanel);
        controlsPanel.setLayout(controlsPanelLayout);
        controlsPanelLayout.setHorizontalGroup(controlsPanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 235, Short.MAX_VALUE)
                .addGroup(controlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(controlsPanelLayout.createSequentialGroup().addGap(7, 7, 7)
                                .addComponent(btn_prev, javax.swing.GroupLayout.PREFERRED_SIZE, 50,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(btn_playPause, javax.swing.GroupLayout.PREFERRED_SIZE, 50,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(btn_stop, javax.swing.GroupLayout.PREFERRED_SIZE, 50,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(btn_next, javax.swing.GroupLayout.PREFERRED_SIZE, 50,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))));
        controlsPanelLayout.setVerticalGroup(controlsPanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 52, Short.MAX_VALUE)
                .addGroup(controlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(controlsPanelLayout.createSequentialGroup().addContainerGap()
                                .addGroup(controlsPanelLayout
                                        .createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                        .addComponent(btn_prev, javax.swing.GroupLayout.PREFERRED_SIZE, 30,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addComponent(btn_playPause, javax.swing.GroupLayout.PREFERRED_SIZE, 30,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addComponent(btn_stop, javax.swing.GroupLayout.PREFERRED_SIZE, 30,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addComponent(btn_next, javax.swing.GroupLayout.PREFERRED_SIZE, 30,
                                                javax.swing.GroupLayout.PREFERRED_SIZE))
                                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))));

        slider.setMaximum(MAX_SLIDER_VAL);
        slider.setPaintLabels(true);
        slider.setValue(0);
        slider.setEnabled(false);
        slider.setOpaque(false);
        slider.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                sliderMousePressed(evt);
            }

            public void mouseReleased(java.awt.event.MouseEvent evt) {
                sliderMouseReleased(evt);
            }
        });

        message.setText("Not connected");

        btn_shuffle.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/controls/24/random.png"))); // NOI18N
        btn_shuffle.setFocusable(false);
        btn_shuffle.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btn_shuffleActionPerformed(evt);
            }
        });

        menubar.setBorder(null);

        meFile.setText("File");

        meExit.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Q,
                java.awt.event.InputEvent.CTRL_MASK));
        meExit.setText("Exit");
        meExit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                meExitActionPerformed(evt);
            }
        });
        meFile.add(meExit);

        menubar.add(meFile);

        meServer.setText("Server");

        meServerStart.setText("Start server");
        meServerStart.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                meServerStartActionPerformed(evt);
            }
        });
        meServer.add(meServerStart);

        meServerStop.setText("Stop server");
        meServerStop.setEnabled(false);
        meServerStop.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                meServerStopActionPerformed(evt);
            }
        });
        meServer.add(meServerStop);

        menubar.add(meServer);

        meClient.setText("Client");

        meConnect.setText("Connect");
        meConnect.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                meConnectActionPerformed(evt);
            }
        });
        meClient.add(meConnect);

        meConnectTo.setText("Connect to...");
        meConnectTo.setEnabled(false);
        meClient.add(meConnectTo);

        menubar.add(meClient);

        meSettings.setText("Settings");

        meConfigIni.setText("Open config.ini...");
        meConfigIni.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                meConfigIniActionPerformed(evt);
            }
        });
        meSettings.add(meConfigIni);

        meConfigReload.setText("Reload config");
        meConfigReload.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                meConfigReloadActionPerformed(evt);
            }
        });
        meSettings.add(meConfigReload);

        menubar.add(meSettings);

        setJMenuBar(menubar);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup().addContainerGap().addGroup(layout
                        .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addComponent(slider, javax.swing.GroupLayout.DEFAULT_SIZE, 801, Short.MAX_VALUE)
                        .addComponent(jSplitPane1)
                        .addGroup(layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                        .addGroup(layout.createSequentialGroup()
                                                .addComponent(message, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED,
                                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                                        .addGroup(layout.createSequentialGroup().addComponent(download_progress)
                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED,
                                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                                .addComponent(btn_shuffle)))
                        .addContainerGap())
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
                        javax.swing.GroupLayout.Alignment.TRAILING,
                        layout.createSequentialGroup().addContainerGap(293, Short.MAX_VALUE)
                                .addComponent(controlsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 235,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addContainerGap(293, Short.MAX_VALUE))));
        layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
                javax.swing.GroupLayout.Alignment.TRAILING,
                layout.createSequentialGroup().addContainerGap()
                        .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 363, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(slider, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addGroup(layout.createSequentialGroup()
                                        .addComponent(download_progress, javax.swing.GroupLayout.PREFERRED_SIZE, 14,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addComponent(message, javax.swing.GroupLayout.PREFERRED_SIZE, 14,
                                                javax.swing.GroupLayout.PREFERRED_SIZE))
                                .addComponent(btn_shuffle))
                        .addGap(10, 10, 10))
                .addGroup(
                        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING,
                                        layout.createSequentialGroup().addContainerGap(401, Short.MAX_VALUE)
                                                .addComponent(controlsPanel, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                        52, javax.swing.GroupLayout.PREFERRED_SIZE)
                                                .addGap(3, 3, 3))));

        pack();
    }// </editor-fold>//GEN-END:initComponents

    @Override
    public void setVisible(boolean b) {
        super.setVisible(b);
    }

    public void stopProcesses() {
        try {
            if (client != null) {
                client.stopClient();
            }
            player.stop();
            Server.get().disable();
        } catch (IOException ex) {
            System.err.println("Couldn't close everything...");
        }
    }

    private boolean askedFiles = false;

    private void tree_filesMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tree_filesMousePressed
        PlaylistManager.get().clearSelection();
        switch (evt.getButton()) {
        case java.awt.event.MouseEvent.BUTTON1: // Left click
            if (evt.getClickCount() == 2) {
                playNodes();
            }
            break;
        case java.awt.event.MouseEvent.BUTTON3: // Right click
            TreePath pathForLocation = tree_files.getPathForLocation(evt.getX(), evt.getY());
            tree_files.setSelectionPath(pathForLocation);
            treeMenu.show(tree_files, evt.getX(), evt.getY());
            break;
        }
    }//GEN-LAST:event_tree_filesMousePressed

    public void askTree() {
        if (client == null) {
            this.setMessage("Connect first...");
            return;
        }
        this.setMessage("Asking path...");
        askedFiles = true;

        new Thread() {
            @Override
            public void run() {
                JSONArray json = client.askJSON();
                tree_model = (DefaultTreeModel) tree_files.getModel();
                //DefaultMutableTreeNode allNode = (DefaultMutableTreeNode) new DefaultMutableTreeNode("Folders");
                //tree_model.setRoot(allNode);
                DefaultMutableTreeNode allNode = (DefaultMutableTreeNode) tree_model.getRoot();
                allNode.removeAllChildren();
                tree_model.reload();

                for (Object obj : json) {
                    JSONObject jsonObj = (JSONObject) obj;
                    fillTree(jsonObj, allNode);
                }

                DefaultMutableTreeNode currentNode = allNode;
                while (currentNode != null) {
                    if (currentNode.getLevel() == 0)
                        tree_files.expandPath(new javax.swing.tree.TreePath(currentNode.getPath()));
                    currentNode = currentNode.getNextNode();
                }
                setMessage("Path loaded");
            }
        }.start();
    }

    private void btn_playPauseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btn_playPauseActionPerformed
        if (player.isPlaying()) {
            player.pause();
            btn_playPause.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/controls/24/play.png")));
        } else if (player.isPaused()) {
            player.resume();
            btn_playPause.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/controls/24/pause.png")));
        } else {
            PlaylistManager.get().playSelected();
        }
    }//GEN-LAST:event_btn_playPauseActionPerformed

    private void btn_stopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btn_stopActionPerformed
        stopPlayer();
    }//GEN-LAST:event_btn_stopActionPerformed

    private void sliderMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_sliderMouseReleased
        player.setTime(slider.getValue(), MAX_SLIDER_VAL);
        this.sliderDragging = false;
    }//GEN-LAST:event_sliderMouseReleased

    private void sliderMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_sliderMousePressed
        this.sliderDragging = true;
    }//GEN-LAST:event_sliderMousePressed

    private void btn_nextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btn_nextActionPerformed
        nextSong();
        if (player.isPlaying() || player.isOnHold()) {
            playSong();
        }
    }//GEN-LAST:event_btn_nextActionPerformed

    private void btn_prevActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btn_prevActionPerformed
        prevSong();
        if (player.isPlaying()) {
            playSong();
        }
    }//GEN-LAST:event_btn_prevActionPerformed

    private void meExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_meExitActionPerformed
        //System.exit(0);
        dispose();
    }//GEN-LAST:event_meExitActionPerformed

    private void meServerStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_meServerStartActionPerformed
        try {
            Server.get().enable();
            message.setText(OPTIONS.getPort() + ": Server is up");
            meServerStop.setEnabled(true);
            meServerStart.setEnabled(false);
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(this, "Couldn't run server on port: " + OPTIONS.getPort(),
                    "Couldn't run server", JOptionPane.WARNING_MESSAGE);
            System.err.println("Couldn't start listener...");
        }
    }//GEN-LAST:event_meServerStartActionPerformed

    private void meServerStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_meServerStopActionPerformed
        try {
            Server.get().disable();
            meServerStart.setEnabled(true);
            meServerStop.setEnabled(false);
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(this, "Couldn't stop server on port: " + OPTIONS.getPort(),
                    "Couldn't stop server", JOptionPane.WARNING_MESSAGE);
            System.err.println("Couldn't stop listener...");
        }
    }//GEN-LAST:event_meServerStopActionPerformed

    private void meConnectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_meConnectActionPerformed
        try {
            this.client = new Client(OPTIONS.getIp(), OPTIONS.getPort());
            player.setClient(client);
            message.setText("Connected");
            askTree();
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(this,
                    "Couldn't connect to client:\n" + OPTIONS.getIp() + " : " + OPTIONS.getPort(),
                    "Cannot connect...", JOptionPane.WARNING_MESSAGE);
            System.err.println("Couldn't connect...");
        }
    }//GEN-LAST:event_meConnectActionPerformed

    private void meConfigIniActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_meConfigIniActionPerformed
        try {
            File configFile = new File(Options.NAMEFILE);
            if (!configFile.exists()) {
                try {
                    String jarDir = Options.class.getProtectionDomain().getCodeSource().getLocation().toURI()
                            .getPath();
                    jarDir = jarDir.substring(0, jarDir.lastIndexOf("/"));
                    configFile = new File(jarDir + "/" + Options.NAMEFILE);
                } catch (URISyntaxException ex) {
                }
            }
            if (configFile.exists()) {
                java.awt.Desktop.getDesktop().open(configFile);
            }
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }//GEN-LAST:event_meConfigIniActionPerformed

    private void btn_shuffleActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btn_shuffleActionPerformed
        OPTIONS.setRandomPlay(btn_shuffle.isSelected());
    }//GEN-LAST:event_btn_shuffleActionPerformed

    private void meConfigReloadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_meConfigReloadActionPerformed
        OPTIONS.load();
    }//GEN-LAST:event_meConfigReloadActionPerformed

    public void setMessage(String str) {
        new Thread() {
            @Override
            public void run() {
                message.setText(str);
            }
        }.start();
    }

    private void stopPlayer() {
        slider.setEnabled(false);
        player.stop();
        slider.setValue(0);
        message.setText("Stopped");
        download_progress.setText("");
        btn_playPause.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/controls/24/play.png")));
    }

    public void playNodes() {
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree_files.getLastSelectedPathComponent();
        if (node != null && node.isLeaf()) {
            DataNode dn = (DataNode) node.getUserObject();
            if (!dn.isFolder()) {
                PlaylistManager pm = PlaylistManager.get();
                DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent();
                pm.clearPlaylist(-1);

                // Get Path:
                javax.swing.tree.TreeNode[] tree = parent.getPath();
                String path = StreamMe.OPTIONS.getOutputPath();
                for (int i = 1; i < tree.length; i++) {
                    path += "\\" + ((DataNode) ((DefaultMutableTreeNode) tree[i]).getUserObject()).getName();
                }

                Enumeration ch = parent.children();
                DefaultMutableTreeNode child = null;
                while (ch.hasMoreElements()) {
                    child = (DefaultMutableTreeNode) ch.nextElement();
                    if (child.isLeaf())
                        break;
                }
                int songIdx = 0, i = 0;
                while (child != null) {
                    DataNode childnode = (DataNode) child.getUserObject();

                    if (child == node) {
                        songIdx = i;
                    }
                    pm.addToPlaylist(-1, childnode.toFileLink(path + "\\" + childnode.getName()));
                    child = child.getNextSibling();
                    i++;
                }
                playSong(pm.getDefaultModelIdx(), songIdx);
            }
        }
    }

    public void addToPlaylist(DefaultMutableTreeNode node, int listIdx, boolean recursive) {
        DefaultMutableTreeNode leaf = node.getFirstLeaf();
        while (node.isNodeDescendant(leaf)) {
            DataNode dn = (DataNode) leaf.getUserObject();
            javax.swing.tree.TreeNode[] tree = leaf.getPath();
            String path = StreamMe.OPTIONS.getOutputPath();
            for (int i = 1; i < tree.length; i++) {
                path += "\\" + ((DataNode) ((DefaultMutableTreeNode) tree[i]).getUserObject()).getName();
            }
            PlaylistManager.get().addToPlaylist(listIdx, dn.toFileLink(path));
            leaf = leaf.getNextLeaf();
        }
    }

    public void playSong(int tabIdx, int songIdx) {
        PlaylistManager.get().selectSong(tabIdx, songIdx);
        playSong();
    }

    private void playSong() {
        FileLink fr = PlaylistManager.get().getSong();
        if (!player.isPlaying(fr)) {
            stopPlayer();
        }
        player.play(fr);
        btn_playPause.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/controls/24/pause.png")));
    }

    private void nextSong() {
        PlaylistManager.get().getNextSong();
        PlaylistManager.get().refreshPlaylist(-1);
        PlaylistManager.get().clearSelection();
    }

    private void prevSong() {
        PlaylistManager.get().getPrevSong();
        PlaylistManager.get().refreshPlaylist(-1);
        PlaylistManager.get().clearSelection();
    }

    private void fillTree(JSONObject json, DefaultMutableTreeNode parent) {
        DataNode folderDN = new DataNode(json.getInt("id"), json.getString("name"), true);
        DefaultMutableTreeNode folder = new DefaultMutableTreeNode(folderDN);

        for (Object obj : json.getJSONArray("folders")) {
            JSONObject jsonObj = (JSONObject) obj;
            fillTree(jsonObj, folder);
        }

        for (Object obj : json.getJSONArray("files")) {
            JSONObject jsonObj = (JSONObject) obj;
            DataNode fileDN = new DataNode(jsonObj.getInt("id"), jsonObj.getString("name"), false);
            DefaultMutableTreeNode file = new DefaultMutableTreeNode(fileDN);
            tree_model.insertNodeInto(file, folder, folder.getChildCount());
        }
        tree_model.insertNodeInto(folder, parent, parent.getChildCount());
    }

    public KeyListener getRenamePlaylistKeyListener() {
        return renamePlaylistKeyListener;
    }

    public void loadTray() {
        if (SystemTray.isSupported()) {
            tray = SystemTray.getSystemTray();

            PopupMenu popup = new PopupMenu();
            MenuItem exitItem = new MenuItem("Exit");
            exitItem.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    dispose();
                }
            });

            MenuItem openItem = new MenuItem("Open");
            openItem.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    minimizeToTray(false);
                }
            });

            popup.add(openItem);
            popup.add(exitItem);
            trayIcon = new TrayIcon(
                    Toolkit.getDefaultToolkit().getImage(getClass().getClassLoader().getResource("res/icon16.png")),
                    "StreamMe", popup);
            trayIcon.setImageAutoSize(true);
            trayIcon.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent evt) {
                    if (evt.getClickCount() == 2) {
                        //minimizeToTray(false);
                        return;
                    }
                    if (evt.getButton() == 1) {
                        minimizeToTray(!isMinimizedToTray());
                    }
                }
            });

            addWindowStateListener(new WindowStateListener() {
                public void windowStateChanged(WindowEvent e) {
                    if (e.getNewState() == ICONIFIED || e.getNewState() == 7) {
                        minimizeToTray(true);
                    }
                }
            });

            addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    minimizeToTray(true);
                }
            });
            try {
                tray.add(trayIcon);
            } catch (AWTException ex) {
                System.out.println("Error adding icon to tray");
            }
        }
    }

    public void minimizeToTray(boolean minimize) {
        if (minimize) {
            setVisible(false);
        } else {
            setVisible(true);
            setExtendedState(javax.swing.JFrame.NORMAL);
        }
    }

    public boolean isMinimizedToTray() {
        return !this.isVisible();
    }

    @Override
    public void dispose() {
        hotkeyProvider.reset();
        hotkeyProvider.stop();
        stopProcesses();
        player.close();
        super.dispose();
        tray.remove(trayIcon);
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btn_next;
    private javax.swing.JButton btn_playPause;
    private javax.swing.JButton btn_prev;
    private javax.swing.JToggleButton btn_shuffle;
    private javax.swing.JButton btn_stop;
    private javax.swing.JPanel controlsPanel;
    private javax.swing.JLabel download_progress;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JMenu meClient;
    private javax.swing.JMenuItem meConfigIni;
    private javax.swing.JMenuItem meConfigReload;
    private javax.swing.JMenuItem meConnect;
    private javax.swing.JMenuItem meConnectTo;
    private javax.swing.JMenuItem meExit;
    private javax.swing.JMenu meFile;
    private javax.swing.JMenu meServer;
    private javax.swing.JMenuItem meServerStart;
    private javax.swing.JMenuItem meServerStop;
    private javax.swing.JMenu meSettings;
    private javax.swing.JMenuBar menubar;
    private javax.swing.JLabel message;
    private javax.swing.JTabbedPane playlistsPanel;
    private javax.swing.JSlider slider;
    private javax.swing.JScrollPane treePanel;
    private javax.swing.JTree tree_files;
    // End of variables declaration//GEN-END:variables

    @Override
    public void onStateUpdated(BasicPlayerEvent bpe) {
        switch (bpe.getCode()) {
        case BasicPlayerEvent.PLAYING:
            this.slider.setEnabled(true);
            break;
        case BasicPlayerEvent.STOPPED:
            this.slider.setEnabled(false);
            if (!player.isFullDownloaded()) {
                player.delayedResume(slider);
            } else {
                nextSong();
                playSong();
            }
            break;
        //case BasicPlayerEvent.UNKNOWN:
        //case BasicPlayerEvent.OPENING:
        //case BasicPlayerEvent.OPENED:
        //case BasicPlayerEvent.PAUSED:
        //case BasicPlayerEvent.RESUMED:
        //case BasicPlayerEvent.SEEKING:
        //case BasicPlayerEvent.SEEKED:
        //case BasicPlayerEvent.EOM:
        //case BasicPlayerEvent.PAN:
        //case BasicPlayerEvent.GAIN:
        default:
            break;
        }
    }

    @Override
    public void onProgress(int i, long l, byte[] bytes, Map map) {
        if (sliderDragging)
            return;

        int lp = (int) (l / 1000);
        int n = (int) ((lp / (player.getAudioDurationSeconds() * 1000)) * MAX_SLIDER_VAL);
        slider.setValue(player.getLastSeek() + n);

        //int t = (int) (l/player.getAudioDurationSeconds());
        //slider.setValue(player.getLastSeek() + t);
    }

    private int totalParts = 1;

    @Override
    public void onDownloadStart(int initPart, int totalParts) {
        DecimalFormat df = new DecimalFormat("0.00");
        df.setMaximumFractionDigits(2);

        this.totalParts = totalParts;
        float mb = initPart * Options.FRAGMENT_SIZE / 1048576.f;
        if (totalParts < 0) {
            this.download_progress.setText(df.format(mb) + " MB");
        } else {
            float tmb = totalParts * Options.FRAGMENT_SIZE / 1048576.f;
            this.download_progress.setText(
                    df.format(mb) + " MB/" + df.format(tmb) + " MB (" + initPart * 100 / totalParts + "%)");
        }

        this.message.setText("Downloading...");
    }

    @Override
    public void onDownloadPart(int part) {
        DecimalFormat df = new DecimalFormat("0.00");
        df.setMaximumFractionDigits(2);

        float mb = part * Options.FRAGMENT_SIZE / 1048576.f;
        if (totalParts < 0) {
            this.download_progress.setText(df.format(mb) + " MB");
        } else {
            float tmb = totalParts * Options.FRAGMENT_SIZE / 1048576.f;
            this.download_progress
                    .setText(df.format(mb) + " MB/" + df.format(tmb) + " MB (" + part * 100 / totalParts + "%)");
        }
    }

    @Override
    public void onDownloadCompleted() {
        //this.download_progress.setText("");
        this.message.setText("Download completed");
    }

    public PlaylistPane getPlaylistsPane() {
        return (PlaylistPane) this.playlistsPanel;
    }

    public JTree getTreePanel() {
        return this.tree_files;
    }
}