Package me.mabra.hellonzb

Source Code of me.mabra.hellonzb.HelloNzbCradle

/*******************************************************************************
* HelloNzb -- The Binary Usenet Tool
* Copyright (C) 2010-2013 Matthias F. Brandstetter
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/

package me.mabra.hellonzb;

import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

import me.mabra.hellonzb.listener.DownloadFileListKeyListener;
import me.mabra.hellonzb.listener.DownloadFileListPopupListener;
import me.mabra.hellonzb.listener.NzbFileListPopupListener;
import me.mabra.hellonzb.listener.actions.*;
import me.mabra.hellonzb.nntpclient.BackupFileDownloader;
import me.mabra.hellonzb.nntpclient.NntpFileDownloader;
import me.mabra.hellonzb.nntpclient.nioengine.NettyNioClient;
import me.mabra.hellonzb.parser.NzbParser;
import me.mabra.hellonzb.preferences.HelloNzbPreferences;
import me.mabra.hellonzb.renderer.AlignedTableHeaderRenderer;
import me.mabra.hellonzb.renderer.MyTableCellRenderer;
import me.mabra.hellonzb.renderer.ProgressRenderer;
import me.mabra.hellonzb.tablemodels.FilesToDownloadTableModel;
import me.mabra.hellonzb.tablemodels.NzbFileQueueTableModel;
import me.mabra.hellonzb.tablemodels.TableRowTransferHandler;
import me.mabra.hellonzb.tablemodels.ThreadViewTableModel;
import me.mabra.hellonzb.util.*;

import javax.swing.*;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
import javax.swing.table.TableColumn;
import javax.xml.stream.XMLStreamException;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Locale;
import java.util.Vector;


/**
* This is the base class of the main application class HelloNzb.
* It contains private/protected members and methods for this main
* application class. These are mainly "background" and low-level
* functionalities.
*
* @author Matthias F. Brandstetter
*/
public abstract class HelloNzbCradle implements HelloNzbConstants
{
  /** The main JFrame object of the application window */
  protected JFrame jframe;
 
  /** The menu bar object */
  protected JMenuBar menuBar;
 
  /** The tool bar object */
  protected JToolBar toolBar;
 
  /** download speed history graph */
  protected SpeedGraphPanel speedGraph;
 
  /** "start" toggle button on toolbar */
  protected JToggleButton startToggleButton;
 
  /** "pause" toggle button on toolbar */
  protected JToggleButton pauseToggleButton;
 
  /** "web access" toggle button on toolbar */
  protected JToggleButton webAccessToggleButton;
 
  /** "shutdown" toggle button on toolbar */
  protected JToggleButton shutdownToggleButton;
 
  /** Menu and toolbar items (actions) */
  protected HashMap<String,AbstractAction> actions;
 
  /** A JPanel representing the status bar of the window */
  protected JPanel statusBarPanel;
 
  /** A text element for the status bar */
  protected JLabel statusBarText;
  protected JLabel memoryUsage;
 
  /** download speed label */
  protected JLabel currDlSpeed;
 
  /** limit download speed button */
  protected JButton limitDlSpeedButton;
   
  /** A text element for the ETA and total file size label on the status bar */
  protected JLabel etaAndTotalText;
 
  /** The list of nzb's to process on the left side of the main split pane */
  protected JTable nzbListTab;
 
  /** A list of all connections in main window */
  protected JTable threadViewTab;
 
  /** left/right split pane */
  protected JSplitPane lrSplitPane;
 
  /** up/down split pane */
  protected JSplitPane udSplitPane;
 
  /** The table model for the left JTable */
  protected NzbFileQueueTableModel nzbFileQueueTabModel;
 
  /** The list of files to download for the selected nzb in the left nzb list */
  protected JTable filesToDownloadTab;

  /** Default NIO client */
  protected NettyNioClient nioClient;

  /** Alternative NIO client */
  protected NettyNioClient backupNioClient;

  /** A pointer to the file downloader currently active */
  protected NntpFileDownloader currentFileDownloader;

  /** A pointer to the file alternative downloader currently active */
  protected BackupFileDownloader backupFileDownloader;

  /** A pointer to the nzb parser currently active */
  protected NzbParser currentNzbParser;
 
  /** the total amount of bytes loaded for the current file download */
  protected long totalBytesLoaded;
 
  /** The table model for the right JTable */
  protected FilesToDownloadTableModel filesToDownloadTabModel;
 
  /** Application preferences container (incl. preferences dialog) */
  protected HelloNzbPreferences prefContainer;
 
  /** background worker for misc. background tasks */
  protected BackgroundWorker bgWorker;
 
  /** task manager responsible for controlling the background progress bar */
  protected TaskManager taskMgr;
 
  /** last known count of active threads */
  protected int lastActThreadCount;

  /** String localer */
  protected StringLocaler localer;
 
  /** cental logger object */
  protected MyLogger logger;
 
  /** logging window */
  protected LoggingWindow logWnd;
 
  /** the system tray icon object */
  protected MyTrayIcon trayIcon;
   
  /** if set to true then we can start another parser content saver */
  protected Boolean contentSaverDone;
 
  /** popup window of the NZB file queue */
  protected JPopupMenu leftPopup;
 
  /** popup window of the download file queue */
  protected JPopupMenu rightPopup;
 
 
  /** Class constructor. */
  public HelloNzbCradle(JFrame frame, String title)
  {
    this.jframe = frame;

    // String localer and JVM default locale
    this.localer = new StringLocaler();
    Locale.setDefault(localer.getLocale());
    JOptionPane.setDefaultLocale(localer.getLocale());
    JFileChooser.setDefaultLocale(localer.getLocale());
   
    // create logging window and logger
    logWnd = new LoggingWindow(localer, frame);
    this.logger = MyLogger.getInstance(this, logWnd.getTextArea());

    // set application logo/icon
    URL url = ClassLoader.getSystemResource("resources/icons/HelloNzb_logo.png");
    Toolkit kit = Toolkit.getDefaultToolkit();
    Image img = kit.createImage(url);
    this.jframe.setIconImage(img);

    // set the (default) settings for the main JFrame
    this.jframe.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    this.jframe.setSize(MAINWIN_WIDTH, MAINWIN_HEIGHT);
    this.jframe.setLocationRelativeTo(null);
    this.jframe.setLayout(new BorderLayout());
   
    // create data for nzb file queue and file download queue
    this.nzbFileQueueTabModel = new NzbFileQueueTableModel(localer);
    this.filesToDownloadTabModel = new FilesToDownloadTableModel(localer);

    // dynamically set the widgets while window size is changed
    Toolkit.getDefaultToolkit().setDynamicLayout(true);
   
    // some default values
    this.currentFileDownloader = null;
    this.backupFileDownloader = null;
    this.currentNzbParser = null;
    this.lastActThreadCount = 0;
    this.totalBytesLoaded = 0;
    this.contentSaverDone = true;
    this.leftPopup = null;
    this.rightPopup = null;
    this.prefContainer = null;
  }
 
  /**
   * Initialise the system tray icon.
   */
  protected void initSystemTray(AbstractAction quitAction)
  {
    // system tray activate in preferences?
    boolean isActive = prefContainer.getBooleanPrefValue("GeneralSettingsShowTrayIcon");
    if(!isActive)
    {
      trayIcon = null;
      return;
    }
   
    // system tray supported by OS?
    if(!SystemTray.isSupported())
    {
      trayIcon = null;
      return;
    }
   
    trayIcon = new MyTrayIcon(this, "HelloNzb -- The Binary Usenet Tool", actions);
   
    SystemTray tray = SystemTray.getSystemTray();
    try
    {
      tray.add(trayIcon);
    }
    catch(Exception ex)
    {
      logger.printStackTrace(ex);
      trayIcon = null;
    }
  }
 
  /**
   * Used by the constructor to create the content panes on the main window.
   *
   * These are:
   *   - headerPanel (NORTH)
   *   - splitPane (CENTER, local object in this method)
   *   - statusBarPanel (SOUTH)
   *  
   * The split pane in the CENTER of the window contains two scrollable panes:
   *   - nzbList (LEFT, list of all nzb's, the queue of nzb's to download)
   *   - filesToDownload (RIGHT, list of all files within the selected nzb)
   *  
   * @param progBar The previously create JProgressBar object
   */
  protected QuitAction addContentPanes(JProgressBar progBar)
  {
    // create spacer panels
    jframe.add(new JPanel(), BorderLayout.WEST);
    jframe.add(new JPanel(), BorderLayout.EAST);
 
    // create menu and tool bars
    actions = new HashMap<String,AbstractAction>();
    QuitAction quitAction = createMenuAndToolBars();

    // header panel -- icons and speed graph
    JPanel headerPanel = new JPanel();
    headerPanel.setLayout(new BoxLayout(headerPanel, BoxLayout.LINE_AXIS));
    headerPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 12));
    headerPanel.add(toolBar);
    headerPanel.add(Box.createHorizontalGlue());
   
    // text area and button left of the speed graph
    JPanel tmpPanel = new JPanel();
    tmpPanel.setLayout(new BoxLayout(tmpPanel, BoxLayout.PAGE_AXIS));
    limitDlSpeedButton = new JButton();
    limitDlSpeedButton.setAlignmentX(Component.RIGHT_ALIGNMENT);
    limitDlSpeedButton.setAction(actions.get("MenuHelloNzbSpeedLimit"));
    limitDlSpeedButton.setToolTipText(localer.getBundleText("MenuHelloNzbSpeedLimit"));
    setConnSpeedLimit();
    currDlSpeed = new JLabel(HelloNzbToolkit.prettyPrintBps(0));
    currDlSpeed.setAlignmentX(Component.RIGHT_ALIGNMENT);
    tmpPanel.add(currDlSpeed);
    tmpPanel.add(Box.createRigidArea(new Dimension(0, 10)));
    tmpPanel.add(limitDlSpeedButton);
    tmpPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
    headerPanel.add(tmpPanel);
   
    // speed graph
    speedGraph = new SpeedGraphPanel(200);
    headerPanel.add(speedGraph);
    jframe.add(headerPanel, BorderLayout.NORTH);

    // create left and right tables
    createDataTables();

    // restore window size
    String savedLrDivider = this.prefContainer.getPrefValue("AutoSettingsLrDivider");
    String savedUdDivider = this.prefContainer.getPrefValue("AutoSettingsUdDivider");

    // create a split pane for the download queues (left/right)
    this.lrSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
        new JScrollPane(nzbListTab), new JScrollPane(filesToDownloadTab));
    lrSplitPane.setContinuousLayout(true);
    if(savedLrDivider.isEmpty())
      lrSplitPane.setDividerLocation((int) (jframe.getWidth() / 3));
    else
      lrSplitPane.setDividerLocation(Integer.valueOf(savedLrDivider));
   
    // create a scroll pane for the thread view
    JScrollPane threadView = createThreadViewPane();
   
    // create a split pane for the main split pane and the thread view (up/down)
    this.udSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, lrSplitPane, threadView);
    udSplitPane.setContinuousLayout(true);
    if(savedUdDivider.isEmpty())
      udSplitPane.setDividerLocation((int) (jframe.getHeight() * 0.5));
    else
      udSplitPane.setDividerLocation(Integer.valueOf(savedUdDivider));

    jframe.add(udSplitPane, BorderLayout.CENTER);
   
    // create status bar
    statusBarPanel = createStatusBar(progBar);
    jframe.add(statusBarPanel, BorderLayout.SOUTH);
   
    // return QuitAction object to use for the window listener
    return quitAction;
  }
 
  /**
   * Create the status bar inclusive all contents.
   *
   * @param progBar The previously create JProgressBar object
   * @return The newly created JPanel object
   */
  protected JPanel createStatusBar(JProgressBar progBar)
  {
    // create layout for this tab/panel
        FormLayout layout = new FormLayout(
        "pref, 10dlu:grow, pref, 10dlu:grow, pref, 10dlu, [100dlu,pref,150dlu]", // cols
        "p")// rows
       
        // create builder
        PanelBuilder builder = new PanelBuilder(layout);
        builder.setDefaultDialogBorder();
        CellConstraints cc = new CellConstraints();   
   
        // left status bar text field
    statusBarText = new JLabel(localer.getBundleText("StatusBarRunningThreads") + " 0");
    builder.add(statusBarText, cc.xy(1, 1));

    // Memory usage label
    memoryUsage = new JLabel("");
    builder.add(memoryUsage, cc.xy(3, 1));

    // ETA & total file size text field
    etaAndTotalText = new JLabel("");
    builder.add(etaAndTotalText, cc.xy(5, 1));
    etaAndTotalText.setToolTipText(
        localer.getBundleText("StatusBarEtaAndTotalTooltip"));

    // create background task progress bar in status bar
    builder.add(progBar, cc.xy(7, 1));
   
    return builder.getPanel();
  }
 
  /**
   * Creates the table for the thread view and adds it to a scroll pane.
   *
   * @return The newly created scroll pane
   */
  protected JScrollPane createThreadViewPane()
  {
    // create table data and table object
    int threadcount = 1;
    String tmp = prefContainer.getPrefValue("ServerSettingsThreadCount");
    if(tmp.length() > 0)
      threadcount = Integer.valueOf(tmp);
    ThreadViewTableModel tm = new ThreadViewTableModel(localer);
    tm.setRowCount(threadcount);
    JTable table = new JTable(tm);
   
    // set center alignment for the contents of the first colunn
    table.getColumnModel().getColumn(0).setCellRenderer(new MyTableCellRenderer(SwingConstants.CENTER));
    table.getColumnModel().getColumn(1).setCellRenderer(new MyTableCellRenderer());

    // set header renderers
    table.getColumnModel().getColumn(0).setHeaderRenderer(new AlignedTableHeaderRenderer(SwingConstants.CENTER));
    table.getColumnModel().getColumn(1).setHeaderRenderer(new AlignedTableHeaderRenderer(SwingConstants.LEFT));

    // misc. table settings
    table.setRowSelectionAllowed(false);
    table.setColumnSelectionAllowed(false);
    table.setCellSelectionEnabled(false);
    table.setDragEnabled(false);
    table.getTableHeader().setReorderingAllowed(false);
   
    TableColumn column = table.getColumnModel().getColumn(1);
    column.setPreferredWidth((int) (jframe.getWidth() * 0.66));
   
    // set table header height
    table.getTableHeader().setPreferredSize(new Dimension(table.getColumnModel().getTotalColumnWidth(), 25));
   
    this.threadViewTab = table;
   
    return new JScrollPane(table);
  }
 
  /**
   * Used by the constructor to create the menu bar for the main window.
   */
  protected QuitAction createMenuAndToolBars()
  {
    menuBar = new JMenuBar();
    toolBar = new JToolBar();
    Icon icon = null;
   
    toolBar.setFloatable(false);
   
    /////////////////////////////////////////////////////////////////////
    // create "HelloNzb" menu (main menu, like "File")
    JMenu helloNzbMenu = new JMenu(localer.getBundleText("MenuHelloNzb"));
    menuBar.add(helloNzbMenu);
   
    // open nzb file action
    icon = new ImageIcon(HelloNzb.class.getResource("/resources/icons/open_nzb.png"));
    OpenNzbFileAction openNzbFileAction = new OpenNzbFileAction(this, icon, "MenuHelloNzbOpenNzbFile");
    helloNzbMenu.add(openNzbFileAction);
    actions.put("MenuHelloNzbOpenNzbFile", openNzbFileAction);
   
    // preferences popup
    icon = new ImageIcon(HelloNzb.class.getResource("/resources/icons/preferences.png"));
    PrefAction prefAction = new PrefAction(this, icon, "MenuHelloNzbPref");
    helloNzbMenu.add(prefAction);
    actions.put("MenuHelloNzbPref", prefAction);
   
    helloNzbMenu.addSeparator();
   
    // shutdown computer after download has finished
    icon = new ImageIcon(HelloNzb.class.getResource("/resources/icons/shutdown.png"));
    Icon iconActive = new ImageIcon(HelloNzb.class.getResource("/resources/icons/shutdown_active.png"));
    ShutdownAction shutdownAction = new ShutdownAction(this, icon, iconActive, "MenuHelloNzbShutdown");
    actions.put("MenuHelloNzbShutdown", shutdownAction);

    // check for program updates
    icon = null;
    CheckForUpdateAction updateAction = new CheckForUpdateAction(this, icon, "MenuHelloNzbUpdate");
    if(BETA_VERSION) updateAction.setEnabled(false);
    helloNzbMenu.add(updateAction);
    actions.put("MenuHelloNzbUpdate", updateAction);

    // show program log
    icon = null;
    ShowLoggingWindowAction showLogAction = new ShowLoggingWindowAction(this, icon, "MenuHelloNzbShowLog", logWnd);
    helloNzbMenu.add(showLogAction);
    actions.put("MenuHelloNzbShowLog", updateAction);
   
    helloNzbMenu.addSeparator();
   
    // quit application
    icon = new ImageIcon(HelloNzb.class.getResource("/resources/icons/quit.png"));
    QuitAction quitAction = new QuitAction(this, icon, "MenuHelloNzbQuit", bgWorker, taskMgr);
    helloNzbMenu.add(quitAction);
    actions.put("MenuHelloNzbQuit", quitAction);

    /////////////////////////////////////////////////////////////////////
    // create "Download" menu (timed downloads, ...)
    JMenu downloadMenu = new JMenu(localer.getBundleText("MenuDownload"));
    menuBar.add(downloadMenu);
    downloadMenu.addMenuListener(new MenuListener()
    {
      @Override
      public void menuSelected(MenuEvent e)
      {
        TimedDownloadsAction action = (TimedDownloadsAction) actions.get("MenuDownloadTimedDownloads");
        String startTime = getPrefValue("DownloadSettingsTimedDownloadStart");
        if(startTime == null || startTime.isEmpty())
        {
          action.setEnabled(false);
          return;
        }
        String stopTime = getPrefValue("DownloadSettingsTimedDownloadStop");
        if(stopTime == null || stopTime.isEmpty())
        {
          action.setEnabled(false);
          return;
        }
        action.setEnabled(true);
      }

      @Override
      public void menuDeselected(MenuEvent e)
      {
      }

      @Override
      public void menuCanceled(MenuEvent e)
      {
      }
    });

    // timed downloads
    icon = null;
    TimedDownloadsAction timedDownloadsAction = new TimedDownloadsAction(this, icon, "MenuDownloadTimedDownloads");
    JCheckBoxMenuItem timedDownloads = new JCheckBoxMenuItem(timedDownloadsAction);
    downloadMenu.add(timedDownloads);
    actions.put("MenuDownloadTimedDownloads", timedDownloadsAction);

    /////////////////////////////////////////////////////////////////////
    // create "Server" menu (connect, disconnect, ...)
    JMenu serverMenu = new JMenu(localer.getBundleText("MenuServer"));
    menuBar.add(serverMenu);
   
    // start download
    icon = new ImageIcon(HelloNzb.class.getResource("/resources/icons/start_download.png"));
    StartDownloadAction startDownloadAction =
      new StartDownloadAction(this, icon, "MenuServerStartDownload");
    actions.put("MenuServerStartDownload", startDownloadAction);
   
    // pause download
    icon = new ImageIcon(HelloNzb.class.getResource("/resources/icons/pause_download.png"));
    PauseDownloadAction pauseDownloadAction =
      new PauseDownloadAction(this, icon, "MenuServerPauseDownload");
    actions.put("MenuServerPauseDownload", pauseDownloadAction);
   
    // test server connection
    icon = null;
    ConnectAction connectAction = new ConnectAction(this, icon, "MenuServerConnect");
    serverMenu.add(connectAction);
    actions.put("MenuServerConnect", connectAction);

    /////////////////////////////////////////////////////////////////////
    // create "Web Access" menu (built-in HTTP(S) server)
    JMenu webAccessMenu = null;
    WebAccessAction webAccessAction = null;
    if(WEB_ACCESS)
    {
//      webAccessMenu = new JMenu(localer.getBundleText("MenuWebAccess"));
//      menuBar.add(webAccessMenu);
     
      // start/stop HTTP(S) server
      icon = new ImageIcon(HelloNzb.class.getResource("/resources/icons/web_interface.png"));
      webAccessAction = new WebAccessAction(this, icon, "MenuWebAccessStartStop");
//      webAccessMenu.add(webAccessAction);
      actions.put("MenuWebAccessStartStop", webAccessAction);
    }

    /////////////////////////////////////////////////////////////////////
    // create "Help" menu (help, about, ...)
    JMenu helpMenu = new JMenu(localer.getBundleText("MenuHelp"));
    menuBar.add(helpMenu);
   
    // for help menu first check whether Deskop operations are supported on current platform
    try
    {
      @SuppressWarnings("unused")
      Desktop desktop = Desktop.getDesktop();
     
      // get help (open browser window)
      icon = null;
      GetHelpAction getHelpAction = new GetHelpAction(this, icon, "MenuHelpGetHelp");
      helpMenu.add(getHelpAction);
      actions.put("MenuHelpGetHelp", getHelpAction);

      // report a bug (open browser window)
      icon = null;
      ReportBugAction reportBugAction = new ReportBugAction(this, icon, "MenuHelpReportBug");
      helpMenu.add(reportBugAction);
      actions.put("MenuHelpReportBug", reportBugAction);

      // donate to HelloNzb (open browser window)
      icon = null;
      DonateToHelloNzbAction donateAction = new DonateToHelloNzbAction(this, icon, "MenuHelpDonateToHelloNzb");
      helpMenu.add(donateAction);
      actions.put("MenuHelpDonateToHelloNzb", donateAction);
    }
    catch(UnsupportedOperationException ex) { }
   
    // about HelloNzb
    icon = null;
    AboutHelloNzbAction aboutAction = new AboutHelloNzbAction(this, icon, "MenuHelpAbout");
    helpMenu.add(aboutAction);
    actions.put("MenuHelpAbout", aboutAction);
   
    // set the new menu bar to the main window
    jframe.setJMenuBar(menuBar);
   
    /////////////////////////////////////////////////////////////////////
    // create tool bar

    // load NZB file
    JButton button = new JButton(openNzbFileAction);
    button.setFocusPainted(false);
    button.setText(null);
    toolBar.add(button);

    // start toggle button
    startToggleButton = new JToggleButton(startDownloadAction);
    startToggleButton.setFocusPainted(false);
    startToggleButton.setText(null);
    startToggleButton.setToolTipText(localer.getBundleText("StartButtonTooltip"));
    toolBar.add(startToggleButton);

    // pause toggle button
    pauseToggleButton = new JToggleButton(pauseDownloadAction);
    pauseToggleButton.setFocusPainted(false);
    pauseToggleButton.setText(null);
    toolBar.add(pauseToggleButton);

    if(WEB_ACCESS)
    {
      webAccessToggleButton = new JToggleButton(webAccessAction);
      webAccessToggleButton.setFocusPainted(false);
      webAccessToggleButton.setText(null);
      toolBar.add(webAccessToggleButton);
    }

    // preferences
    button = new JButton(prefAction);
    button.setFocusPainted(false);
    button.setText(null);
    toolBar.add(button);

    toolBar.addSeparator();

    // shutdown toggle button
    shutdownToggleButton = new JToggleButton(shutdownAction);
    shutdownToggleButton.setFocusable(false);
    shutdownToggleButton.setText(null);
    toolBar.add(shutdownToggleButton);

    // quit application
    button = new JButton(quitAction);
    button.setFocusPainted(false);
    button.setText(null);
    toolBar.add(button);

    // speed limit popup
    SpeedLimitAction speedLimitAction = new SpeedLimitAction(this, icon, "MenuHelloNzbSpeedLimit");
    actions.put("MenuHelloNzbSpeedLimit", speedLimitAction);
   
    startDownloadAction.setEnabled(false);
    pauseDownloadAction.setEnabled(false);
   
    // return QuitAction object to use for the window listener
    return quitAction;
  }
 
  /**
   * This method creates the data vectors for the left and right tables
   * (left = nzb files, right = download file queue).
   */
  protected void createDataTables()
  {
    DownloadFileListPopupListener dlFileListener = null;
    DownloadFileListKeyListener dlFileKeyListener = null;
   
    // create left JTable (nzb files)
    nzbListTab = new JTable(nzbFileQueueTabModel)
    {
      public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend)
      {
        super.changeSelection(rowIndex, columnIndex, !extend, extend);
      }
    };

    nzbListTab.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
    nzbListTab.getTableHeader().setReorderingAllowed(false);
    nzbListTab.addMouseListener(new NzbFileListPopupListener(this, nzbListTab));
    nzbListTab.setDragEnabled(true);
    nzbListTab.setDropMode(DropMode.INSERT_ROWS);
    nzbListTab.setTransferHandler(new TableRowTransferHandler(nzbListTab, this));
    nzbListTab.setRowHeight(23);

    // set table cell renderers (left)
    ProgressRenderer cellRenderer = new ProgressRenderer(true);
    nzbListTab.getColumnModel().getColumn(0).setCellRenderer(cellRenderer);
   
    // set table header renderers (left)
    nzbListTab.getColumnModel().getColumn(0).setHeaderRenderer(
        new AlignedTableHeaderRenderer(SwingConstants.CENTER));
   
    // create right JTable (files to download)
    filesToDownloadTab = new JTable(filesToDownloadTabModel);

    filesToDownloadTab.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    dlFileListener = new DownloadFileListPopupListener(this, filesToDownloadTab);
    dlFileKeyListener = new DownloadFileListKeyListener(this, filesToDownloadTab);
    filesToDownloadTab.addMouseListener(dlFileListener);
    filesToDownloadTab.addKeyListener(dlFileKeyListener);
    filesToDownloadTab.getSelectionModel().addListSelectionListener(dlFileListener);
    filesToDownloadTab.getColumnModel().getColumn(0).setMinWidth(333);
    filesToDownloadTab.getColumnModel().getColumn(1).setMinWidth(50);
    filesToDownloadTab.getColumnModel().getColumn(2).setMinWidth(50);
    filesToDownloadTab.getColumnModel().getColumn(3).setMinWidth(50);
    filesToDownloadTab.getTableHeader().setReorderingAllowed(false);

    // set table cell renderers (right)
    filesToDownloadTab.getColumnModel().getColumn(0).setCellRenderer(new MyTableCellRenderer());
    filesToDownloadTab.getColumnModel().getColumn(1).setCellRenderer(new MyTableCellRenderer(SwingConstants.CENTER));
    filesToDownloadTab.getColumnModel().getColumn(2).setCellRenderer(new MyTableCellRenderer(SwingConstants.CENTER));
    filesToDownloadTab.getColumnModel().getColumn(3).setCellRenderer(new ProgressRenderer(false));
   
    // set table header renderers (right)
    filesToDownloadTab.getColumnModel().getColumn(0).setHeaderRenderer(
        new AlignedTableHeaderRenderer(SwingConstants.CENTER));
    filesToDownloadTab.getColumnModel().getColumn(1).setHeaderRenderer(
        new AlignedTableHeaderRenderer(SwingConstants.CENTER));
    filesToDownloadTab.getColumnModel().getColumn(2).setHeaderRenderer(
        new AlignedTableHeaderRenderer(SwingConstants.CENTER));
    filesToDownloadTab.getColumnModel().getColumn(3).setHeaderRenderer(
        new AlignedTableHeaderRenderer(SwingConstants.CENTER));

    // set table header height
    nzbListTab.getTableHeader().setPreferredSize(
        new Dimension(nzbListTab.getColumnModel().getTotalColumnWidth(), 25));
    filesToDownloadTab.getTableHeader().setPreferredSize(
        new Dimension(filesToDownloadTab.getColumnModel().getTotalColumnWidth(), 25));
  }

  /**
   * Set the status bar to a "Running threads: <count>" message.
   *
   * @param threads The count of running download threads
   */
  public void updStatusBar(int threads)
  {
    if(pauseToggleButton.isSelected())
      return;
    if(!startToggleButton.isSelected() && threads >= lastActThreadCount)
      return;
   
    String text = localer.getBundleText("StatusBarRunningThreads") + " " + threads;
    String tc = prefContainer.getPrefValue("ServerSettingsThreadCount");

    final String statusText = text + "/" + tc;
    lastActThreadCount = threads;

        SwingUtilities.invokeLater(new Runnable()
        {
          public void run()
          {
            statusBarText.setText(statusText);
      }
    } );
  }

  /**
   * This method is called if either
   *   a) the last file in download queue has been downloaded, or
   *   b) the user has manually removed the first entry in the nzb file queue.
   *  
   * It reads the next item in the nzb file queue, retrieves all items from
   * it and updates the download file queue.
   */
  protected void loadNextNzbFile()
  {
    if(nzbFileQueueTabModel.getRowCount() > 0)
    {
      // start to download first file of the next nzb file in queue
      NzbParser parser = nzbFileQueueTabModel.getNzbParser(0);
      if(parser != null)
      {
        filesToDownloadTabModel.addNzbParserContents(parser);
        currentNzbParser = parser;
      }
    }
  }
 
  /**
   * This method adds the content of a nzb file (i.e. a NzbParser object)
   * to the download queue. It first checks if another nzb file with that
   * name already exists in the nzb queue.
   *
   * @param parser The NzbParser object to add
   */
  public void addNzbToQueue(NzbParser parser)
  {
    // check if an nzb file with this name already exists in queue
    if(nzbFileQueueTabModel.containsNzb(parser))
    {
      String title = localer.getBundleText("PopupErrorTitle");
      String msg = localer.getBundleText("PopupNzbFilenameAlreadyInQueue");
      JOptionPane.showMessageDialog(null, msg, title, JOptionPane.ERROR_MESSAGE);
      return;
    }
   
    // no, so add the new nzb file to the queue
    nzbFileQueueTabModel.addRow(parser);
   
    if(filesToDownloadTabModel.getRowCount() == 0)
    {
      if(!filesToDownloadTabModel.addNzbParserContents(parser))
        logger.msg("Failed to add at least one file to the queue -- is it too large?", MyLogger.SEV_WARNING);

      currentNzbParser = parser;
      totalBytesLoaded = currentNzbParser.getDownloadedBytes();
    }
   
    logger.msg("Added content of " + parser.getName() + ".nzb to queue", MyLogger.SEV_INFO);

    // enable toolbar and menu action
    AbstractAction action = actions.get("MenuServerStartDownload");
    action.setEnabled(true);
  }
 
  /**
   * Load the last session (NZB files that were open).
   */
  protected void loadLastSession()
  {
    // does data directory exists?
    String datadirPath = System.getProperty("user.home") + File.separator + ".HelloNzb" + File.separator;
    File datadir = new File(datadirPath);
   
    if(!datadir.isDirectory() || !datadir.canRead() || !datadir.canExecute())
    {
      logger.msg("Could not load last session, specified folder is no directory or non-readable", MyLogger.SEV_DEBUG);
      return;
    }
       
    // set background status bar
    taskMgr.loadSession(true);
       
    // directory exists, so load all nzb files from it
    File [] files = datadir.listFiles();
    File tmpFile = null;
    for(File file : files)
    {
      try
      {
        // directory
        if(file.isDirectory())
          continue;
       
        // nzb file?
        String filename = file.getCanonicalPath();
        if(!filename.substring(filename.length() - 4, filename.length()).equalsIgnoreCase(".nzb"))
        {
          if(file.canWrite())
          {
            logger.msg("Deleting non-NZB file " + file.getName(), MyLogger.SEV_INFO);
            file.delete();
          }
          continue;
        }
       
        if(!filename.contains("-"))
        {
          if(file.canWrite())
          {
            logger.msg("Deleting NZB file without '-' (" + file.getName() + ")", MyLogger.SEV_INFO);
            file.delete();
          }
          continue;
        }

        // yes, so remove index part of the filename (e.g. "1-filename.nzb")
        while(!filename.startsWith("-"))
          filename = filename.substring(1, filename.length());
        filename = filename.substring(1, filename.length());
       
        // tmp. rename original source file
        tmpFile = new File(datadirPath + filename);
        file.renameTo(tmpFile);
       
        NzbParser parser = new NzbParser(tmpFile.getAbsolutePath(), getPrefValue("GeneralSettingsDownloadDir"));
        addNzbToQueue(parser);
        logger.msg("Loaded new NZB file from last session: " + parser.getName(), MyLogger.SEV_INFO);
      }
      catch(Exception e)
      {
        logger.printStackTrace(e);
      }
      finally
      {
        if(tmpFile != null && tmpFile.canWrite())
          tmpFile.delete();
        if(file != null && file.canWrite())
          file.delete();
      }
    }
   
    // unset background status bar
    taskMgr.loadSession(false);
  }
 
  /**
   * Update the status of one connection in the thread view table.
   *
   * @param conn The connection number to set (counted from 0)
   * @param text The new text to set
   */
  public void updThreadView(int conn, String text)
  {
    synchronized(threadViewTab)
    {
      threadViewTab.setValueAt(text, conn, 1);
    }
  }
 
  /**
   * Called to save the currently open and unused parser data.
   *
   * @param wait If true then wait until saving to disk has finished.
   */
  public void saveOpenParserData(boolean wait)
  {
    synchronized(contentSaverDone)
    {
      if(contentSaverDone)
      {
        contentSaverDone = false;     
        new ParserContentSaver(this, nzbFileQueueTabModel.copyQueue(), filesToDownloadTabModel.getDownloadFileVector()).start();
      }
    }
   
    if(wait)
    {
      while(!contentSaverDone)
      {
        try
        {
          Thread.sleep(100);
        }
        catch(InterruptedException ex) {}
      }
    }
  }

  /**
   * Sets the contentSaverDone flag to true.
   */
  public void contentSaverDone()
  {
    synchronized(contentSaverDone)
    {
      contentSaverDone = true;
    }
  }
 
  /**
   * Return the current contentSaverDone value (either true or false).
   */
  public boolean isContentSaverDone()
  {
    boolean ret;
   
    synchronized(contentSaverDone)
    {
      ret = contentSaverDone;
    }
   
    return ret;
  }
 
  /**
   * Load the specified nzb file (passed via command line at application call).
   *
   * @param filename The file to load, quit if null
   */
  protected void loadFileFromCmdLine(String filename)
  {
    // filename passed at command line?
    if(filename == null)
      return;
   
    // set background status bar
    taskMgr.loadNzb(true);

    try
    {
      File file = new File(filename);
      addNzbToQueue(new NzbParser(filename, getPrefValue("GeneralSettingsDownloadDir")));
      if(getBooleanPrefValue("GeneralSettingsDelNzbAfterLoading"))
        file.delete();
    }
    catch(IOException e)
    {
      System.err.println("Error while reading file '" + filename + "'!");
      System.exit(8);
    }
    catch(XMLStreamException e)
    {
      System.err.println("Given file '" + filename + "' is not a valid NZB file!");
      System.exit(8);
    }
    catch(java.text.ParseException e)
    {
      System.err.println(e.getMessage());
      System.exit(8);
    }
   
    // unset background status bar
    taskMgr.loadNzb(false);
  }

  /**
   * Shutdown the HelloNzb application.
   */
  public void shutdownHelloNzb()
  {
    final AbstractAction quitAction = actions.get("MenuHelloNzbQuit");
    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
      {
        quitAction.actionPerformed(null);
      }
    });
  }

  /**
   * Shutdown the computer now (after all downloads have been finished).
   */
  public void shutdownNow()
  {
    String shutdownCmd = "";
    String shutdownDir = "";
   
    if(System.getProperty("os.name").contains("Windows"))
    {
      shutdownCmd = "shutdown.exe /s /f";
      shutdownDir = System.getenv("SystemRoot") + "/system32";
    }
    else if(System.getProperty("os.name").contains("Linux"))
    {
      shutdownCmd = "sudo shutdown -h -q now";
      shutdownDir = "/sbin";
    }
   
    File dir = new File(shutdownDir);
   
    try
    {
      Thread.sleep(1000);
      saveOpenParserData(true);

      // execute shutdown command
      taskMgr.shutdown();
      bgWorker.shutdown();
      Runtime rt = Runtime.getRuntime();
      Process proc = rt.exec(shutdownCmd, null, dir);
      StreamGobbler errGobbler = new StreamGobbler(logger, proc.getErrorStream(), "ERR");
      StreamGobbler outGobbler = new StreamGobbler(logger, proc.getInputStream(), "OUT");

      // fetch command's STDOUT and STDERR
      errGobbler.start();
      outGobbler.start();
    }
    catch(Exception e)
    {
      logger.printStackTrace(e);
    }
   
    System.exit(0);
  }
 
  /**
   * Create a share memory mapping so that a second instance of this
   * program can later on pass new nzb files to this first instance here.
   * This method also starts a background thread that "listens" to this
   * shared memory for new data (nzb file locations) to read.
   *
   * This method creates an instance of the BackgroundWorker thread class
   * and starts this thread.
   */
  protected void startBgWorker()
  {
    try
    {
      bgWorker = new BackgroundWorker(this, MEM_MAP_BUFFER_SIZE);
      bgWorker.start();
    }
    catch(IOException e)
    {
      logger.printStackTrace(e);
    }
  }

  /**
   * Set the connection speed limit label on the status bar
   * according to value in preferences.
   */
  public void setConnSpeedLimit()
  {
    String pref = prefContainer.getPrefValue("DownloadSettingsMaxConnectionSpeed");
   
    try
    {
      @SuppressWarnings("unused")
      long tmp = Long.parseLong(pref);
    }
    catch(Exception ex)
    {
      pref = "0";
      prefContainer.setSpeedLimit("0");
    }
   
    if(pref.length() == 0 || Long.valueOf(pref) == 0)
    {
      limitDlSpeedButton.setText(localer.getBundleText("DlSpeedLimitButton"));
    }   
    else 
    {
      limitDlSpeedButton.setText(
          localer.getBundleText("DlSpeedLimitButton2") + " " + pref + " KB/s");
    }     
  }
 
  /**
   * Use this method to set the ETA and total file size label.
   * Also set the tooltip of the system tray icon accordingly.
   *
   * @param text The text to set on the label
   */
  public void setEtaAndTotalLabel(final String text)
  {
    // set label in status bar
    if(etaAndTotalText != null)
    {
          SwingUtilities.invokeLater(new Runnable()
          {
            public void run()
            {
              etaAndTotalText.setText(text);
        }
      } );
    }
   
    // set system tray icon
    if(trayIcon != null)
    {
      if(text == null || text.isEmpty())
        trayIcon.setToolTip("HelloNzb -- " + localer.getBundleText("SystemTrayTooltipNoFiles"));
      else
        trayIcon.setToolTip("HelloNzb -- " + text);
    }
  }

  /**
   * Set the memory usage label in the program's status bar.
   *
   * @param text The text to set on the label
   */
  public void setMemoryUsageLabel(final String text)
  {
    if(etaAndTotalText != null)
    {
      SwingUtilities.invokeLater(new Runnable()
      {
        public void run()
        {
          memoryUsage.setText(text);
        }
      } );
    }
  }
 
  /**
   * Use this method to set the current download speed label.
   *
   * @param bps The text to set on the label
   */
  public void setCurrDlSpeedLabel(final long bps)
  {
    if(currDlSpeed != null)
    {
          SwingUtilities.invokeLater(new Runnable()
          {
            public void run()
            {
              currDlSpeed.setText(HelloNzbToolkit.prettyPrintBps(bps));
        }
      } );
    }     
  }
 
  /**
   * (Un)set the system tray icon.
   *
   * @param flag Whether or not to set the icon
   */
  public void setTrayIcon(boolean flag)
  {
    if(flag && trayIcon != null)
      return; // yes to set, but alreay active
    else if(!flag && trayIcon == null)
      return; // don't set, but already non-active
    else if(flag)
      initSystemTray(actions.get("MenuHelloNzbQuit")); // set it
    else
    {
      // unset it
      SystemTray tray = SystemTray.getSystemTray();
      tray.remove(trayIcon);
      trayIcon = null;
    }
  }

  /**
   * Check whether or not the system tray icon is set for the running program.
   *
   * @return true if we have set the tray icon, false otherwise
   */
  public boolean hasTrayIcon()
  {
    return (trayIcon != null) ? true : false
  }
 
  /**
   * Returns true if there is currently a download active.
   *
   * @return true/false
   */
  public boolean isDownloadActive()
  {
    return (currentFileDownloader == null ? false : true);
  }

  /**
   * Get the JFrame object, i.e. the applications main window.
   *
   * @return The JFrame object
   */
  public JFrame getJFrame()
  {
    return jframe;
  }
 
  /**
   * Get the specified preferences value.
   */
  public String getPrefValue(String id)
  {
    return prefContainer.getPrefValue(id);
  }
 
  /**
   * Get the specified boolean-type preferences value.
   */
  public boolean getBooleanPrefValue(String id)
  {
    return prefContainer.getBooleanPrefValue(id);
  }
 
  /**
   * Get the applications preferences container.
   *
   * @return The HelloNzbPreferences object
   */
  public HelloNzbPreferences getPrefContainer()
  {
    return prefContainer;
  }
 
  /**
   * Get the menu bar object of the main application window.
   *
   * @return The JMenuBar object
   */
  public JMenuBar getMenu()
  {
    return menuBar;
  }
 
  /**
   * Get the tool bar object of the main application window.
   *
   * @return The JToolBar object
   */
  public JToolBar getToolBar()
  {
    return toolBar;
  }
 
  /**
   * Return the count of files in the download queue.
   *
   * @return The count of files
   */
  public int getDownloadFileCount()
  {
    return filesToDownloadTabModel.getRowCount();
  }
 
  /**
   * Set the table in the thread view to the according number of lines.
   */
  public void resetThreadView()
  {
    try
    {
      int threadcount = Integer.valueOf(prefContainer.getPrefValue("ServerSettingsThreadCount"));
      ThreadViewTableModel tm = (ThreadViewTableModel) threadViewTab.getModel();
      tm.setRowCount(threadcount);
    }
    catch(NumberFormatException ex)
    {
      ThreadViewTableModel tm = (ThreadViewTableModel) threadViewTab.getModel();
      tm.setRowCount(1);
    }
  }
 
  /**
   * Globally disconnect from server, if currently connected.
   *
   * @param block Whether or not to wait until connection has closed
   */
  public void globalDisconnect(boolean block)
  {
    if(currentFileDownloader != null)
    {
      currentFileDownloader.shutdown();
      currentFileDownloader = null;
    }

    if(backupFileDownloader != null)
    {
      backupFileDownloader.shutdown();
      backupFileDownloader = null;
    }

    if(nioClient != null)
    {
      nioClient.shutdown(false, System.nanoTime() + 10 * SEC_MODIFIER, block);
      nioClient = null;
    }

    if(backupNioClient != null)
    {
      backupNioClient.shutdown(false, System.nanoTime() + 10 * SEC_MODIFIER, block);
      backupNioClient = null;
    }

    resetThreadView();
  }

  /**
   * Set the start/stop and pause toggle buttons.
   * This method sets the buttons' states, icons, and tooltips.
   */
  public void setStartStopPauseToggleButtons(boolean start)
  {
    if(start)
    {
      startToggleButton.setIcon(new ImageIcon(HelloNzb.class.getResource("/resources/icons/start_download.png")));
      startToggleButton.setToolTipText(localer.getBundleText("StartButtonTooltip"));
      startToggleButton.setSelected(false);
      pauseToggleButton.setSelected(false);
    }
    else
    {
      startToggleButton.setIcon(new ImageIcon(HelloNzb.class.getResource("/resources/icons/stop_download.png")));
      startToggleButton.setToolTipText(localer.getBundleText("StopButtonTooltip"));
      startToggleButton.setSelected(true);
      pauseToggleButton.setSelected(false);
    }
  }

  /**
   * Returns the lr split pane divider.
   *
   * @return The current value
   */
  public JSplitPane getLrSplitPane()
  {
    return lrSplitPane;
  }

  /**
   * Returns the ud split pane divider.
   *
   * @return The current value
   */
  public JSplitPane getUdSplitPane()
  {
    return udSplitPane;
  }
 
  /**
   * Returns the localer object.
   *
   * @return The localer object
   */
  public StringLocaler getLocaler()
  {
    return localer;
  }
 
  /**
   * Returns the task manager object.
   *
   * @return The task manager object
   */
  public TaskManager getTaskManager()
  {
    return taskMgr;
  }
 
  /**
   * Returns the current NettyNioClient object (or null)
   *
   * @return The current NettyNioClient object (or null)
   */
  public NettyNioClient getCurrNioClient()
  {
    return nioClient;
  }
 
  /**
   * Returns the total amount of bytes loaded (counted for the currently
   * downloaded NZB file and all its segments).
   *
   * @return The total amount of loaded bytes
   */
  public long getTotalBytesLoaded()
  {
    return totalBytesLoaded;
  }
 
  /**
   * Returns all NzbParser objects currently in the NZB file queue.
   *
   * @return All NzbParser objects in a vector
   */
  public Vector<NzbParser> getNzbQueue()
  {
    Vector<NzbParser> vector = new Vector<NzbParser>();
   
    // get all NzbParser objects from table model
    try
    {
      int size = nzbFileQueueTabModel.getRowCount();
      for(int i = 0; i < size; i++)
        vector.add(nzbFileQueueTabModel.getNzbParser(i));
    }
    catch(Exception e) {}
   
    return vector;
  }
 
  /**
   * Returns the central logger instance.
   * @return The Logger object
   */
  public MyLogger getLogger()
  {
    return logger;
  }
 
  /**
   * Returns the speed history graph panel object.
   * @return The SpeedGraphPanel object
   */
  public SpeedGraphPanel getSpeedGraphPanel()
  {
    return speedGraph;
  }

  /**
   * Register the popup menu object of the NZB file queue.
   * @param popup
   */
  public void registerLeftPopup(JPopupMenu popup)
  {
    leftPopup = popup;
  }

  /**
   * Register the popup menu object of the download file queue.
   * @param popup
   */
  public void registerRightPopup(JPopupMenu popup)
  {
    rightPopup = popup;
  }
 
  /**
   * Dispose left popup menu.
   */
  public void disposeLeftPopup()
  {
    if(leftPopup != null)
    {
      leftPopup.setVisible(false);
      leftPopup.setEnabled(false);
      leftPopup = null;
    }
  }
 
  /**
   * Dispose right popup menu.
   */
  public void disposeRightPopup()
  {
    if(rightPopup != null)
    {
      rightPopup.setVisible(false);
      rightPopup.setEnabled(false);
      rightPopup = null;
    }
  }

  /**
   * Retrieve the given menu/toolbar action.
   */
  public AbstractAction getMenuToolbarAction(String action)
  {
    return actions.get(action);
  }

  public abstract void startDownload();
}
























TOP

Related Classes of me.mabra.hellonzb.HelloNzbCradle

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.