org.transdroid.gui.TorrentsFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.transdroid.gui.TorrentsFragment.java

Source

/*
 *   This file is part of Transdroid <http://www.transdroid.org>
 *   
 *   Transdroid 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.
 *   
 *   Transdroid 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 Transdroid.  If not, see <http://www.gnu.org/licenses/>.
 *   
 */
package org.transdroid.gui;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.transdroid.R;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.DaemonMethod;
import org.transdroid.daemon.DaemonSettings;
import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.IDaemonCallback;
import org.transdroid.daemon.Label;
import org.transdroid.daemon.TaskQueue;
import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.TorrentStatus;
import org.transdroid.daemon.TorrentsComparator;
import org.transdroid.daemon.TorrentsSortBy;
import org.transdroid.daemon.task.AddByFileTask;
import org.transdroid.daemon.task.AddByMagnetUrlTask;
import org.transdroid.daemon.task.AddByUrlTask;
import org.transdroid.daemon.task.DaemonTask;
import org.transdroid.daemon.task.DaemonTaskFailureResult;
import org.transdroid.daemon.task.DaemonTaskSuccessResult;
import org.transdroid.daemon.task.GetStatsTask;
import org.transdroid.daemon.task.GetStatsTaskSuccessResult;
import org.transdroid.daemon.task.PauseAllTask;
import org.transdroid.daemon.task.PauseTask;
import org.transdroid.daemon.task.RemoveTask;
import org.transdroid.daemon.task.ResumeAllTask;
import org.transdroid.daemon.task.ResumeTask;
import org.transdroid.daemon.task.RetrieveTask;
import org.transdroid.daemon.task.RetrieveTaskSuccessResult;
import org.transdroid.daemon.task.SetAlternativeModeTask;
import org.transdroid.daemon.task.SetDownloadLocationTask;
import org.transdroid.daemon.task.SetLabelTask;
import org.transdroid.daemon.task.SetTransferRatesTask;
import org.transdroid.daemon.task.StartAllTask;
import org.transdroid.daemon.task.StartTask;
import org.transdroid.daemon.task.StopAllTask;
import org.transdroid.daemon.task.StopTask;
import org.transdroid.daemon.util.DLog;
import org.transdroid.daemon.util.FileSizeConverter;
import org.transdroid.daemon.util.HttpHelper;
import org.transdroid.gui.SetLabelDialog.ResultListener;
import org.transdroid.gui.TorrentViewSelectorWindow.LabelSelectionListener;
import org.transdroid.gui.TorrentViewSelectorWindow.MainViewTypeSelectionListener;
import org.transdroid.gui.rss.RssFeeds;
import org.transdroid.gui.search.Search;
import org.transdroid.gui.util.ActivityUtil;
import org.transdroid.gui.util.DialogWrapper;
import org.transdroid.gui.util.ErrorLogSender;
import org.transdroid.gui.util.InterfaceSettings;
import org.transdroid.preferences.Preferences;
import org.transdroid.preferences.PreferencesMain;
import org.transdroid.search.barcode.GoogleWebSearchBarcodeResolver;
import org.transdroid.service.AlarmSettings;
import org.transdroid.service.BootReceiver;
import org.transdroid.util.TLog;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.SearchManager;
import android.content.ContentResolver;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SpinnerAdapter;
import android.widget.TableLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
import com.actionbarsherlock.app.SherlockFragment;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.SubMenu;

/**
 * The main screen for the Transdroid application and provides most on-the-surface functionality 
 * as well. Server daemon and search engine communication is wrapped in adapters.
 * 
 * @author erickok
 *
 */
public class TorrentsFragment extends SherlockFragment implements IDaemonCallback, OnTouchListener {

    private static final String LOG_NAME = "Main";

    private static final int ACTIVITY_PREFERENCES = 0;
    private static final int ACTIVITY_DETAILS = 1;
    private static final int ACTIVITY_BARCODE = 0x0000c0de;

    private static final int DIALOG_SERVERS = 0;
    private static final int DIALOG_RATES = 1;
    private static final int DIALOG_CHANGELOG = 2;
    private static final int DIALOG_ASKREMOVE = 3;
    private static final int DIALOG_SETLABEL = 4;
    private static final int DIALOG_ADDFAILED = 5;
    private static final int DIALOG_SETDOWNLOADLOCATION = 6;
    private static final int DIALOG_REFRESH_INTERVAL = 7;
    private static final int DIALOG_INSTALLBARCODESCANNER = 8;
    private static final int DIALOG_FILTER = 9;

    private static final int MENU_ADD_ID = 1;
    private static final int MENU_BARCODE_ID = 2;
    private static final int MENU_RSS_ID = 3;
    private static final int MENU_FORALL_ID = 4;
    private static final int MENU_SORT_ID = 5;

    private static final int MENU_SETTINGS_ID = 6;
    private static final int MENU_CHANGELOG_ID = 7;
    private static final int MENU_SWITCH_ID = 8;
    private static final int MENU_RATES_ID = 9;
    private static final int MENU_ERRORREPORT_ID = 10;

    private static final int MENU_REFRESH_ID = 11;
    private static final int MENU_SEARCH_ID = 12;
    private static final int MENU_ALTMODE_ID = 13;

    private static final int MENU_FORALL_GROUP_ID = 20;
    private static final int MENU_FORALL_PAUSE_ID = 21;
    private static final int MENU_FORALL_RESUME_ID = 22;
    private static final int MENU_FORALL_STOP_ID = 23;
    private static final int MENU_FORALL_START_ID = 24;

    private static final int MENU_SORT_GROUP_ID = 30;
    private static final int MENU_SORT_ALPHA_ID = 31;
    private static final int MENU_SORT_STATUS_ID = 32;
    private static final int MENU_SORT_DONE_ID = 33;
    private static final int MENU_SORT_ADDED_ID = 34;
    private static final int MENU_SORT_UPSPEED_ID = 35;
    private static final int MENU_SORT_RATIO_ID = 36;
    private static final int MENU_SORT_GTZERO_ID = 37;

    private static final int MENU_PAUSE_ID = 41;
    private static final int MENU_RESUME_ID = 42;
    private static final int MENU_STOP_ID = 43;
    private static final int MENU_START_ID = 44;
    private static final int MENU_FORCESTART_ID = 45;
    private static final int MENU_REMOVE_ID = 46;
    private static final int MENU_REMOVE_DATA_ID = 47;
    private static final int MENU_SETLABEL_ID = 48;
    private static final int MENU_SETDOWNLOADLOCATION_ID = 49;

    private static final int MENU_FILTER_ID = 60;

    protected boolean useTabletInterface;
    private Handler handler;
    private Runnable refreshRunable;
    private GestureDetector gestureDetector;
    private TextView emptyText;
    private TableLayout statusBox;
    private TextView taskmessage, statusDown, statusUp, statusDownRate, statusUpRate;
    private LinearLayout startsettings;
    private ImageView viewtypeselector;
    private TextView viewtype;
    private LinearLayout controlbar;
    private TorrentViewSelectorWindow viewtypeselectorpopup;

    // Variables determining which view over the torrents to show
    private TorrentsSortBy sortSetting = TorrentsSortBy.Alphanumeric;
    private boolean sortReversed = false;
    private MainViewType activeMainView = MainViewType.ShowAll;
    private boolean onlyShowTransferring = false;
    private List<String> availableLabels;
    private String activeLabel = null;
    private boolean inAlternativeMode = false; // Whether the server is in alternative (speed) mode (i.e. Transmission's Turtle Mode)
    protected boolean ignoreFirstListNavigation = true;
    private String activeFilter = null;

    private List<Torrent> allTorrents;
    private List<Label> allLabels;

    private TaskQueue queue;
    private boolean inProgress = false;

    // Settings-related variables
    private IDaemonAdapter daemon;
    private static List<DaemonSettings> allDaemonSettings;
    private static int lastUsedDaemonSettings;
    private static InterfaceSettings interfaceSettings;
    private static AlarmSettings alarmServiceSettings;

    // Variables to store data to use inside the dialogs that we pop up
    private Torrent selectedTorrent;
    private boolean selectedRemoveData;
    private String failedTorrentUri;
    private String failedTorrentTitle;

    public TorrentsFragment() {
        setHasOptionsMenu(true);
        setRetainInstance(true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        ignoreFirstListNavigation = true;
        return inflater.inflate(R.layout.fragment_torrents, container, false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        // Attach the Android TLog to the daemon logger
        DLog.setLogger(TLog.getInstance());

        // Set activity screen features
        useTabletInterface = Transdroid.isTablet(getResources());
        registerForContextMenu(getListView());
        getListView().setTextFilterEnabled(true);
        getListView().setOnItemClickListener(onTorrentClicked);

        // Access UI widgets and title
        emptyText = (TextView) findViewById(android.R.id.empty);
        startsettings = (LinearLayout) findViewById(R.id.startsettings);
        taskmessage = (TextView) findViewById(R.id.taskmessage);
        statusBox = (TableLayout) findViewById(R.id.st_box);
        statusDown = (TextView) findViewById(R.id.st_down);
        statusDownRate = (TextView) findViewById(R.id.st_downrate);
        statusUp = (TextView) findViewById(R.id.st_up);
        statusUpRate = (TextView) findViewById(R.id.st_uprate);
        setProgressBar(false);

        // Open settings button
        Button startsettingsButton = (Button) findViewById(R.id.startsettings_button);
        startsettingsButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // Open settings screen
                startActivityForResult(new Intent(getActivity(), PreferencesMain.class), ACTIVITY_PREFERENCES);
            }
        });
        // Show a dialog allowing control over max. upload and download speeds
        statusBox.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                showDialog(DIALOG_RATES);
            }
        });

        // The control bar and view type selector (quickaction popup)
        controlbar = (LinearLayout) findViewById(R.id.controlbar);
        viewtype = (TextView) findViewById(R.id.viewtype);
        viewtypeselector = (ImageView) findViewById(R.id.viewtypeselector);
        viewtypeselectorpopup = new TorrentViewSelectorWindow(viewtypeselector,
                new MainViewTypeSelectionListener() {
                    @Override
                    public void onMainViewTypeSelected(MainViewType newType) {
                        if (activeMainView != newType) {
                            // Show torrents for the new main view selection
                            activeMainView = newType;
                            updateTorrentsView(true);
                        }
                    }
                }, new LabelSelectionListener() {
                    @Override
                    public void onLabelSelected(int labelPosition) {
                        String newLabel = availableLabels.get(labelPosition);
                        if (activeLabel != newLabel) {
                            // Show torrents for the new label selection
                            activeLabel = newLabel;
                            updateTorrentsView(true);
                        }
                    }
                });
        viewtypeselector.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                viewtypeselectorpopup.showLikePopDownMenu();
            }
        });

        // Swiping (flinging) between server configurations (or labels)
        gestureDetector = new GestureDetector(new MainScreenGestureListener());
        getListView().setOnTouchListener(this);
        emptyText.setOnTouchListener(this);

        // Attach auto refresh handler
        handler = new Handler();
        refreshRunable = new Runnable() {
            public void run() {
                updateTorrentList();
                setupRefreshTimer();
            }
        };

        // Read all the user preferences
        readSettings();

        // Setup the default server daemon
        setupDaemon();

        // Set up a task queue
        queue = new TaskQueue(new TaskResultHandler(this));
        queue.start();

        // Start the alarm service, if needed
        BootReceiver.startAlarm(getActivity().getApplicationContext());

        // Check for new app version, if needed
        BootReceiver.startUpdateCheck(getActivity().getApplicationContext());

        handleIntent(getActivity().getIntent());

    }

    public void handleIntent(final Intent startIntent) {

        // Handle new intents that come from either a regular application startup, a startup from a 
        // new intent or a new intent being send with the application already started
        if (startIntent != null
                && (startIntent.getData() != null || (startIntent.getAction() != null
                        && startIntent.getAction().equals(Transdroid.INTENT_ADD_MULTIPLE)))
                && !isLaunchedFromHistory(startIntent)) {

            if (startIntent.getAction() != null && startIntent.getAction().equals(Transdroid.INTENT_ADD_MULTIPLE)) {

                // Intent should have some extras pointing to possibly multiple torrents
                String[] urls = startIntent.getStringArrayExtra(Transdroid.INTENT_TORRENT_URLS);
                String[] titles = startIntent.getStringArrayExtra(Transdroid.INTENT_TORRENT_TITLES);
                if (urls != null) {
                    for (int i = 0; i < urls.length; i++) {
                        addTorrentByUrl(urls[i], (titles != null && titles.length >= i ? titles[i] : "Torrent"));
                    }
                }

            } else {

                // Intent should have some Uri data pointing to a single torrent
                String data = startIntent.getDataString();
                if (data != null && startIntent.getData() != null && startIntent.getData().getScheme() != null) {
                    // From Android 4.2 the file path is not directly in the Intent :( but rather in the 'Download manager' cursor
                    if (startIntent.getData().getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
                        addTorrentFromDownloads(startIntent.getData());
                    } else if (startIntent.getData().getScheme().equals(HttpHelper.SCHEME_HTTP)
                            || startIntent.getData().getScheme().equals(HttpHelper.SCHEME_HTTPS)) {
                        // From a global intent to add a .torrent file via URL (maybe form the browser)
                        String title = data.substring(data.lastIndexOf("/"));
                        if (startIntent.hasExtra(Transdroid.INTENT_TORRENT_TITLE)) {
                            title = startIntent.getStringExtra(Transdroid.INTENT_TORRENT_TITLE);
                        }
                        addTorrentByUrl(data, title);
                    } else if (startIntent.getData().getScheme().equals(HttpHelper.SCHEME_MAGNET)) {
                        // From a global intent to add a magnet link via URL (usually from the browser)
                        addTorrentByMagnetUrl(data);
                    } else if (startIntent.getData().getScheme().equals(HttpHelper.SCHEME_FILE)) {
                        // From a global intent to add via the contents of a local .torrent file (maybe form a file manager)
                        addTorrentByFile(data);
                    }
                }

            }

        }

        // Possibly switch to a specific daemon (other than the last used)
        boolean forceUpdate = false;
        if (startIntent != null && !isLaunchedFromHistory(startIntent)
                && startIntent.hasExtra(Transdroid.INTENT_OPENDAEMON)) {
            String openDaemon = startIntent.getStringExtra(Transdroid.INTENT_OPENDAEMON);
            if (!daemon.getSettings().getIdString().equals(openDaemon)) {
                int openDaemonI = (openDaemon == null || openDaemon.equals("") ? 0 : Integer.parseInt(openDaemon));
                if (openDaemonI >= allDaemonSettings.size()) {
                    openDaemonI = 0;
                }
                forceUpdate = true;
                switchDaemonConfig(openDaemonI);
            }

        }

        if (forceUpdate || allTorrents == null) {
            // Not swithcing to another daemon and no known list of torrents: update
            updateTorrentList();
        } else {
            // We retained the list of torrents form the fragment state: show again
            updateStatusText(null);
            updateTorrentsView(false);
        }

    }

    private boolean isLaunchedFromHistory(final Intent startIntent) {
        return (startIntent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0;
    }

    public void onResume() {
        super.onResume();
        queue.start();
        setupRefreshTimer();
    }

    public void onPause() {
        super.onPause();
        queue.requestStop();
        handler.removeCallbacks(refreshRunable);
    }

    /**
     * Start a refresh timer, if the user enabled this in the settings
     */
    private void setupRefreshTimer() {
        if (interfaceSettings != null && interfaceSettings.getRefreshTimerInterval() > 0) {
            handler.postDelayed(refreshRunable, interfaceSettings.getRefreshTimerInterval() * 1000);
        }
    }

    private void readSettings() {

        TLog.d(LOG_NAME, "Reading settings");

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
        allDaemonSettings = Preferences.readAllDaemonSettings(prefs);
        lastUsedDaemonSettings = Preferences.readLastUsedDaemonOrderNumber(prefs, allDaemonSettings);
        interfaceSettings = Preferences.readInterfaceSettings(prefs);
        sortSetting = TorrentsSortBy
                .getStatus(prefs.getInt(Preferences.KEY_PREF_LASTSORTBY, TorrentsSortBy.Alphanumeric.getCode()));
        sortReversed = prefs.getBoolean(Preferences.KEY_PREF_LASTSORTORD, false);
        onlyShowTransferring = prefs.getBoolean(Preferences.KEY_PREF_LASTSORTGTZERO, false);
        alarmServiceSettings = Preferences.readAlarmSettings(prefs);

        // Update the navigation list of the action bar
        ignoreFirstListNavigation = true;
        getSherlockActivity().getSupportActionBar().setListNavigationCallbacks(buildServerListAdapter(),
                onServerChanged);

    }

    private void setupDaemon() {

        // If preferences are set, create the daemon adapter
        if (allDaemonSettings != null && allDaemonSettings.size() > lastUsedDaemonSettings
                && allDaemonSettings.get(lastUsedDaemonSettings) != null
                && allDaemonSettings.get(lastUsedDaemonSettings).getType() != null) {

            // Instantiate the daemon (the connection isn't made until an actual request is done)
            DaemonSettings settings = allDaemonSettings.get(lastUsedDaemonSettings);
            daemon = settings.getType().createAdapter(settings);
            emptyText.setText(R.string.connecting);

            // Show which server configuration is currently active
            ignoreFirstListNavigation = true;
            getSherlockActivity().getSupportActionBar().setSelectedNavigationItem(lastUsedDaemonSettings);

            // Show the control bar
            startsettings.setVisibility(View.GONE);
            controlbar.setVisibility(View.VISIBLE);
            statusBox.setVisibility(View.GONE);
            activeLabel = null;
            inAlternativeMode = false; // TODO: Actually this should be retrieved from the server's session
            getSherlockActivity().supportInvalidateOptionsMenu();

        } else {

            daemon = null;

            // The 'set preferences first' screen is shown
            emptyText.setText(R.string.no_settings);

            // Show that no server configuration is currently active
            ignoreFirstListNavigation = true;
            getSherlockActivity().getSupportActionBar().setListNavigationCallbacks(null, onServerChanged);
            statusBox.setVisibility(View.GONE);
            viewtype.setText("");

            // Hide the control bar
            startsettings.setVisibility(View.VISIBLE);
            controlbar.setVisibility(View.GONE);
            activeLabel = null;
            getSherlockActivity().supportInvalidateOptionsMenu();

        }

    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);

        // Add the pause/resume/stop/start options
        Torrent selected = (Torrent) getTorrentListAdapter().getItem((int) ((AdapterContextMenuInfo) menuInfo).id);
        if (selected.canPause()) {
            menu.add(0, MENU_PAUSE_ID, 0, R.string.menu_pause);
        } else if (selected.canResume()) {
            menu.add(0, MENU_RESUME_ID, 0, R.string.menu_resume);
        }
        if (daemon != null && Daemon.supportsStoppingStarting(daemon.getType())) {
            if (selected.canStop()) {
                menu.add(0, MENU_STOP_ID, 0, R.string.menu_stop);
            } else if (selected.canStart()) {
                menu.add(0, MENU_START_ID, 0, R.string.menu_start);
            }
        }
        if (daemon != null && Daemon.supportsForcedStarting(daemon.getType()) && selected.canStart()) {
            menu.add(0, MENU_FORCESTART_ID, 0, R.string.menu_forcestart);
        }

        // Add the remove options
        menu.add(0, MENU_REMOVE_ID, 0, R.string.menu_remove);
        if (daemon != null && Daemon.supportsRemoveWithData(daemon.getType())) {
            menu.add(0, MENU_REMOVE_DATA_ID, 0, R.string.menu_remove_data);
        }

        // Add the 'set label' option
        if (daemon != null && Daemon.supportsSetLabel(daemon.getType())) {
            menu.add(0, MENU_SETLABEL_ID, 0, R.string.menu_setlabel);
        }

        // Add the 'set download location' option
        if (daemon != null && Daemon.supportsSetDownloadLocation(daemon.getType())) {
            menu.add(0, MENU_SETDOWNLOADLOCATION_ID, 0, R.string.menu_setdownloadlocation);
        }

    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

        // Add title bar buttons
        MenuItem miRefresh = menu.add(0, MENU_REFRESH_ID, 0, R.string.refresh);
        miRefresh.setIcon(R.drawable.icon_refresh_title);
        miRefresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
        if (inProgress) {
            // Show progress spinner instead of the option item
            View view = getActivity().getLayoutInflater().inflate(R.layout.part_actionbar_progressitem, null);
            miRefresh.setActionView(view);
        }
        MenuItem miSearch = menu.add(0, MENU_SEARCH_ID, 0, R.string.search);
        miSearch.setIcon(R.drawable.icon_search_title);
        miSearch.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
        MenuItem miAltMode = menu.add(0, MENU_ALTMODE_ID, 0, R.string.menu_altmode);
        miAltMode.setIcon(inAlternativeMode ? R.drawable.icon_turtle_title : R.drawable.icon_turtle_title_off);
        miAltMode.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
        miAltMode.setVisible(daemon != null && Daemon.supportsSetAlternativeMode(daemon.getType()));

        // Add the menu options row 1
        MenuItem miAdd = menu.add(0, MENU_ADD_ID, 0, R.string.menu_add);
        if (useTabletInterface) {
            miAdd.setIcon(R.drawable.icon_add);
        } else {
            miAdd.setIcon(android.R.drawable.ic_menu_add);
        }
        miAdd.setShortcut('1', 'a');
        miAdd.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        MenuItem miBarcode = menu.add(0, MENU_BARCODE_ID, 0, R.string.menu_scanbarcode);
        miBarcode.setIcon(R.drawable.icon_barcode);
        miBarcode.setShortcut('2', 'f');
        miBarcode.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        MenuItem miRss = menu.add(0, MENU_RSS_ID, 0, R.string.menu_rss);
        miRss.setIcon(R.drawable.icon_rss);
        miRss.setShortcut('3', 'r');
        miRss.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

        // Add the menu options row 2
        SubMenu miForAll = menu.addSubMenu(MENU_FORALL_GROUP_ID, MENU_FORALL_ID, 0, R.string.menu_forall);
        miForAll.setIcon(android.R.drawable.ic_menu_set_as);
        miForAll.add(MENU_FORALL_GROUP_ID, MENU_FORALL_PAUSE_ID, 0, R.string.menu_forall_pause).setShortcut('4',
                'p');
        miForAll.add(MENU_FORALL_GROUP_ID, MENU_FORALL_RESUME_ID, 0, R.string.menu_forall_resume).setShortcut('5',
                'u');
        miForAll.add(MENU_FORALL_GROUP_ID, MENU_FORALL_STOP_ID, 0, R.string.menu_forall_stop).setShortcut('7', 't');
        miForAll.add(MENU_FORALL_GROUP_ID, MENU_FORALL_START_ID, 0, R.string.menu_forall_start).setShortcut('8',
                's');

        menu.add(0, MENU_FILTER_ID, 0, R.string.menu_filter);

        SubMenu miSort = menu.addSubMenu(MENU_SORT_GROUP_ID, MENU_SORT_ID, 0, R.string.menu_sort);
        miSort.setIcon(android.R.drawable.ic_menu_sort_alphabetically);
        //miSort.setHeaderTitle(R.string.menu_sort_reverse);
        miSort.add(MENU_SORT_GROUP_ID, MENU_SORT_ALPHA_ID, 0, R.string.menu_sort_alpha).setAlphabeticShortcut('1')
                .setChecked(true);
        miSort.add(MENU_SORT_GROUP_ID, MENU_SORT_STATUS_ID, 0, R.string.menu_sort_status)
                .setAlphabeticShortcut('2');
        miSort.add(MENU_SORT_GROUP_ID, MENU_SORT_ADDED_ID, 0, R.string.menu_sort_added).setAlphabeticShortcut('3');
        miSort.add(MENU_SORT_GROUP_ID, MENU_SORT_DONE_ID, 0, R.string.menu_sort_done).setAlphabeticShortcut('4');
        miSort.add(MENU_SORT_GROUP_ID, MENU_SORT_UPSPEED_ID, 0, R.string.menu_sort_upspeed)
                .setAlphabeticShortcut('5');
        miSort.add(MENU_SORT_GROUP_ID, MENU_SORT_RATIO_ID, 0, R.string.menu_sort_ratio).setAlphabeticShortcut('6');
        miSort.setGroupCheckable(MENU_SORT_GROUP_ID, true, true);
        miSort.add(MENU_SORT_GTZERO_ID, MENU_SORT_GTZERO_ID, 0, R.string.menu_sort_onlytransferring)
                .setCheckable(true);

        // Add the extras menu options
        MenuItem miSpeeds = menu.add(0, MENU_RATES_ID, 0, R.string.menu_speeds);
        miSpeeds.setNumericShortcut('6');
        miSpeeds.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        MenuItem miSwitch = menu.add(0, MENU_SWITCH_ID, 0, R.string.menu_servers);
        miSwitch.setShortcut('9', 'h');
        miSwitch.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        menu.add(0, MENU_ERRORREPORT_ID, 0, R.string.menu_errorreport);
        menu.add(0, MENU_CHANGELOG_ID, 0, R.string.menu_changelog);
        MenuItem miSettings = menu.add(0, MENU_SETTINGS_ID, 0, R.string.menu_settings);
        //miSettings.setIcon(android.R.drawable.ic_menu_preferences);
        miSettings.setNumericShortcut('0');
        miSettings.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

    }

    @Override
    public void onPrepareOptionsMenu(Menu menu) {
        boolean ok = daemon != null;
        menu.findItem(MENU_ADD_ID).setEnabled(ok);
        menu.findItem(MENU_BARCODE_ID).setEnabled(ok);
        menu.findItem(MENU_RSS_ID).setEnabled(ok);
        menu.findItem(MENU_FORALL_ID).setEnabled(ok);
        menu.findItem(MENU_FILTER_ID).setEnabled(ok);
        menu.findItem(MENU_SORT_ID).setEnabled(ok);
        if (ok) {
            menu.findItem(MENU_ALTMODE_ID).setVisible(Daemon.supportsSetAlternativeMode(daemon.getType()));
            /*menu.findItem(MENU_SORT_ADDED_ID).setVisible(Daemon.supportsDateAdded(daemon.getType()));
            menu.findItem(MENU_FORALL_STOP_ID).setVisible(Daemon.supportsStoppingStarting(daemon.getType()));
            menu.findItem(MENU_FORALL_START_ID).setVisible(Daemon.supportsStoppingStarting(daemon.getType()));
                
            // Show the currently selected sort by option
            SubMenu sortmenu = menu.findItem(MENU_SORT_ID).getSubMenu();
            for (int i = 0; i < sortmenu.size(); i++) {
               if (sortmenu.getItem(i).getItemId() == MENU_SORT_ALPHA_ID && sortSetting == TorrentsSortBy.Alphanumeric) {
                  sortmenu.getItem(i).setChecked(true);
                  break;
               } else if (sortmenu.getItem(i).getItemId() == MENU_SORT_STATUS_ID && sortSetting == TorrentsSortBy.Status) {
                  sortmenu.getItem(i).setChecked(true);
                  break;
               } else if (sortmenu.getItem(i).getItemId() == MENU_SORT_ADDED_ID && sortSetting == TorrentsSortBy.DateAdded) {
                  sortmenu.getItem(i).setChecked(true);
                  break;
               } else if (sortmenu.getItem(i).getItemId() == MENU_SORT_DONE_ID && sortSetting == TorrentsSortBy.DateDone) {
                  sortmenu.getItem(i).setChecked(true);
                  break;
               } else if (sortmenu.getItem(i).getItemId() == MENU_SORT_UPSPEED_ID && sortSetting == TorrentsSortBy.UploadSpeed) {
                  sortmenu.getItem(i).setChecked(true);
                  break;
               } else if (sortmenu.getItem(i).getItemId() == MENU_SORT_RATIO_ID && sortSetting == TorrentsSortBy.Ratio) {
                  sortmenu.getItem(i).setChecked(true);
                  break;
               }
            }
                
            // Show the checkbox status according to the current settings
            menu.findItem(MENU_SORT_GTZERO_ID).setChecked(onlyShowTransferring);*/
        }
    }

    @Override
    public boolean onContextItemSelected(android.view.MenuItem item) {
        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();

        if (daemon == null) {
            // No connection possible yet: give message
            Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
            return true;
        }

        // Get torrent item (if it still exists)
        if (getTorrentListAdapter().getCount() <= info.id)
            return true;
        Torrent selection = (Torrent) getTorrentListAdapter().getItem((int) info.id);

        switch (item.getItemId()) {
        case MENU_PAUSE_ID:

            // Set an intermediate status first (for a response feel)
            selection.mimicPause();
            // Update adapter
            getTorrentListAdapter().notifyDataSetChanged();

            queue.enqueue(PauseTask.create(daemon, selection));
            return true;

        case MENU_RESUME_ID:

            // Set an intermediate status first (for a response feel)
            selection.mimicResume();
            // Update adapter
            getTorrentListAdapter().notifyDataSetChanged();

            queue.enqueue(ResumeTask.create(daemon, selection));
            queue.enqueue(RetrieveTask.create(daemon));
            return true;

        case MENU_STOP_ID:

            // Set an intermediate status first (for a response feel)
            selection.mimicStop();
            // Update adapter
            getTorrentListAdapter().notifyDataSetChanged();

            queue.enqueue(StopTask.create(daemon, selection));
            return true;

        case MENU_START_ID:

            // Set an intermediate status first (for a response feel)
            selection.mimicStart();
            // Update adapter
            getTorrentListAdapter().notifyDataSetChanged();

            queue.enqueue(StartTask.create(daemon, selection, false));
            queue.enqueue(RetrieveTask.create(daemon));
            return true;

        case MENU_FORCESTART_ID:

            // Set an intermediate status first (for a response feel)
            selection.mimicStart();
            // Update adapter
            getTorrentListAdapter().notifyDataSetChanged();

            queue.enqueue(StartTask.create(daemon, selection, true));
            queue.enqueue(RetrieveTask.create(daemon));
            return true;

        case MENU_REMOVE_ID:

            if (interfaceSettings.getAskBeforeRemove()) {
                // We store the torrent that we selected so the dialog can use this to make its calls
                selectedTorrent = selection;
                selectedRemoveData = false;
                showDialog(DIALOG_ASKREMOVE);
            } else {
                removeTorrentOnServer(selection, false);
            }
            return true;

        case MENU_REMOVE_DATA_ID:

            if (interfaceSettings.getAskBeforeRemove()) {
                // We store the torrent that we selected so the dialog can use this to make its calls
                selectedTorrent = selection;
                selectedRemoveData = true;
                showDialog(DIALOG_ASKREMOVE);
            } else {
                removeTorrentOnServer(selection, true);
            }
            return true;

        case MENU_SETLABEL_ID:

            // Store the torrent that we selected and open the set label dialog
            selectedTorrent = selection;
            showDialog(DIALOG_SETLABEL);
            return true;

        case MENU_SETDOWNLOADLOCATION_ID:

            // Store the torrent that we selected and open the set download location dialog
            selectedTorrent = selection;
            showDialog(DIALOG_SETDOWNLOADLOCATION);
            return true;

        }
        return super.onContextItemSelected(item);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        // Check connection first (when not opening the settings)
        if (item.getItemId() != MENU_SETTINGS_ID && item.getItemId() != MENU_CHANGELOG_ID && daemon == null) {
            // No connection possible yet: give message
            Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
            return true;
        }

        switch (item.getItemId()) {
        /*case android.R.id.home:
               
           // Home button click in the action bar
           Intent i = new Intent(getActivity(), Torrents.class);
           i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
           startActivity(i);
           break;*/

        case MENU_REFRESH_ID:

            refreshActivity();
            break;

        case MENU_SEARCH_ID:
            getSherlockActivity().onSearchRequested();
            break;

        case MENU_ALTMODE_ID:

            switchAlternativeMode();
            break;

        case MENU_FORALL_PAUSE_ID:

            if (allTorrents != null && allTorrents.size() > 0) {

                // Set an intermediate status first on all items (for a response feel)
                for (Torrent torrent : allTorrents) {
                    torrent.mimicPause();
                }
                // Update adapter
                getTorrentListAdapter().notifyDataSetChanged();

                queue.enqueue(PauseAllTask.create(daemon));

            }
            break;

        case MENU_FORALL_RESUME_ID:

            if (allTorrents != null && allTorrents.size() > 0) {

                // Set an intermediate status first on all items (for a response feel)
                for (Torrent torrent : allTorrents) {
                    torrent.mimicResume();
                }
                // Update adapter
                getTorrentListAdapter().notifyDataSetChanged();

                queue.enqueue(ResumeAllTask.create(daemon));
                queue.enqueue(RetrieveTask.create(daemon));

            }
            break;

        case MENU_FORALL_STOP_ID:

            if (allTorrents != null && allTorrents.size() > 0
                    && Daemon.supportsStoppingStarting(daemon.getType())) {

                // Set an intermediate status first on all items (for a response feel)
                for (Torrent torrent : allTorrents) {
                    torrent.mimicStop();
                }
                // Update adapter
                getTorrentListAdapter().notifyDataSetChanged();

                queue.enqueue(StopAllTask.create(daemon));

            }
            break;

        case MENU_FORALL_START_ID:

            if (allTorrents != null && allTorrents.size() > 0
                    && Daemon.supportsStoppingStarting(daemon.getType())) {

                // Set an intermediate status first on all items (for a response feel)
                for (Torrent torrent : allTorrents) {
                    torrent.mimicStart();
                }
                // Update adapter
                getTorrentListAdapter().notifyDataSetChanged();

                queue.enqueue(StartAllTask.create(daemon, false));
                queue.enqueue(RetrieveTask.create(daemon));

            }
            break;

        case MENU_ADD_ID:

            // Show a torrent URL input screen;
            startActivity(new Intent(getActivity(), Add.class));
            break;

        case MENU_BARCODE_ID:

            startBarcodeScanner();
            break;

        case MENU_RSS_ID:

            // Show the RSS feeds screen
            startActivity(new Intent(getActivity(), RssFeeds.class));
            break;

        case MENU_SWITCH_ID:

            // Present a dialog with all available servers
            showDialog(DIALOG_SERVERS);
            break;

        case MENU_SETTINGS_ID:

            // Open settings menu
            startActivityForResult(new Intent(getActivity(), PreferencesMain.class), ACTIVITY_PREFERENCES);
            break;

        case MENU_RATES_ID:

            // Present a dialog that allows the setting of maxium transfer rates
            showDialog(DIALOG_RATES);
            break;

        case MENU_CHANGELOG_ID:

            // Present a dialog that shows version information and recent changes
            showDialog(DIALOG_CHANGELOG);
            break;

        case MENU_ERRORREPORT_ID:

            ErrorLogSender.collectAndSendLog(getActivity(), daemon, allDaemonSettings.get(lastUsedDaemonSettings));
            break;

        case MENU_FILTER_ID:
            // Present a dialog that allows filtering the list
            showDialog(DIALOG_FILTER);
            break;

        case MENU_SORT_ALPHA_ID:

            // Resort
            item.setChecked(true);
            newTorrentListSorting(TorrentsSortBy.Alphanumeric);
            break;

        case MENU_SORT_STATUS_ID:

            // Resort
            item.setChecked(true);
            newTorrentListSorting(TorrentsSortBy.Status);
            break;

        case MENU_SORT_DONE_ID:

            // Resort
            item.setChecked(true);
            newTorrentListSorting(TorrentsSortBy.DateDone);
            break;

        case MENU_SORT_UPSPEED_ID:

            // Resort
            item.setChecked(true);
            newTorrentListSorting(TorrentsSortBy.UploadSpeed);
            break;

        case MENU_SORT_RATIO_ID:

            // Resort
            item.setChecked(true);
            newTorrentListSorting(TorrentsSortBy.Ratio);
            break;

        case MENU_SORT_ADDED_ID:

            if (Daemon.supportsDateAdded(daemon.getType())) {

                // Resort
                item.setChecked(true);
                newTorrentListSorting(TorrentsSortBy.DateAdded);

            }
            break;

        case MENU_SORT_GTZERO_ID:

            // Set boolean to filter on only transferring (> 0 KB/s) torrents
            item.setChecked(!item.isChecked());
            onlyShowTransferring = item.isChecked();

            updateTorrentsView(true);

            break;

        }
        return super.onOptionsItemSelected(item);
    }

    private OnItemClickListener onTorrentClicked = new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> arg0, View v, int position, long id) {
            if (getTorrentListAdapter() != null) {

                Torrent tor = getTorrentListAdapter().getItem(position);

                // Show the details in the right of the screen (tablet interface) or separately
                if (useTabletInterface) {
                    FragmentTransaction ft = getSherlockActivity().getSupportFragmentManager().beginTransaction();
                    ft.replace(R.id.details, new DetailsFragment(TorrentsFragment.this, lastUsedDaemonSettings, tor,
                            buildLabelTexts(false)));
                    ft.commit();
                } else {
                    Intent i = new Intent(getActivity(), Details.class);
                    i.putExtra(Details.STATE_DAEMON, lastUsedDaemonSettings);
                    i.putExtra(Details.STATE_LABELS, buildLabelTexts(false));
                    i.putExtra(Details.STATE_TORRENT, tor);
                    startActivityForResult(i, ACTIVITY_DETAILS);
                }

            }
        }
    };

    private void startBarcodeScanner() {

        // Test to see if the ZXing barcode scanner is available that can handle the SCAN intent
        Intent scan = new Intent(Transdroid.SCAN_INTENT);
        scan.addCategory(Intent.CATEGORY_DEFAULT);
        if (ActivityUtil.isIntentAvailable(getActivity(), scan)) {
            // Ask the barcode scanner to allow the user to scan some code
            startActivityForResult(scan, ACTIVITY_BARCODE);
        } else {
            // Show a message if the user should install the barcode scanner for this feature
            showDialog(DIALOG_INSTALLBARCODESCANNER);
        }

    }

    protected Dialog onCreateDialog(int id) {

        switch (id) {
        case DIALOG_SERVERS:

            // Build a dialog with a radio box per daemon configuration
            AlertDialog.Builder serverDialog = new AlertDialog.Builder(getActivity());
            serverDialog.setTitle(R.string.menu_servers);
            serverDialog.setSingleChoiceItems(buildServerTextsForDialog(), // The strings of the available server configurations 
                    (lastUsedDaemonSettings < allDaemonSettings.size() ? lastUsedDaemonSettings : 0), // The current selection except when this suddenly doesn't exist any more 
                    new DialogInterface.OnClickListener() {

                        @Override
                        // When the server is clicked (and it is different from the current active configuration), 
                        // reload the daemon and update the torrent list
                        public void onClick(DialogInterface dialog, int which) {
                            if (which != lastUsedDaemonSettings) {
                                switchDaemonConfig(which);
                            }
                            dismissDialog(DIALOG_SERVERS);
                        }
                    });
            return serverDialog.create();

        case DIALOG_REFRESH_INTERVAL:

            // Build a dialog with a radio boxes of different refresh intervals to choose from
            AlertDialog.Builder refintDialog = new AlertDialog.Builder(getActivity());
            refintDialog.setTitle(R.string.pref_uirefresh);
            refintDialog.setSingleChoiceItems(R.array.pref_uirefresh_types, getCurrentRefreshIntervalID(),
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            // Store new refresh interval
                            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
                            Preferences.storeNewRefreshInterval(prefs,
                                    getResources().getStringArray(R.array.pref_uirefresh_values)[which]);
                            interfaceSettings = Preferences.readInterfaceSettings(prefs);
                            // Apply new refresh interval
                            handler.removeCallbacks(refreshRunable); // Stops refresh timer
                            setupRefreshTimer();
                            dismissDialog(DIALOG_REFRESH_INTERVAL);
                        }
                    });
            return refintDialog.create();

        case DIALOG_SETLABEL:

            // Build a dialog that asks for a new or selected an existing label to assign to the selected torrent
            String[] setLabelTexts = buildLabelTexts(false);
            SetLabelDialog setLabelDialog = new SetLabelDialog(getActivity(), new ResultListener() {
                @Override
                public void onLabelResult(String newLabel) {
                    if (newLabel.equals(getString(R.string.labels_unlabeled).toString())) {
                        // Setting a torrent to 'unlabeled' is actually setting the label to an empty string
                        newLabel = "";
                    }
                    setNewLabel(newLabel);
                }
            }, setLabelTexts, selectedTorrent.getLabelName());
            setLabelDialog.setTitle(R.string.labels_newlabel);

            return setLabelDialog;

        case DIALOG_SETDOWNLOADLOCATION:

            // Build a dialog that asks for a new download location for the torrent
            final View setLocationLayout = getActivity().getLayoutInflater()
                    .inflate(R.layout.dialog_set_download_location, null);
            final EditText newLocation = (EditText) setLocationLayout.findViewById(R.id.download_location);
            newLocation.setText(selectedTorrent.getLocationDir());
            AlertDialog.Builder setLocationDialog = new AlertDialog.Builder(getActivity());
            setLocationDialog.setTitle(R.string.menu_setdownloadlocation);
            setLocationDialog.setView(setLocationLayout);
            setLocationDialog.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface arg0, int arg1) {

                    setDownloadLocation(newLocation.getText().toString());
                }
            });
            setLocationDialog.setNegativeButton(android.R.string.cancel, null);
            return setLocationDialog.create();

        case DIALOG_RATES:

            // Build a dialog that allows for the input of maximum upload and download transfer rates
            final View ratesDialogView = getActivity().getLayoutInflater().inflate(R.layout.dialog_transfer_rates,
                    null);
            final EditText rateDownload = (EditText) ratesDialogView.findViewById(R.id.rate_download);
            final EditText rateUpload = (EditText) ratesDialogView.findViewById(R.id.rate_upload);
            AlertDialog.Builder ratesDialog = new AlertDialog.Builder(getActivity());
            ratesDialog.setTitle(R.string.menu_speeds);
            ratesDialog.setView(ratesDialogView);
            ratesDialog.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    setTransferRates(
                            (rateUpload.getText().toString().equals("") ? null
                                    : Integer.parseInt(rateUpload.getText().toString())),
                            (rateDownload.getText().toString().equals("") ? null
                                    : Integer.parseInt(rateDownload.getText().toString())));
                }
            });
            ratesDialog.setNeutralButton(R.string.rate_reset, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    // Reset the text boxes first
                    rateUpload.setText("");
                    rateDownload.setText("");
                    setTransferRates(null, null);
                }
            });
            ratesDialog.setNegativeButton(android.R.string.cancel, null);

            return ratesDialog.create();

        case DIALOG_CHANGELOG:

            // Build a dialog listing the recent changes in Transdroid
            AlertDialog.Builder changesDialog = new AlertDialog.Builder(getActivity());
            changesDialog.setTitle(R.string.menu_changelog);
            View changes = getActivity().getLayoutInflater().inflate(R.layout.dialog_about, null);
            ((TextView) changes.findViewById(R.id.transdroid))
                    .setText("Transdroid " + ActivityUtil.getVersionNumber(getActivity()));
            changesDialog.setView(changes);
            return changesDialog.create();

        case DIALOG_ASKREMOVE:

            // Build a dialog that asks to confirm the deletions of a torrent
            AlertDialog.Builder askRemoveDialog = new AlertDialog.Builder(getActivity());
            askRemoveDialog.setTitle(R.string.askremove_title);
            askRemoveDialog.setMessage(R.string.askremove);
            askRemoveDialog.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface arg0, int arg1) {
                    removeTorrentOnServer(selectedTorrent, selectedRemoveData);
                    dismissDialog(DIALOG_ASKREMOVE);
                }
            });
            askRemoveDialog.setNegativeButton(android.R.string.no, null);
            return askRemoveDialog.create();

        case DIALOG_ADDFAILED:

            // Build a dialog that asks to retry or store this torrent and add it later
            AlertDialog.Builder addFailedDialog = new AlertDialog.Builder(getActivity());
            addFailedDialog.setTitle(R.string.addfailed_title);
            if (alarmServiceSettings.isAlarmEnabled()) {
                addFailedDialog.setMessage(getString(R.string.addfailed_service2, failedTorrentTitle));
                addFailedDialog.setNeutralButton(R.string.addfailed_addlater,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface arg0, int arg1) {
                                Preferences.addToTorrentAddQueue(
                                        PreferenceManager.getDefaultSharedPreferences(getActivity()),
                                        daemon.getSettings().getIdString(), failedTorrentUri);
                                dismissDialog(DIALOG_ADDFAILED);
                            }
                        });
            } else {
                addFailedDialog.setMessage(getString(R.string.addfailed_noservice2, failedTorrentTitle));
            }
            addFailedDialog.setPositiveButton(R.string.addfailed_retry, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface arg0, int arg1) {
                    if (Preferences.isQueuedTorrentToAddALocalFile(failedTorrentUri)) {
                        addTorrentByFile(failedTorrentUri);
                    } else if (Preferences.isQueuedTorrentToAddAMagnetUrl(failedTorrentUri)) {
                        addTorrentByMagnetUrl(failedTorrentUri);
                    } else {
                        addTorrentByUrl(failedTorrentUri, failedTorrentTitle);
                    }
                    dismissDialog(DIALOG_ADDFAILED);
                }
            });
            addFailedDialog.setNegativeButton(android.R.string.no, null);
            return addFailedDialog.create();

        case DIALOG_INSTALLBARCODESCANNER:
            return ActivityUtil.buildInstallDialog(getActivity(), R.string.scanner_not_found,
                    Transdroid.SCANNER_MARKET_URI);

        case DIALOG_FILTER:
            // Build a dialog that asks for a new download location for the torrent
            final View setFilterLayout = getActivity().getLayoutInflater().inflate(R.layout.dialog_set_filter,
                    null);
            final EditText newFilter = (EditText) setFilterLayout.findViewById(R.id.filter);
            if (activeFilter != null)
                newFilter.setText(activeFilter);
            AlertDialog.Builder setFilterDialog = new AlertDialog.Builder(getActivity());
            setFilterDialog.setTitle(R.string.menu_setfilter);
            setFilterDialog.setView(setFilterLayout);
            setFilterDialog.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface arg0, int arg1) {

                    setFilter(newFilter.getText().toString());
                }
            });
            setFilterDialog.setNegativeButton(android.R.string.cancel, null);
            setFilterDialog.setNeutralButton(R.string.reset, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface arg0, int arg1) {
                    setFilter("");
                }
            });
            return setFilterDialog.create();
        }
        return null;

    }

    /*@Override
    protected void onPrepareDialog(int id, Dialog dialog) {
       super.onPrepareDialog(id, dialog);
           
       switch (id) {
       case DIALOG_SERVERS:
         
     // Re-populate the dialog adapter with possibly new/edited server configurations
     AlertDialog serverDialog = (AlertDialog) dialog;
     ListView serverRadios = serverDialog.getListView();
     ArrayAdapter<String> serverList = new ArrayAdapter<String>(this, android.R.layout.select_dialog_singlechoice, android.R.id.text1, buildServerTextsForDialog());
     serverRadios.setAdapter(serverList);
         
     // Also pre-select the active daemon
     int serverSelected = (lastUsedDaemonSettings < allDaemonSettings.size()? lastUsedDaemonSettings: 0); // Prevent going out of bounds
     serverRadios.clearChoices();
     serverRadios.setItemChecked(serverSelected, true);
     serverRadios.setSelection(serverSelected);
     break;
        
       case DIALOG_REFRESH_INTERVAL:
         
     // Pre-select the current refresh interval
     AlertDialog refintDialog = (AlertDialog) dialog;
     ListView refintRadios = refintDialog.getListView();
     refintRadios.clearChoices();
     refintRadios.setItemChecked(getCurrentRefreshIntervalID(), true);
     refintRadios.setSelection(getCurrentRefreshIntervalID());
     break;
        
       case DIALOG_SETLABEL:
        
     // Re-populate the dialog adapter with the available labels
     SetLabelDialog setLabelDialog = (SetLabelDialog) dialog;
     String[] setLabelTexts = buildLabelTexts(false);
     setLabelDialog.resetDialog(this, setLabelTexts, selectedTorrent.getLabelName());
     break;
         
       case DIALOG_SETDOWNLOADLOCATION:
         
     // Show the existing download location
     final EditText newLocation = (EditText) dialog.findViewById(R.id.download_location);
     newLocation.setText(selectedTorrent.getLocationDir());
     break;
         
       case DIALOG_ADDFAILED:
        
     AlertDialog addFailedDialog = (AlertDialog) dialog;
     if (alarmServiceSettings.isAlarmEnabled()) {
        addFailedDialog.setMessage(getString(R.string.addfailed_service2, failedTorrentTitle));
        addFailedDialog.setButton2(getText(R.string.addfailed_addlater), new DialogInterface.OnClickListener() {
           @Override
           public void onClick(DialogInterface arg0, int arg1) {
              Preferences.addToTorrentAddQueue(PreferenceManager.getDefaultSharedPreferences(TorrentsFragment.this), 
                    daemon.getSettings().getIdString(), failedTorrentUri);
              removeDialog(DIALOG_ADDFAILED);
           }
        });
     } else {
        addFailedDialog.setMessage(getString(R.string.addfailed_noservice2, failedTorrentTitle));
        addFailedDialog.setButton2(null, (DialogInterface.OnClickListener)null);
     }
     break;
       }
    }*/

    private SpinnerAdapter buildServerListAdapter() {
        ArrayAdapter<String> ad = new ArrayAdapter<String>(getActivity(), R.layout.abs__simple_spinner_item,
                buildServerTextsForDialog());
        ad.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        return ad;
    }

    private String[] buildServerTextsForDialog() {

        // Build a textual list of servers available
        ArrayList<String> servers = new ArrayList<String>();
        for (DaemonSettings daemon : allDaemonSettings) {
            servers.add(daemon.getName());
        }
        return servers.toArray(new String[servers.size()]);

    }

    private int getCurrentRefreshIntervalID() {
        String[] values = getResources().getStringArray(R.array.pref_uirefresh_values);
        int current = interfaceSettings.getRefreshTimerInterval();
        for (int i = 0; i < values.length; i++) {
            if (values[i].equals(Integer.toString(current))) {
                return i;
            }
        }
        return 0;
    }

    private String[] buildLabelTexts(boolean addShowAll) {

        // Build a textual list of used torrent labels
        ArrayList<String> labelNames = new ArrayList<String>();
        if (availableLabels != null) {
            // The 'show all' label first ...
            String showAll = getText(R.string.labels_showall).toString();
            if (addShowAll) {
                labelNames.add(showAll);
            }
            // ... then all the normal labels (which will end up in alphabetical order)
            for (String name : availableLabels) {
                if (!name.equals(showAll)) {
                    labelNames.add(name);
                }
            }
        }
        return labelNames.toArray(new String[labelNames.size()]);

    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
        case ACTIVITY_PREFERENCES:

            // Preference screen was called: use new preferences to connect
            readSettings();
            setupDaemon();
            updateTorrentList();
            break;

        case ACTIVITY_DETAILS:

            // Details screen was shown; we may have an updated torrent (it can be started/removed/etc.)
            updateTorrentList();
            break;

        case ACTIVITY_BARCODE:

            if (resultCode == Activity.RESULT_OK) {

                // Get scan results code
                String contents = data.getStringExtra("SCAN_RESULT");
                String formatName = data.getStringExtra("SCAN_RESULT_FORMAT");

                if (formatName != null && formatName.equals(Transdroid.SCAN_FORMAT_QRCODE)) {
                    // Scanned barcode was a QR code: assume the contents contain a URL to a .torrent file
                    TLog.d(LOG_NAME, "Add torrent from QR code url '" + contents + "'");
                    addTorrentByUrl(contents, "Torrent QR code"); // No real torrent title known
                } else {
                    // Get a meaningful search query based on a Google Search product lookup
                    TLog.d(LOG_NAME,
                            "Starting barcode lookup for code '" + contents + "' "
                                    + (formatName == null ? "(code type is unknown)"
                                            : "(this should be a " + formatName + " code)"));
                    setProgressBar(true);
                    new GoogleWebSearchBarcodeResolver() {
                        @Override
                        protected void onBarcodeLookupComplete(String result) {

                            setProgressBar(false);

                            // No proper result?
                            if (result == null || result.equals("")) {
                                TLog.d(LOG_NAME, "Barcode not resolved (timout, connection error, no items, etc.)");
                                Toast.makeText(getActivity(), R.string.no_results, Toast.LENGTH_SHORT).show();
                                return;
                            }

                            // Open TransdroidSearch directly, mimicking a search query
                            TLog.d(LOG_NAME, "Barcode resolved to '" + result + "'. Now starting search.");
                            Intent search = new Intent(getActivity(), Search.class);
                            search.setAction(Intent.ACTION_SEARCH);
                            search.putExtra(SearchManager.QUERY, result);
                            startActivity(search);

                        }
                    }.execute(contents);
                }

            }
            break;
        }
    }

    private void refreshActivity() {
        updateTorrentList();
        if (getSherlockActivity().getSupportFragmentManager().findFragmentById(R.id.details) != null) {
            // Marshal the refresh button click to the fragment
            ((DetailsFragment) getSherlockActivity().getSupportFragmentManager().findFragmentById(R.id.details))
                    .refreshActivity();
        }
    }

    public void updateTorrentList() {
        if (daemon != null) {
            queue.enqueue(RetrieveTask.create(daemon));
            if (Daemon.supportsStats(daemon.getType())) {
                queue.enqueue(GetStatsTask.create(daemon));
            }
        }
    }

    private void addTorrentByUrl(String url, String title) {

        if (daemon == null) {
            // No connection possible yet: give message
            Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
            return;
        }

        queue.enqueue(AddByUrlTask.create(daemon, url, title));
        queue.enqueue(RetrieveTask.create(daemon));
    }

    private void addTorrentByMagnetUrl(String url) {

        if (daemon == null) {
            // No connection possible yet: give message
            Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
            return;
        }

        if (!Daemon.supportsAddByMagnetUrl(daemon.getType())) {
            // Not supported by the torrent client
            Toast.makeText(getActivity(), R.string.no_magnet_links, Toast.LENGTH_SHORT).show();
            return;
        }

        queue.enqueue(AddByMagnetUrlTask.create(daemon, url));
        queue.enqueue(RetrieveTask.create(daemon));

    }

    private void addTorrentFromDownloads(Uri contentUri) {

        InputStream input = null;
        try {
            // Open the content uri as input stream
            input = getActivity().getContentResolver().openInputStream(contentUri);

            // Write a temporary file with the torrent contents
            File tempFile = File.createTempFile("transdroid_", ".torrent", getActivity().getCacheDir());
            FileOutputStream output = new FileOutputStream(tempFile);
            try {
                final byte[] buffer = new byte[1024];
                int read;
                while ((read = input.read(buffer)) != -1)
                    output.write(buffer, 0, read);
                output.flush();
                addTorrentByFile(Uri.fromFile(tempFile).toString());
            } finally {
                output.close();
            }
        } catch (SecurityException e) {
            // No longer access to this file
            Toast.makeText(getActivity(), R.string.error_torrentfile, Toast.LENGTH_SHORT).show();
        } catch (IOException e1) {
            // Can't write temporary file
            Toast.makeText(getActivity(), R.string.error_torrentfile, Toast.LENGTH_SHORT).show();
        } finally {
            try {
                if (input != null)
                    input.close();
            } catch (IOException e) {
                Toast.makeText(getActivity(), R.string.error_torrentfile, Toast.LENGTH_SHORT).show();
            }
        }
    }

    private void addTorrentByFile(String fileUri) {

        if (daemon == null) {
            // No connection possible yet: give message
            if (getActivity() != null) {
                Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
            }
            return;
        }

        if (!Daemon.supportsAddByFile(daemon.getType())) {
            // The daemon type does not support .torrent file uploads/metadata sending or this is not yet implemented
            if (getActivity() != null) {
                Toast.makeText(getActivity(), R.string.no_file_uploads, Toast.LENGTH_LONG).show();
            }
            return;
        }

        queue.enqueue(AddByFileTask.create(daemon, fileUri));
        queue.enqueue(RetrieveTask.create(daemon));

    }

    private void removeTorrentOnServer(Torrent torrent, boolean removeData) {

        // Remove the list item first (for a responsive feel) from views and labels
        getTorrentListAdapter().remove(torrent);
        updateEmptyListDescription();

        // Remove the torrent from the server
        queue.enqueue(RemoveTask.create(daemon, torrent, removeData));

    }

    private void setTransferRates(Integer uploadRate, Integer downloadRate) {

        if (daemon == null) {
            // No connection possible yet: give message
            Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
            return;
        }

        if (!Daemon.supportsSetTransferRates(daemon.getType())) {
            // The daemon type does not support adjusting the maximum transfer rates
            Toast.makeText(getActivity(), R.string.rate_no_support, Toast.LENGTH_LONG).show();
            return;
        }

        queue.enqueue(SetTransferRatesTask.create(daemon, uploadRate, downloadRate));

    }

    private void setNewLabel(String newLabel) {

        if (daemon == null) {
            // No connection possible yet: give message
            Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
            return;
        }

        if (!Daemon.supportsSetLabel(daemon.getType())) {
            // The daemon type does not support setting the label of a torrent
            Toast.makeText(getActivity(), R.string.labels_no_support, Toast.LENGTH_LONG).show();
            return;
        }

        // Mimic that we have already set the label (for a response feel)
        selectedTorrent.mimicNewLabel(newLabel);

        queue.enqueue(SetLabelTask.create(daemon, selectedTorrent, newLabel));
        queue.enqueue(RetrieveTask.create(daemon));

    }

    private void setDownloadLocation(String newLocation) {

        if (daemon == null) {
            // No connection possible yet: give message
            Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
            return;
        }

        if (!Daemon.supportsSetDownloadLocation(daemon.getType())) {
            return;
        }

        queue.enqueue(SetDownloadLocationTask.create(daemon, selectedTorrent, newLocation));

    }

    protected void switchAlternativeMode() {

        if (daemon == null) {
            // No connection possible yet: give message
            Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
            return;
        }

        if (!Daemon.supportsSetAlternativeMode(daemon.getType())) {
            return;
        }

        inAlternativeMode = !inAlternativeMode;
        updateAlternativeModeIcon();
        queue.enqueue(SetAlternativeModeTask.create(daemon, inAlternativeMode));

    }

    @Override
    public void onQueuedTaskFinished(DaemonTask started) {

        // Show the daemon status (speeds) again
        updateStatusText(null);

    }

    @Override
    public void onQueuedTaskStarted(DaemonTask started) {

        // Started on a new task: turn on status indicator
        setProgressBar(true);
        // Show which task we are executing
        updateStatusText(getStatusFromTask(started).toString());

    }

    @Override
    public void onQueueEmpty() {

        // No active task: turn off status indicator
        setProgressBar(false);

    }

    private CharSequence getStatusFromTask(DaemonTask started) {
        switch (started.getMethod()) {
        case Retrieve:
            return getText(R.string.task_refreshing);
        case AddByUrl:
            return getText(R.string.task_addbyurl);
        case AddByMagnetUrl:
            return getText(R.string.task_addbyurl);
        case AddByFile:
            return getText(R.string.task_addbyfile);
        case Remove:
            return getText(R.string.task_removing);
        case Pause:
            return getText(R.string.task_pausing);
        case PauseAll:
            return getText(R.string.task_pausingall);
        case Resume:
            return getText(R.string.task_resuming);
        case ResumeAll:
            return getText(R.string.task_resumingall);
        case Stop:
            return getText(R.string.task_stopping);
        case StopAll:
            return getText(R.string.task_stoppingall);
        case Start:
            return getText(R.string.task_starting);
        case StartAll:
            return getText(R.string.task_startingall);
        case GetFileList:
            return getText(R.string.task_getfiles);
        case SetFilePriorities:
            return getText(R.string.task_setfileprop);
        case SetTransferRates:
            return getText(R.string.task_settransrates);
        case SetLabel:
            return getText(R.string.task_setlabel);
        case SetDownloadLocation:
            return getText(R.string.task_setlocation);
        case SetAlternativeMode:
            return getText(R.string.task_setalternativemode);
        }
        return "";
    }

    @Override
    public boolean isAttached() {
        return getActivity() != null;
    }

    @Override
    public void onTaskFailure(DaemonTaskFailureResult result) {

        if (result.getMethod() == DaemonMethod.Retrieve) {
            // For retrieve tasks: Only bother if we still are still looking at the same daemon since the task was queued
            if (result.getTask().getAdapterType() == daemon.getType()) {
                // Show error message
                Toast.makeText(getActivity(), LocalTorrent.getResourceForDaemonException(result.getException()),
                        Toast.LENGTH_SHORT * 2).show();
            }

        } else if (result.getMethod() == DaemonMethod.AddByFile) {
            // Failed adding a torrent? Ask to add this torrent later
            failedTorrentUri = ((AddByFileTask) result.getTask()).getFile();
            failedTorrentTitle = new File(failedTorrentUri).getName(); // Use filename as title
            showDialog(DIALOG_ADDFAILED);

        } else if (result.getMethod() == DaemonMethod.AddByUrl) {
            // Failed adding a torrent? Ask to add this torrent later
            failedTorrentUri = ((AddByUrlTask) result.getTask()).getUrl();
            failedTorrentTitle = ((AddByUrlTask) result.getTask()).getTitle(); // Get title directly from task
            showDialog(DIALOG_ADDFAILED);

        } else if (result.getMethod() == DaemonMethod.AddByMagnetUrl) {
            // Failed adding a torrent? Ask to add this torrent later
            failedTorrentUri = ((AddByMagnetUrlTask) result.getTask()).getUrl();
            failedTorrentTitle = "Torrent"; // No way to know the title here
            showDialog(DIALOG_ADDFAILED);

        } else {
            // Show error message
            Toast.makeText(getActivity(), LocalTorrent.getResourceForDaemonException(result.getException()),
                    Toast.LENGTH_SHORT * 2).show();
        }

    }

    @Override
    public void onTaskSuccess(DaemonTaskSuccessResult result) {

        switch (result.getMethod()) {
        case AddByFile:
        case AddByUrl:

            // Show 'added' message
            Toast.makeText(getActivity(), R.string.torrent_added, Toast.LENGTH_SHORT).show();
            break;

        case Retrieve:

            // Only bother if we still are still looking at the same daemon since the task was queued
            if (result.getTask().getAdapterType() == daemon.getType()) {

                // Sort the new list of torrents
                allTorrents = ((RetrieveTaskSuccessResult) result).getTorrents();
                Collections.sort(allTorrents, new TorrentsComparator(daemon, sortSetting, sortReversed));

                // Sort the new list of labels
                allLabels = ((RetrieveTaskSuccessResult) result).getLabels();

                // Show refreshed totals for this daemon
                updateStatusText(null);
                updateTorrentsView(false);

                // Show 'refreshed' message unless we enabled the hide refresh message setting
                if (!interfaceSettings.shouldHideRefreshMessage()) {
                    Toast.makeText(getActivity(), R.string.list_refreshed, Toast.LENGTH_SHORT).show();
                }

            }
            break;

        case GetStats:

            // Only bother if we still are still looking at the same daemon since the task was queued
            if (result.getTask().getAdapterType() == daemon.getType()) {

                GetStatsTaskSuccessResult stats = (GetStatsTaskSuccessResult) result;
                if (Daemon.supportsSetAlternativeMode(daemon.getType())) {
                    // Update the alternative/tutle mode indicator
                    inAlternativeMode = stats.isAlternativeModeEnabled();
                    updateAlternativeModeIcon();
                }

            }
            break;

        case Remove:

            // Show 'removed' message
            boolean includingData = ((RemoveTask) result.getTask()).includingData();
            Toast.makeText(getActivity(),
                    "'" + result.getTargetTorrent().getName() + "' "
                            + getText(
                                    includingData ? R.string.torrent_removed_with_data : R.string.torrent_removed),
                    Toast.LENGTH_SHORT).show();
            break;

        case Resume:

            // Show 'resumed' message
            Toast.makeText(getActivity(),
                    "'" + result.getTargetTorrent().getName() + "' " + getText(R.string.torrent_resumed),
                    Toast.LENGTH_SHORT).show();
            break;

        case ResumeAll:

            // Show 'resumed all' message
            Toast.makeText(getActivity(), getText(R.string.torrent_resumed_all), Toast.LENGTH_SHORT).show();
            break;

        case Pause:

            // Show 'paused' message
            Toast.makeText(getActivity(),
                    "'" + result.getTargetTorrent().getName() + "' " + getText(R.string.torrent_paused),
                    Toast.LENGTH_SHORT).show();
            break;

        case PauseAll:

            // Show 'paused all' message
            Toast.makeText(getActivity(), getText(R.string.torrent_paused_all), Toast.LENGTH_SHORT).show();
            break;

        case Start:

            // Show 'started' message
            Toast.makeText(getActivity(),
                    "'" + result.getTargetTorrent().getName() + "' " + getText(R.string.torrent_started),
                    Toast.LENGTH_SHORT).show();
            break;

        case StartAll:

            // Show 'started all' message
            Toast.makeText(getActivity(), getText(R.string.torrent_started_all), Toast.LENGTH_SHORT).show();
            break;

        case Stop:

            // Show 'stopped' message
            Toast.makeText(getActivity(),
                    "'" + result.getTargetTorrent().getName() + "' " + getText(R.string.torrent_stopped),
                    Toast.LENGTH_SHORT).show();
            break;

        case StopAll:

            // Show 'stopped all' message
            Toast.makeText(getActivity(), getText(R.string.torrent_stopped_all), Toast.LENGTH_SHORT).show();
            break;

        case SetTransferRates:

            // Show 'rates updated' message
            Toast.makeText(getActivity(), R.string.rate_updated, Toast.LENGTH_SHORT).show();
            break;

        case SetDownloadLocation:
            Toast.makeText(getActivity(),
                    getString(R.string.torrent_locationset,
                            ((SetDownloadLocationTask) result.getTask()).getNewLocation()),
                    Toast.LENGTH_SHORT).show();
            break;

        case SetAlternativeMode:

            // Updated the mode: now update the server stats to reflect the real new status (since the action might have been unsuccessful for some reason)
            queue.enqueue(GetStatsTask.create(daemon));
            break;
        }

    }

    private void updateAlternativeModeIcon() {
        // By invalidation the options menu it gets redrawn and the turtle icon gets updated
        getSherlockActivity().supportInvalidateOptionsMenu();
    }

    /**
     * Shows the proper text when the torrent list is empty
     */
    private void updateEmptyListDescription() {

        // Show empty text when no torrents exist any more
        if (getTorrentListAdapter() != null && getTorrentListAdapter().getAllItems().size() == 0) {
            if (activeMainView == MainViewType.OnlyDownloading) {
                emptyText.setText(R.string.no_downloading_torrents);
            } else if (activeMainView == MainViewType.OnlyUploading) {
                emptyText.setText(R.string.no_uploading_torrents);
            } else if (activeMainView == MainViewType.OnlyInactive) {
                emptyText.setText(R.string.no_inactive_torrents);
            } else if (activeMainView == MainViewType.OnlyActive) {
                emptyText.setText(R.string.no_active_torrents);
            } else {
                emptyText.setText(R.string.no_torrents);
            }
        }

    }

    private void updateStatusText(String taskmessageText) {

        if (taskmessageText != null || allTorrents == null) {
            taskmessage.setText(taskmessageText);
            taskmessage.setVisibility(View.VISIBLE);
            statusBox.setVisibility(View.GONE);
            if (allTorrents == null) {
                emptyText.setVisibility(View.VISIBLE);
            }
            return;
        }

        // Keep totals
        int downloading = 0;
        int downloadingD = 0;
        int downloadingU = 0;
        int eta = -1;
        int seeding = 0;
        int seedingU = 0;
        //int other = 0;
        for (Torrent tor : allTorrents) {
            if (tor.getStatusCode() == TorrentStatus.Downloading
                    && (!onlyShowTransferring || tor.getRateDownload() > 0)) {
                downloading++;
                downloadingD += tor.getRateDownload();
                downloadingU += tor.getRateUpload();
                eta = Math.max(eta, tor.getEta());
            } else if (tor.getStatusCode() == TorrentStatus.Seeding
                    && (!onlyShowTransferring || tor.getRateUpload() > 0)) {
                seeding++;
                seedingU += tor.getRateUpload();
                //} else {
                //   other++;
            }
        }

        // Set text views
        taskmessage.setVisibility(View.GONE);
        statusBox.setVisibility(View.VISIBLE);
        statusDown.setText(downloading + "\u2193");
        statusUp.setText(seeding + "\u2191");
        statusDownRate.setText(FileSizeConverter.getSize(downloadingD) + getString(R.string.status_persecond));
        statusUpRate
                .setText(FileSizeConverter.getSize(downloadingU + seedingU) + getString(R.string.status_persecond));
        emptyText.setVisibility(View.GONE);
        getListView().setVisibility(View.VISIBLE);

    }

    private void newTorrentListSorting(TorrentsSortBy newSortBy) {

        this.sortReversed = (sortSetting == newSortBy ? !sortReversed : false); // If the same is selected again, reverse the sort order
        this.sortSetting = newSortBy;

        if (!(getTorrentListAdapter() == null || getTorrentListAdapter().getCount() == 0)) {

            // Sort the shown list of torrents using the new sortBy criteria
            Collections.sort(allTorrents, new TorrentsComparator(daemon, sortSetting, sortReversed));
            updateTorrentsView(true);

        }

        // Remember the new option by saving it to the user preferences (for a new Transdroid startup)
        Editor editor = PreferenceManager.getDefaultSharedPreferences(getActivity()).edit();
        editor.putInt(Preferences.KEY_PREF_LASTSORTBY, sortSetting.getCode());
        editor.putBoolean(Preferences.KEY_PREF_LASTSORTORD, sortReversed);
        editor.putBoolean(Preferences.KEY_PREF_LASTSORTGTZERO, onlyShowTransferring);
        editor.commit();

    }

    private OnNavigationListener onServerChanged = new OnNavigationListener() {
        @Override
        public boolean onNavigationItemSelected(int itemPosition, long itemId) {
            if (!ignoreFirstListNavigation) {
                switchDaemonConfig((int) itemId);
            }
            ignoreFirstListNavigation = false;
            return true;
        }
    };

    /**
     * Clear the screen and set up the new daemon (just as if we were clicking on a daemon in the pop-up menu)
     * @param which To which daemon settings configuration to switch to (which must exist)
     */
    private void switchDaemonConfig(int which) {

        if (getActivity() == null) {
            return;
        }

        // Store this new 'last used server'
        Preferences.storeLastUsedDaemonSettings(getActivity().getApplicationContext(), which);
        lastUsedDaemonSettings = which;

        // Clear any old 'refresh' tasks from the queue
        queue.clear(DaemonMethod.Retrieve);

        // Hide the old torrents list and show that we are connecting again
        if (allTorrents != null) {
            allTorrents.clear();
        }
        if (getTorrentListAdapter() != null) {
            getTorrentListAdapter().clear();
        }
        emptyText.setText(R.string.connecting);

        // Clear the old details fragment
        if (useTabletInterface) {
            Fragment f = getSherlockActivity().getSupportFragmentManager().findFragmentById(R.id.details);
            if (f != null) {
                FragmentTransaction ft = getSherlockActivity().getSupportFragmentManager().beginTransaction();
                ft.remove(f);
                ft.commit();
            }
        }

        // Reload server and update torrent list
        setupDaemon();
        updateTorrentList();

    }

    private void loadLabels() {

        availableLabels = new ArrayList<String>();

        if (Daemon.supportsLabels(getActiveDaemonType())) {

            // Add a label that includes all torrents called 'show all'
            String showAll = getText(R.string.labels_showall).toString();
            availableLabels.add(showAll);

            // Gather the used labels from the torrents
            if (allLabels != null) {
                for (Label lab : allLabels) {
                    String name = lab.getName();
                    // Start a new label if this name wasn't encountered yet
                    if (!availableLabels.contains(name)) {
                        availableLabels.add(name);
                    }

                }
            }
            for (Torrent tor : allTorrents) {

                // Force a label name (use 'unlabeled' if none is provided)
                String name = tor.getLabelName();
                if (name == null || name.equals("")) {
                    name = getText(R.string.labels_unlabeled).toString();
                }
                tor.mimicNewLabel(name);

                // Start a new label if this name wasn't encountered yet
                if (!availableLabels.contains(name)) {
                    availableLabels.add(name);
                }

            }
            Collections.sort(availableLabels);

        }

        viewtypeselectorpopup.updateLabels(availableLabels);

    }

    private void updateTorrentsView(boolean forceScrollToTop) {
        if (daemon != null && allTorrents != null) {

            // Load the labels
            String useLabel = null;
            String showAllLabelsText = getText(R.string.labels_showall).toString();
            loadLabels();
            if (Daemon.supportsLabels(getActiveDaemonType())) {
                useLabel = showAllLabelsText;
                if (activeLabel != null && availableLabels.contains(activeLabel)) {
                    useLabel = activeLabel;
                }
            }

            // Build a list of torrents that should be shown
            List<Torrent> showTorrents = new ArrayList<Torrent>();
            for (Torrent torrent : allTorrents) {
                if (matchesLabel(torrent, useLabel, showAllLabelsText) && matchesStatus(torrent, activeMainView)
                        && matchesFilter(torrent, activeFilter)) {
                    showTorrents.add(torrent);
                }
            }

            if (getTorrentListAdapter() == null) {
                setListAdapter(new TorrentListAdapter(this, showTorrents));
            } else {
                getTorrentListAdapter().replace(showTorrents);
            }

            // Scroll to the top of the list as well?
            if (forceScrollToTop) {
                getListView().setSelection(0);
            }

            updateEmptyListDescription();

            // Update the torrents view type text
            int mainViewTextID = activeMainView == MainViewType.OnlyDownloading ? R.string.view_showdl
                    : (activeMainView == MainViewType.OnlyUploading ? R.string.view_showul
                            : (activeMainView == MainViewType.OnlyInactive ? R.string.view_showinactive
                                    : (activeMainView == MainViewType.OnlyActive ? R.string.view_showactive
                                            : R.string.view_showall)));
            int mainViewDrawableID = activeMainView == MainViewType.OnlyDownloading ? R.drawable.icon_showdl
                    : (activeMainView == MainViewType.OnlyUploading ? R.drawable.icon_showup
                            : (activeMainView == MainViewType.OnlyInactive ? R.drawable.icon_showinactive
                                    : (activeMainView == MainViewType.OnlyActive ? R.drawable.icon_showactive
                                            : R.drawable.icon_showall)));
            viewtype.setText(getText(mainViewTextID).toString()
                    + (Daemon.supportsLabels(getActiveDaemonType()) ? "\n" + useLabel : ""));
            viewtypeselector.setImageResource(mainViewDrawableID);

        }
    }

    private boolean matchesLabel(Torrent torrent, String matchLabel, String showAllLabelsText) {
        if (Daemon.supportsLabels(getActiveDaemonType())) {
            return matchLabel == null || matchLabel.equals(showAllLabelsText)
                    || torrent.getLabelName().equals(matchLabel);
        }
        return true;
    }

    private boolean matchesStatus(Torrent torrent, MainViewType matchViewType) {
        boolean isActivelyDownloading = torrent.getStatusCode() == TorrentStatus.Downloading
                && (!onlyShowTransferring || torrent.getRateDownload() > 0);
        boolean isActivelySeeding = torrent.getStatusCode() == TorrentStatus.Seeding
                && (!onlyShowTransferring || torrent.getRateUpload() > 0);
        return (matchViewType == MainViewType.ShowAll
                || (matchViewType == MainViewType.OnlyDownloading && isActivelyDownloading)
                || (matchViewType == MainViewType.OnlyUploading && isActivelySeeding)
                || (matchViewType == MainViewType.OnlyActive && (isActivelySeeding || isActivelyDownloading))
                || (matchViewType == MainViewType.OnlyInactive && !isActivelyDownloading && !isActivelySeeding));
    }

    private boolean matchesFilter(Torrent torrent, String matchSearchString) {
        return ((matchSearchString == null ? true : false)
                || (torrent.getName().toLowerCase().indexOf(matchSearchString.toLowerCase()) > -1));
    }

    private void setProgressBar(boolean b) {
        inProgress = b;
        if (getSherlockActivity() != null)
            getSherlockActivity().supportInvalidateOptionsMenu();
    }

    protected View findViewById(int id) {
        return getView().findViewById(id);
    }

    protected ListView getListView() {
        return (ListView) findViewById(R.id.torrents);
    }

    private TorrentListAdapter getTorrentListAdapter() {
        return (TorrentListAdapter) getListView().getAdapter();
    }

    private void setListAdapter(TorrentListAdapter torrentListAdapter) {
        getListView().setAdapter(torrentListAdapter);
        if (torrentListAdapter == null || torrentListAdapter.getCount() <= 0) {
            emptyText.setVisibility(View.VISIBLE);
            getListView().setVisibility(View.GONE);
        } else {
            emptyText.setVisibility(View.GONE);
            getListView().setVisibility(View.VISIBLE);
        }
    }

    public void setFilter(String search_text) {
        if (search_text.equals(""))
            activeFilter = null;
        else
            activeFilter = search_text.trim();
        updateTorrentsView(true);
    }

    public void showDialog(int id) {
        new DialogWrapper(onCreateDialog(id)).show(getSherlockActivity().getSupportFragmentManager(),
                DialogWrapper.TAG + id);
    }

    protected void dismissDialog(int id) {
        // Remove the dialog wrapper fragment for the dialog's ID
        getSherlockActivity().getSupportFragmentManager().beginTransaction()
                .remove(getSherlockActivity().getSupportFragmentManager().findFragmentByTag(DialogWrapper.TAG + id))
                .commit();
    }

    /**
     * Returns the type of the currently active (shown) daemon
     * @return The enum type of the active daemon
     */
    public Daemon getActiveDaemonType() {
        return daemon.getType();
    }

    /*@Override
    public boolean onTouchEvent(MotionEvent me) {
       return gestureDetector.onTouchEvent(me);
    }*/

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    /**
     * Internal class that handles gestures from the Transdroid main screen (a 'swipe' or 'fling').
     * 
     * More at http://stackoverflow.com/questions/937313/android-basic-gesture-detection
     */
    class MainScreenGestureListener extends SimpleOnGestureListener {

        private static final int SWIPE_MIN_DISTANCE = 120;
        private static final int SWIPE_MAX_OFF_PATH = 250;
        private static final int SWIPE_THRESHOLD_VELOCITY = 200;

        @Override
        public boolean onDoubleTap(MotionEvent e) {
            return false;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

            if (e1 != null && e2 != null) {
                if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
                    return false;
                }

                if (daemon != null && interfaceSettings != null) {
                    if (Daemon.supportsLabels(daemon.getType()) && interfaceSettings.shouldSwipeLabels()) {

                        // Determine to which label to switch
                        String[] allLabels = buildLabelTexts(true);
                        int newLabel = 0;
                        if (activeLabel != null) {
                            for (int i = 0; i < allLabels.length; i++) {
                                if (activeLabel.equals(allLabels[i])) {
                                    newLabel = i;
                                    break;
                                }
                            }
                        }
                        if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
                                && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                            newLabel++;
                            if (newLabel >= allLabels.length) {
                                newLabel = 0;
                            }
                        } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
                                && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                            newLabel--;
                            if (newLabel < 0) {
                                newLabel = allLabels.length - 1;
                            }
                        }

                        // Make the switch, if possible and needed
                        if (newLabel >= 0 && newLabel < allLabels.length
                                && (activeLabel == null || activeLabel != allLabels[newLabel])) {
                            activeLabel = allLabels[newLabel];
                            updateTorrentsView(true);
                        }

                    } else {

                        // Determine to which daemon we are now switching
                        int newDaemon = lastUsedDaemonSettings;
                        // right to left swipe
                        if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
                                && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                            newDaemon = lastUsedDaemonSettings + 1;
                            if (newDaemon >= allDaemonSettings.size()) {
                                newDaemon = 0;
                            }
                        } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
                                && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                            newDaemon = lastUsedDaemonSettings - 1;
                            if (newDaemon < 0) {
                                newDaemon = allDaemonSettings.size() - 1;
                            }
                        }

                        // Make the switch, if needed
                        if (lastUsedDaemonSettings != newDaemon) {
                            switchDaemonConfig(newDaemon);
                        }

                    }
                }
            }

            return false;
        }

    }

}