/*
*  qm_libraryview.cpp
*  QUIMUP library treeview
*  © 2008-2024 Johan Spee
*  SPDX-License-Identifier: GPL-3.0-or-later
*/

#include "qm_libraryview.h"
#include "qm_modes_ids.h"


qm_libraryView::qm_libraryView(QWidget *parent, qm_Config *cfg)
{
    setParent(parent);

    if (objectName().isEmpty())
        setObjectName("quimup library");

    config = cfg;

    set_themed_icons(config->set_dark_theme);

    // init_vars
    mpd_cmd = nullptr;
    b_mpd_connected = false;
    playlist_droppos = 0;
    resize_countdown = 10;
    column_count = 0;
    setRootIsDecorated(true);
    setItemsExpandable (true);
    setUniformRowHeights(true);
    setAllColumnsShowFocus(false);
    setSelectionMode(ExtendedSelection);
    sortByColumn (-1, Qt::AscendingOrder); // no sorting
    setSortingEnabled(false);
    set_column_count(1);
    setDragDropMode(QAbstractItemView::DragOnly);
    setDropIndicatorShown(false);
    setDragEnabled(true);
    string_last_column = "";
    connect( this, SIGNAL(itemExpanded(QTreeWidgetItem *)), this, SLOT( on_item_expanded(QTreeWidgetItem *)) );
    connect( this, SIGNAL(itemSelectionChanged()), this, SLOT( on_selection_changed()) );

    setup_widgets();

    set_auto_columns();
}


void qm_libraryView::setup_widgets()
{
    // context menu
    context_menu = new QMenu(this);
    this->setContextMenuPolicy(Qt::DefaultContextMenu);

    a_newplaylist = new QAction(context_menu);
    a_newplaylist->setText(tr("Open in new playlist"));
    // icon set in set_themed_icons
    connect( a_newplaylist, SIGNAL(triggered()), this, SLOT( on_createnew()) );
    context_menu->addAction(a_newplaylist);

    a_append = new QAction(context_menu);
    a_append->setText(tr("Append to playlist"));
    // icon set in set_themed_icons
    connect( a_append, SIGNAL(triggered()), this, SLOT( on_append()) );
    context_menu->addAction(a_append);

    a_loadtags = new QAction(context_menu);
    a_loadtags->setText(tr("Rescan selection"));
    // icon set in set_themed_icons
    connect( a_loadtags, SIGNAL(triggered()), this, SLOT( on_update()) );
    context_menu->addAction(a_loadtags);

    a_opendir = new QAction(context_menu);
    a_opendir->setText(tr("Open folder"));
    // icon set in set_themed_icons
    connect( a_opendir, SIGNAL(triggered()), this, SLOT( on_opendir()) );
    context_menu->addAction(a_opendir);

    a_tagedit = new QAction(context_menu);
    a_tagedit->setText(tr("Edit tags"));
    // icon set in set_themed_icons
    connect( a_tagedit, SIGNAL(triggered()), this, SLOT( on_tagedit()) );
    context_menu->addAction(a_tagedit);

    a_delete = new QAction(context_menu);
    a_delete->setText(tr("Delete selection"));
    // icon set in set_themed_icons
    connect( a_delete, SIGNAL(triggered()), this, SLOT( on_delete()) );
    context_menu->addAction(a_delete);

    a_collapse = new QAction(context_menu);
    a_collapse->setText(tr("Collapse all"));
    // icon set in set_themed_icons
    connect( a_collapse, SIGNAL(triggered()), this, SLOT( collapseAll()) );
    context_menu->addAction(a_collapse);

    a_delete->setEnabled(false);
    a_opendir->setEnabled(false);
    a_tagedit->setEnabled(false);
    a_loadtags->setEnabled(false);

    a_newplaylist->setIcon(ic_a_newplaylist);
    a_append->setIcon(ic_a_append);
    a_loadtags->setIcon(ic_a_loadtags);
    a_opendir->setIcon(ic_a_opendir);
    a_tagedit->setIcon(ic_a_tagedit);
    a_delete->setIcon(ic_a_delete);
    a_collapse->setIcon(ic_a_collapse);

    hvw_library = new QHeaderView(Qt::Horizontal, this);
    hvw_library->setHighlightSections(false);
    hvw_library->setSectionsClickable(false);
    hvw_library->setDefaultAlignment(Qt::AlignLeft);
    hvw_library->setStretchLastSection(true);
    hvw_library->setMinimumSectionSize(60);
    setHeader(hvw_library);
    hvw_library->show();
}


void qm_libraryView::on_selection_changed()
{
    int counter = 0;
    QTreeWidgetItemIterator itr(this);
    while (*itr)
    {
        QTreeWidgetItem *current = *itr;

        if ( current->isSelected() )
        {
             // no selection of non-draggable items
            if (current->gettype >= TP_PLISTITEM)
                current->setSelected(false);
            else
            { // no selection if if a parent is already selected
                bool a_parent_selected = false;
                QTreeWidgetItem *up = current->parent();
                while (up != nullptr)
                {
                    if ( up->isSelected() )
                        a_parent_selected = true;
                    up = up->parent();
                }

                if (a_parent_selected)
                    current->setSelected(false);
                else
                    counter++;
            }
        }
        ++itr;
    }

    // MDIR_ACCESSIBLE is false on remote connection
    if (counter == 1 && config->mpd_musicdir_status == MDIR_ACCESSIBLE && currentItem() != nullptr )
    {
        QTreeWidgetItem *current = currentItem();

        if ( current != nullptr && (current->gettype == TP_SONG || current->gettype == TP_DIRECTORY))
        {
            // bool is used in set_actions()
            b_opendir_tagedit_set = true;
            a_opendir->setEnabled(config->file_manager_installed);
            a_tagedit->setEnabled(config->tag_editor_installed);
        }
        else
        {
            b_opendir_tagedit_set = false;
            a_opendir->setEnabled(false);
            a_tagedit->setEnabled(false);
        }
    }
    else
    {
        b_opendir_tagedit_set = false;
        a_opendir->setEnabled(false);
        a_tagedit->setEnabled(false);
    }
}


void qm_libraryView::on_item_expanded(QTreeWidgetItem *active_item)
{
    if (!b_mpd_connected)
        return;

    switch (active_item->gettype)
    {
        case TP_ARTIST:
        {
            if(active_item->getdummy)
            {
                take_dummy_from(active_item);
                expand_artist(active_item);
            }
            break;
        }

        case TP_ALBUM:
        {
            if(active_item->getdummy)
            {
                take_dummy_from(active_item);
                expand_album(active_item);
            }
            break;
        }

        case TP_GENRE:
        {
            if(active_item->getdummy)
            {
                take_dummy_from(active_item);
                expand_genre(active_item);
            }
            break;
        }

        case TP_PLAYLIST:
        {
            if(active_item->getdummy)
            {
                take_dummy_from(active_item);
                expand_playlist(active_item);
            }
            break;
        }

        case TP_DIRECTORY:
        {
            if(active_item->getdummy)
            {
                take_dummy_from(active_item);
                expand_directory(active_item);
            }
            break;
        }

        default: // TP_SONG, TP_PLISTITEM, TP_COMMENT
            break;
    }
}

// tree root items in album mode
void qm_libraryView::get_albums(QString searchfor, bool sort_by_date)
{
    if (!b_mpd_connected)
    {
        headerItem()->setIcon(0, ic_delete);
        headerItem()->setText(0, " " + tr("not connected") + " ");
        set_column_count(1);
        set_auto_columns();
        return;
    }

    qm_itemList itemlist;

    if (searchfor.isEmpty())
        itemlist = mpd_cmd->get_albumlist(sort_by_date);
    else
        itemlist = mpd_cmd->get_album_searchlist(searchfor);

    if (itemlist.empty())
    {
        headerItem()->setIcon(0, ic_dot);
        headerItem()->setText(0, " " + tr("no albums found") + " ");
        set_column_count(1);
        set_auto_columns();
        return;
    }

    bool bydate = (sort_by_date && searchfor.isEmpty());

    if (bydate)
        set_column_count(3);
    else
        set_column_count(2);

    int count = 0;

    itemlist.sort();

    QString album = NULL_STRING;
    QString artist = NULL_STRING;

    QTreeWidgetItem *new_item;
    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        // Skip duplicates
        if (album == iter->album && artist == iter->artist)
        continue;

        album = iter->album;
        artist = iter->artist;

        new_item =  new QTreeWidgetItem();
        if (iter->album.isEmpty())
            new_item->setText(0, "?");
        else
            new_item->setText(0, iter->album);
        if (iter->artist.isEmpty())
            new_item->setText(1, "?");
        else
            new_item->setText(1, iter->artist);
        new_item->setIcon(0, ic_album);

        new_item->settype(TP_ALBUM);
        new_item->setartist(iter->artist);
        new_item->setalbum(iter->album);

        if (bydate)
            new_item->setText(2, iter->moddate);

        addTopLevelItem(new_item);
        add_dummy_to(new_item);
        count ++;

    }
    itemlist.clear();

    // added two extra '0' to make it fit
    string_last_column = " 054/54/54 54:540 ";
    last_column_width = get_string_width(string_last_column);

    QString str = " " + QString::number(count) + " " + tr("albums") + " ";
    headerItem()->setIcon(0, ic_check);
    headerItem()->setText(0, str);
    headerItem()->setText(1, tr("artist") );
    if (bydate)
        headerItem()->setText(2, tr("Last modified") );

    set_auto_columns();
}

// tree root items in year mode
void qm_libraryView::get_albums_year()
{
    if (!b_mpd_connected)
    {
        headerItem()->setIcon(0, ic_delete);
        headerItem()->setText(0, " " + tr("not connected") + " ");
        set_column_count(1);
        set_auto_columns();
        return;
    }

    qm_itemList itemlist;

    itemlist = mpd_cmd->get_yearlist();

    if (itemlist.empty())
    {
        headerItem()->setIcon(0, ic_dot);
        headerItem()->setText(0, " " + tr("no albums found") + " ");
        set_column_count(1);
        set_auto_columns();
        return;
    }

    set_column_count(3);
    int count = 0;
    itemlist.sort();

    QString album = NULL_STRING;
    QString artist = NULL_STRING;

    QTreeWidgetItem *new_item;
    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        // Skip duplicates
        if (album == iter->album && artist == iter->artist)
            continue;

        album = iter->album;
        artist = iter->artist;

        new_item =  new QTreeWidgetItem();
        if (iter->album.isEmpty())
            new_item->setText(0, "?");
        else
            new_item->setText(0, iter->album);
        if (iter->artist.isEmpty())
            new_item->setText(1, "?");
        else
            new_item->setText(1, iter->artist);
        new_item->setIcon(0, ic_album);

        new_item->settype(TP_ALBUM);
        new_item->setartist(iter->artist);
        new_item->setalbum(iter->album);

        new_item->setText(2, iter->year);

        addTopLevelItem(new_item);
        add_dummy_to(new_item);
        count ++;
    }
    itemlist.clear();

    // added one extra '0' to make it fit
    string_last_column = " 99990 ";
    last_column_width = get_string_width(string_last_column);

    QString str = " " + QString::number(count) + " " + tr("albums") + " ";
    headerItem()->setIcon(0, ic_check);
    headerItem()->setText(0, str);
    headerItem()->setText(1, tr("artist") );
    headerItem()->setText(2, tr("year") );

    set_auto_columns();
}

// tree root items in dir directory mode
void qm_libraryView::get_directories(QString searchfor)
{
    set_column_count(1);

    if (!b_mpd_connected)
    {
        headerItem()->setText(0, " " + tr("not connected") + " " );
        headerItem()->setIcon(0, ic_delete);
        set_auto_columns();
        return;
    }

    qm_itemList itemlist;

    if (searchfor.isEmpty() || searchfor == "/")
        itemlist = mpd_cmd->get_dirlist("/");
    else
        itemlist = mpd_cmd->get_dir_searchlist(searchfor);

    if (itemlist.empty())
    {
        headerItem()->setText(0, " " + tr("no folders found") + " " );
        headerItem()->setIcon(0, ic_dot);
        set_auto_columns();
        return;
    }

    itemlist.sort();
    int count = 0;
    QTreeWidgetItem *new_item;
    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        if ( iter->type == TP_DIRECTORY )
        {
            new_item = new QTreeWidgetItem();
            new_item->setText(0, iter->name);
            new_item->setIcon(0, ic_dir);

            new_item->settype(TP_DIRECTORY);
            new_item->seturi(iter->uri);
            new_item->setname(iter->name);

            addTopLevelItem(new_item);
            add_dummy_to(new_item);
            count++;
        }
    }

    itemlist.clear();

    headerItem()->setText(0, " " + QString::number(count) + " " + tr("folders") + " ");
    headerItem()->setIcon(0, ic_check);

    set_auto_columns();
}

// tree root items in palylist mode
void qm_libraryView::get_playlists()
{
    set_column_count(1);

    if (!b_mpd_connected)
    {
        headerItem()->setText(0, " " + tr("not connected") + " " );
        headerItem()->setIcon(0, ic_delete);
        set_auto_columns();
        return;
    }

    qm_itemList itemlist = mpd_cmd->get_playlistlist();

    if (itemlist.empty())
    {
        headerItem()->setText(0, " " + tr("no playlists found") + " " );
        headerItem()->setIcon(0, ic_dot);
        set_auto_columns();
        return;
    }

    itemlist.sort();

    int count = 0;
    QTreeWidgetItem *new_item;
    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        if (iter->name.isEmpty())
            iter->name = "?";

        new_item = new QTreeWidgetItem();
        new_item->setText(0, iter->name);
        new_item->setIcon(0, ic_playlist);
        new_item->settype(TP_PLAYLIST);
        new_item->seturi(iter->uri);
        new_item->setname(iter->name);

        addTopLevelItem(new_item);
        add_dummy_to(new_item);

        count ++;
    }
    itemlist.clear();

    QString str = " " + QString::number(count) + " " + tr("playlists") + " ";
    headerItem()->setText(0, str);
    headerItem()->setIcon(0, ic_check);

    set_auto_columns();
}

// tree root items in artist mode
void qm_libraryView::get_artists(QString searchfor)
{
    set_column_count(1);

    if (!b_mpd_connected)
    {
        headerItem()->setText(0, " " + tr("not connected") + " " );
        headerItem()->setIcon(0, ic_delete);
        set_auto_columns();
        return;
    }

    qm_itemList itemlist;

    if (searchfor.isEmpty())
        itemlist = mpd_cmd->get_artistlist();
    else
        itemlist = mpd_cmd->get_artist_searchlist(searchfor);

    if (itemlist.empty())
    {
        headerItem()->setText(0, " " + tr("no artists found") + " ");
        headerItem()->setIcon(0, ic_dot);
        set_auto_columns();
        return;
    }

    int count = 0;

    itemlist.sort();

    // do not skip ""
    QString artist = NULL_STRING;

    QTreeWidgetItem *new_item;
    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        // skip duplicates
        if (artist == iter->artist)
            continue;

        artist = iter->artist;

        new_item = new QTreeWidgetItem();
        if (iter->artist.isEmpty())
            new_item->setText(0, "?");
        else
            new_item->setText(0, iter->artist);
        new_item->setIcon(0, ic_artist);

        new_item->settype(TP_ARTIST);
        new_item->setartist(iter->artist);
        new_item->setalbum(iter->album);
        new_item->setname(iter->name);

        addTopLevelItem(new_item);
        add_dummy_to(new_item);

        count ++;
    }
    itemlist.clear();

    QString str = " " + QString::number(count) + " " + tr("artists") + " ";
    headerItem()->setText(0, str);
    headerItem()->setIcon(0, ic_check);

    set_auto_columns();
}

// tree root items in song (searched) mode
void qm_libraryView::get_songs(QString searchfor)
{
    if (!b_mpd_connected)
    {
        headerItem()->setText(0, " " + tr("not connected") + " " );
        set_column_count(1);
        set_auto_columns();
        return;
    }

    qm_itemList itemlist;

    if (searchfor.isEmpty())
        itemlist = mpd_cmd->get_songlist();
    else
        itemlist = mpd_cmd->get_song_searchlist(searchfor);

    if (itemlist.empty())
    {
        headerItem()->setText(0, " " + tr("no titles found") + " " );
        headerItem()->setIcon(0, ic_dot);
        set_column_count(1);
        set_auto_columns();
        return;
    }

    set_column_count(3);

    int count = 0;
    itemlist.sort();

    QTreeWidgetItem *new_item;
    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        new_item = new QTreeWidgetItem();
        if (iter->title.isEmpty())
        {
            // use file name as title
            int i = (iter->uri).lastIndexOf( '/' ) + 1;
            iter->title = "? (" + (iter->uri).right((iter->uri).length() - i) + ")";
        }
        new_item->setText(0, iter->title);

        if (iter->artist.isEmpty())
            new_item->setText(1, "?");
        else
            new_item->setText(1, iter->artist);

        if (iter->album.isEmpty())
        new_item->setText(2, "?");
        else
            new_item->setText(2, iter->album);

        new_item->setIcon(0, ic_track);
        add_songdata_toItem(new_item, *iter);
        addTopLevelItem(new_item);
        count ++;
    }
    itemlist.clear();

    QString str = " " + QString::number(count) + " " + tr("titles") + " ";
    headerItem()->setText(0, str);
    headerItem()->setText(1, tr("artist") );
    headerItem()->setText(2, tr("album") );
    headerItem()->setIcon(0, ic_check);

    // bool title_mode is set in resize_columns()
    set_auto_columns();
}

// tree root items in genre mode
void qm_libraryView::get_genres(QString searchfor)
{
    set_column_count(1);

    if (!b_mpd_connected)
    {
        headerItem()->setText(0, " " + tr("not connected") + " " );
        headerItem()->setIcon(0, ic_delete);
        set_auto_columns();
        return;
    }

    qm_itemList itemlist;
    if (searchfor.isEmpty())
        itemlist = mpd_cmd->get_genrelist();
    else
        itemlist = mpd_cmd->get_genre_searchlist(searchfor);

    if (itemlist.empty())
    {
        headerItem()->setText(0, " " + tr("no genres found") + " " );
        headerItem()->setIcon(0, ic_dot);
        set_auto_columns();
        return;
    }

    int count = 0;
    itemlist.sort();
    QTreeWidgetItem *new_item;
    QString genre = NULL_STRING;
    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        // Skip duplicates
        if(iter->genre != genre)
        {
            genre = iter->genre;
            new_item = new QTreeWidgetItem();
            if (iter->genre.isEmpty())
                new_item->setText(0, "?");
            else
                new_item->setText(0, iter->genre);
            new_item->settype(TP_GENRE);
            new_item->setgenre(iter->genre);
            new_item->setIcon(0, ic_genre);
            addTopLevelItem(new_item);
            add_dummy_to(new_item);
            count++;
        }
    }
    itemlist.clear();

    QString str = " " + QString::number(count) + " " + tr("genres") + " ";
    headerItem()->setText(0, str);
    headerItem()->setIcon(0, ic_check);

    set_auto_columns();
}


void qm_libraryView::expand_album(QTreeWidgetItem *active_item)
{
    qm_itemList itemlist;

    if ( config->browser_libmode == LB_ID_GENRE)
        itemlist = mpd_cmd->get_songs_for_any(active_item->getalbum, active_item->getartist, active_item->getgenre);
    else
        itemlist = mpd_cmd->get_songs_for_any(active_item->getalbum, active_item->getartist, NULL_STRING);

    if (itemlist.empty())
        return;

    itemlist.sort();

    QTreeWidgetItem *new_item;
    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        if ( iter->type == TP_SONG )
        {
            if (iter->title.isEmpty())
            {
                // use file name as title
                int i = (iter->uri).lastIndexOf( '/' ) + 1;
                iter->title = (iter->uri).right((iter->uri).length() - i);
            }
            if (iter->artist.isEmpty())
                iter->artist = "?";
            new_item = new QTreeWidgetItem();
            QString track = "?";
            if (!iter->track.isEmpty())
                track = iter->track;
            if (!iter->disc.isEmpty())
                track = track + " / " + iter->disc;
            new_item->setText(0, track + " " + iter->title);
            new_item->setIcon(0, ic_track);
            add_songdata_toItem(new_item, *iter);
            active_item->addChild(new_item);
            addTopLevelItem(new_item);
            // show title across all columns:
            new_item->setFirstColumnSpanned(true);
        }
    }
    itemlist.clear();
}


void qm_libraryView::expand_artist(QTreeWidgetItem *active_item)
{
    qm_itemList itemlist = mpd_cmd->get_albums_for_artist(active_item->getartist);

    if (itemlist.empty())
        return;

    if (config->sort_albums_year)// add the date to the sorter
    {
        std::list<qm_listItemInfo>::iterator it;
        for (it = itemlist.begin(); it != itemlist.end(); ++it)
        {
            it->year  = mpd_cmd->get_year_for_album( it->album, it->artist);
            it->sorter = it->year + it->sorter;
        }
    }

    itemlist.sort();

    QString album = NULL_STRING;

    QTreeWidgetItem *new_item;
    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        // skip duplicates
        if (album == iter->album)
            continue;

        album = iter->album;

        new_item =  new QTreeWidgetItem();

        if (config->sort_albums_year)
        {
            if (iter->album.isEmpty())
                new_item->setText(0, iter->year + "?");
            else
                new_item->setText(0, iter->year + "  " + iter->album);
        }
        else
        {
            if (iter->album.isEmpty())
                new_item->setText(0, "?");
            else
                new_item->setText(0, iter->album);
        }

        new_item->setIcon(0, ic_album);

        new_item->settype(TP_ALBUM);
        new_item->setartist(iter->artist);
        new_item->setalbum(iter->album);
        new_item->setname(iter->name);

        active_item->addChild(new_item);
        add_dummy_to(new_item);
    }
    itemlist.clear();
}


void qm_libraryView::expand_playlist(QTreeWidgetItem *active_item)
{
    qm_itemList itemlist = mpd_cmd->get_items_for_playlist(active_item->geturi);

    if (itemlist.empty())
        return;

    QTreeWidgetItem *new_item;
    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        new_item = new QTreeWidgetItem();
        new_item->seturi(iter->uri);
        new_item->settype(TP_PLISTITEM);
        new_item->setForeground( 0, QBrush(QColor("#70707A")));
        if (iter->type == TP_STREAM)
        {
            new_item->setIcon(0, ic_stream);
            new_item->setText(0, iter->uri);
        }
        else
        {
            new_item->setIcon(0, ic_track);
            new_item->setText(0, iter->artist + " : " + iter->title);
            new_item->settime(iter->time);
            new_item->setartist(iter->artist);
            new_item->setalbum(iter->album);
            new_item->settitle(iter->title);
            new_item->settrack(iter->track);
            new_item->setname(iter->name);
            new_item->setgenre(iter->genre);
        }
        active_item->addChild(new_item);
    }
    itemlist.clear();
}


void qm_libraryView::expand_genre(QTreeWidgetItem *active_item)
{
    qm_itemList itemlist = mpd_cmd->get_artists_for_genre(active_item->getgenre);

    if (itemlist.empty())
        return;

    itemlist.sort();

    QTreeWidgetItem *artist_item = new QTreeWidgetItem();
    QString current_artist = NULL_STRING;
    QTreeWidgetItem *album_item = new QTreeWidgetItem();
    QString current_album = NULL_STRING;
    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        if (iter->artist != current_artist)
        {
            // add artist to active_item
            current_artist = iter->artist;
            artist_item = new QTreeWidgetItem();
            if (iter->artist.isEmpty())
                artist_item->setText(0, "?");
            else
                artist_item->setText(0, iter->artist);
            artist_item->setIcon(0, ic_artist);
            artist_item->settype(TP_ARTIST);
            artist_item->setartist(iter->artist);
            artist_item->setgenre(iter->genre);
            active_item->addChild(artist_item);

            // add albums to artist_item
            current_album = iter->album;
            album_item = new QTreeWidgetItem();
            if (iter->album.isEmpty())
                album_item->setText(0, "?");
            else
                album_item->setText(0, iter->album);
            album_item->setIcon(0, ic_album);
            album_item->settype(TP_ALBUM);
            album_item->setartist(iter->artist);
            album_item->setalbum(iter->album);
            album_item->setgenre(iter->genre);
            add_dummy_to(album_item);
            artist_item->addChild(album_item);
        }
        else // add more albums to artist_item
        {
            if (iter->album != current_album)
            {
                current_album = iter->album;
                album_item = new QTreeWidgetItem();
                if (iter->album.isEmpty())
                    album_item->setText(0, "?");
                else
                    album_item->setText(0, iter->album);
                album_item->setIcon(0, ic_album);
                album_item->settype(TP_ALBUM);
                album_item->setartist(iter->artist);
                album_item->setalbum(iter->album);
                album_item->setgenre(iter->genre);
                add_dummy_to(album_item);
                artist_item->addChild(album_item);
            }
        }
    }
    itemlist.clear();
}


void qm_libraryView::expand_directory(QTreeWidgetItem *active_item)
{
    qm_itemList itemlist = mpd_cmd->get_dirlist(active_item->geturi);

    if (itemlist.empty())
        return;
    else
        itemlist.sort();

    QTreeWidgetItem *new_item;
    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        if ( iter->type == TP_DIRECTORY )
        {
            new_item = new QTreeWidgetItem();
            new_item->setText(0, iter->name);
            new_item->setIcon(0, ic_dir);

            new_item->settype(TP_DIRECTORY);
            new_item->seturi(iter->uri);
            new_item->setname(iter->name);

            active_item->addChild(new_item);
            add_dummy_to(new_item);
        }
        else
        if ( iter->type == TP_SONG )
        {
            new_item = new QTreeWidgetItem();
            new_item->setText(0, iter->name);
            new_item->setIcon(0, ic_track);
            add_songdata_toItem(new_item, *iter);
            active_item->addChild(new_item);
        }
        else
        if ( iter->type == TP_PLAYLIST )
        {
            new_item = new QTreeWidgetItem();
            new_item->setText(0, iter->name);
            new_item->setIcon(0, ic_playlist);
            //add_songdata_toItem(new_item, *iter);
            new_item->settype(TP_PLAYLIST);
            new_item->seturi(iter->uri);
            new_item->setname(iter->name);
            active_item->addChild(new_item);
        }
    }

    itemlist.clear();
}


void qm_libraryView::on_mpd_plistsaved()
{
    if (config->browser_libmode == LB_ID_PLIST)
        reload_root();
}


void qm_libraryView::set_connected(qm_mpdCommand *cmd, bool isconnected)
{
    mpd_cmd = cmd;
    if (mpd_cmd == nullptr)
        b_mpd_connected = false;
    else
        b_mpd_connected = isconnected;

    if (b_mpd_connected)
    {
        connect( mpd_cmd, SIGNAL(signal_playlist_saved()), this, SLOT( on_mpd_plistsaved()));
        reload_root();

        if (config->mpd_rm_allowed && config->browser_libmode == LB_ID_PLIST)
            a_delete->setEnabled(true);
        else
            a_delete->setEnabled(false);
        a_newplaylist->setEnabled(true);
        a_append->setEnabled(true);
        a_collapse->setEnabled(true);
        if (config->mpd_rescan_allowed)
            a_loadtags->setEnabled(true);
        // a_opendir and a_tagedit are set in on_selection changed()
    }
    else
    {
        clear();
        set_column_count(1);
        headerItem()->setIcon(0, ic_delete);
        headerItem()->setText(0, " " + tr("not connected") + " ");
        a_delete->setEnabled(false);
        a_newplaylist->setEnabled(false);
        a_append->setEnabled(false);
        a_collapse->setEnabled(false);
        a_loadtags->setEnabled(false);
        a_opendir->setEnabled(false);
        a_tagedit->setEnabled(false);
        set_auto_columns();
    }
}


void qm_libraryView::contextMenuEvent ( QContextMenuEvent *event )
{
    if (event->reason() == QContextMenuEvent::Mouse)
        context_menu->exec(QCursor::pos(), nullptr);
}


void qm_libraryView::add_songdata_toItem(QTreeWidgetItem *theItem, qm_listItemInfo data)
{
    theItem->settype(data.type);
    theItem->settime(data.time);
    theItem->setartist(data.artist);
    theItem->setalbum(data.album);
    theItem->settitle(data.title);
    theItem->seturi(data.uri);
    theItem->settrack(data.track);
    theItem->setname(data.name);
    theItem->setgenre(data.genre);
}


void qm_libraryView::add_dummy_to(QTreeWidgetItem *theItem)
{
    QTreeWidgetItem *dummy = new QTreeWidgetItem();
    dummy->setText(0, NULL_STRING);
    theItem->addChild(dummy);
    theItem->setdummy(true);
}


void qm_libraryView::take_dummy_from(QTreeWidgetItem *theItem)
{
    theItem->takeChild(0);
    theItem->setdummy(false);
}


void qm_libraryView::reload_root()
{
    clear();

    if (!b_mpd_connected)
        return;

    if (config->browser_libmode == LB_ID_PLIST)
    {
        a_delete->setEnabled(true);
        a_loadtags->setEnabled(false);
    }
    else
    {
        a_delete->setEnabled(false);
        if (config->mpd_rescan_allowed || config->mpd_update_allowed)
            a_loadtags->setEnabled(true);
        else
            a_loadtags->setEnabled(false);
    }

    switch (config->browser_libmode)
    {
        case LB_ID_ARTIST:
        {
            get_artists("");
            break;
        }
        case LB_ID_ALBUM:
        {
            get_albums("", false);
            break;
        }
        case LB_ID_PLIST:
        {
            get_playlists();
            break;
        }
        case LB_ID_DIR:
        {
            get_directories("");
            break;
        }
        case LB_ID_TSTAMP:
        {
            get_albums("", true);
            break;
        }
        case LB_ID_YEAR:
        {
            get_albums_year();
            break;
        }
        case LB_ID_TITLE:
        {
            get_songs("");
            break;
        }
        case LB_ID_GENRE:
        {
            get_genres("");
            break;
        }
        case LB_ID_SEARCH:
        {
            switch (config->browser_searchmode)
            {
                case SR_ID_ARTIST:
                {
                    get_artists(config->search_string);
                    break;
                }
                case SR_ID_ALBUM:
                {
                    get_albums(config->search_string, false);
                    break;
                }
                case SR_ID_TITLE:
                {
                    get_songs(config->search_string);
                    break;
                }
                case SR_ID_GENRE:
                {
                    get_genres(config->search_string);
                    break;
                }
                case SR_ID_DIR:
                {
                    get_directories(config->search_string);
                    break;
                }
                default:
                    break;
            } // end switch searched_mode
            break;
        }
        default:
            break;
    }
}


void qm_libraryView::on_append()
{
    modify_playlist(false, false);
}


void qm_libraryView::on_createnew()
{
    modify_playlist(true, false);

    if (config->auto_playfirst)
    {
        mpd_cmd->play(true);
    }
}


void qm_libraryView::on_delete()
{
    if (config->browser_libmode != LB_ID_PLIST || !b_mpd_connected)
        return;

    QList<QTreeWidgetItem*> tobeRemoved = selectedItems();
    if (tobeRemoved.empty())
        return;

    // Ask for confirmation
    QMessageBox msgBox = QMessageBox(this);
    msgBox.setText(tr("Are you sure?"));
    msgBox.setInformativeText(tr("This will permanently remove the selected playlists!"));
    msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
    if ( msgBox.exec() == QMessageBox::Cancel)
    return;

    qm_commandList newCommandList;
    QListIterator<QTreeWidgetItem *> itr(tobeRemoved);
    itr.toBack();
    while (itr.hasPrevious())
    {
        QTreeWidgetItem *current = itr.previous();
        qm_mpd_command newCommand;
        newCommand.cmd = CMD_DPL;
        newCommand.uri = current->geturi;
        newCommandList.push_back(newCommand);
    }

    mpd_cmd->execute_commands( newCommandList, false );
    newCommandList.clear();
    tobeRemoved.clear();
    reload_root();
}


void qm_libraryView::on_update()
{
    if (topLevelItemCount() == 0 || !b_mpd_connected || (!config->mpd_rescan_allowed && !config->mpd_update_allowed) )
        return;

    QList<QTreeWidgetItem*> tobeUpdated = selectedItems();
    if (tobeUpdated.empty())
        return;

    std::list <QString> updateFilesList;

    QListIterator<QTreeWidgetItem *> itr(tobeUpdated);
    while (itr.hasNext())
    {
        qm_itemList itemlist;
        QTreeWidgetItem *currentItem = itr.next();
        switch (currentItem->gettype)
        {
            case TP_SONG:
            {
                updateFilesList.push_back(currentItem->geturi);
                break;
            }
            case TP_ARTIST:
            {
                if ( config->browser_libmode == LB_ID_GENRE)
                    itemlist = mpd_cmd->get_songs_for_any(NULL_STRING, currentItem->getartist, currentItem->getgenre);
                else
                    itemlist = mpd_cmd->get_songs_for_any(NULL_STRING, currentItem->getartist, NULL_STRING);

                if (!itemlist.empty())
                {
                    std::list<qm_listItemInfo>::iterator iter;
                    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
                    {
                        updateFilesList.push_back(iter->uri);
                    }
                }
                itemlist.clear();
                break;
            }
            case TP_ALBUM:
            {
                if ( config->browser_libmode == LB_ID_GENRE)
                    itemlist = mpd_cmd->get_songs_for_any(currentItem->getalbum, currentItem->getartist, currentItem->getgenre);
                else
                    itemlist = mpd_cmd->get_songs_for_any(currentItem->getalbum, currentItem->getartist, NULL_STRING);

                if (!itemlist.empty())
                {
                    std::list<qm_listItemInfo>::iterator iter;
                    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
                    {
                        updateFilesList.push_back(iter->uri);
                    }
                }
                itemlist.clear();
                break;
            }
            case TP_GENRE:
            {
                itemlist = mpd_cmd->get_songs_for_any(NULL_STRING, NULL_STRING, currentItem->getgenre);
                if (!itemlist.empty())
                {
                    std::list<qm_listItemInfo>::iterator iter;
                    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
                    {
                        updateFilesList.push_back(iter->uri);
                    }
                }
                itemlist.clear();
                break;
            }
            case TP_DIRECTORY:
            {
                updateFilesList.push_back(currentItem->geturi);
                break;
            }
            default:
                break;
        }
    }

    tobeUpdated.clear();

    qm_commandList theUpdateList;

    int count = 0;
    updateFilesList.sort();
    QString previous_dir = "";
    std::list<QString>::iterator iter;
    for (iter = updateFilesList.begin(); iter != updateFilesList.end(); ++iter)
    {
        qm_mpd_command newCommand;
        /*
           We only handle entire directories because of an MPD 0.17 bug:
           Rescanning files often results in a partially updated database.
           So we first sort the list (above), next strip the filename off
           (below) and add the dir when it is different from the previous.
        */
        newCommand.uri = (*iter).left((*iter).lastIndexOf("/"));
        if (newCommand.uri != previous_dir)
        {
            if (config->mpd_rescan_allowed)
            {
                newCommand.cmd = CMD_SCN; // only updates files, even if timestamp has not changed
                theUpdateList.push_back(newCommand);
            }
            if (config->mpd_update_allowed)
            {
                newCommand.cmd = CMD_UPD; // finds additions/removals and files with changed timestamp
                theUpdateList.push_back(newCommand);
            }
            previous_dir = newCommand.uri;
            count++;
        }
    }
    updateFilesList.clear();

    if (config->mpd_rescan_allowed && config->cout_extensive)
        printf("Rescanning directories: %i\n", count);
    if (config->mpd_update_allowed && config->cout_extensive)
        printf("Updating directories: %i\n", count);

    int results = 0;
    if (!theUpdateList.empty())
    {
        results = mpd_cmd->execute_commands(theUpdateList, false);
        theUpdateList.clear();
        reload_root();
    }

    if (results < count)
        printf("Some update or rescan commands failed!\n");
}


void qm_libraryView::on_tagedit()
{
    if (currentItem() == nullptr)
        return;

    if (config->mpd_musicdir_status != 1)
    {
        printf ("Album art: Directory is not accessible\n");
        return;
    }

    if (!config->tag_editor_installed)
        return;

    QString mpd_path = currentItem()->geturi;
    if (currentItem()->gettype != TP_DIRECTORY)
        mpd_path = mpd_path.left(mpd_path.lastIndexOf("/"));

    QProcess *proc = nullptr;

    QString full_path = config->mpd_musicpath + "/" + mpd_path;

    proc->startDetached(config->tag_editor, QStringList() << full_path);
}


void qm_libraryView::on_opendir()
{
    if (currentItem() == nullptr)
        return;

    if (config->mpd_musicdir_status != 1)
    {
        printf ("Open directory: not accessible\n");
        return;
    }

    if (!config->file_manager_installed)
        return;

    QString mpd_path = currentItem()->geturi;
    if (currentItem()->gettype != TP_DIRECTORY)
        mpd_path = mpd_path.left(mpd_path.lastIndexOf("/"));

    QProcess *proc = nullptr;

    QString full_path = config->mpd_musicpath + "/" + mpd_path;

    proc->startDetached(config->file_manager, QStringList() << full_path);
}


void qm_libraryView::modify_playlist(bool b_newlist,  bool b_insert)
{
    playlist_modification_list.clear();

    if (topLevelItemCount() == 0 || !b_mpd_connected)
        return;

    QList<QTreeWidgetItem*> tobeAdded;


    QTreeWidgetItemIterator sitr(this);
    while (*sitr)
    {
        if ( (*sitr)->isSelected() )
        {
            tobeAdded.push_back( *sitr );
        }
        ++sitr;
    }

    if (tobeAdded.empty())
        return;

    QListIterator<QTreeWidgetItem *> itr(tobeAdded);
    while (itr.hasNext())
    {
        QTreeWidgetItem *currentItem = itr.next();
        switch (currentItem->gettype)
        {
            case TP_STREAM:
            case TP_SONG:
            {
                qm_mpd_command newCommand;
                if (b_insert)
                    newCommand.cmd = CMD_INS;
                else
                    newCommand.cmd = CMD_ADD;
                newCommand.moveto = playlist_droppos;
                newCommand.type = currentItem->gettype;
                newCommand.uri = currentItem->geturi;
                newCommand.time = currentItem->gettime;
                newCommand.artist = currentItem->getartist;
                newCommand.album = currentItem->getalbum;
                newCommand.title = currentItem->gettitle;
                newCommand.track = currentItem->gettrack;
                if (b_insert)
                    playlist_modification_list.push_front(newCommand);
                else
                    playlist_modification_list.push_back(newCommand);
                break;
            }
            case TP_ARTIST:
            {
                if ( config->browser_libmode == LB_ID_GENRE)
                    append_to_modlist(NULL_STRING, currentItem->getartist, currentItem->getgenre, b_insert);
                else
                    append_to_modlist(NULL_STRING, currentItem->getartist, NULL_STRING, b_insert);
                break;
            }
            case TP_ALBUM:
            {
                if ( config->browser_libmode == LB_ID_GENRE)
                    append_to_modlist(currentItem->getalbum, currentItem->getartist, currentItem->getgenre, b_insert);
                else
                    append_to_modlist(currentItem->getalbum, currentItem->getartist, NULL_STRING, b_insert);
                break;
            }
            case TP_GENRE:
            {
                append_to_modlist(NULL_STRING, NULL_STRING, currentItem->getgenre, b_insert);
                break;
            }
            case TP_PLAYLIST:
            {
                append_to_modlist_plist(currentItem->geturi, b_insert);
                break;
            }
            case TP_DIRECTORY:
            {
                append_to_modlist_dir(currentItem->geturi, b_insert);
                break;
            }
            default:
                break;
        }
    }

    tobeAdded.clear();

    if (!playlist_modification_list.isEmpty())
    {
        if (b_newlist)
            mpd_cmd->clear_list();

        mpd_cmd->execute_commands(playlist_modification_list, true );

        playlist_modification_list.clear();
        playlist_droppos = 0;
    }
}


void qm_libraryView::append_to_modlist(QString album,QString artist, QString genre, bool b_insert)
{
    qm_itemList itemlist = mpd_cmd->get_songs_for_any(album, artist, genre);

    if (itemlist.empty())
        return;

    itemlist.sort();

    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        qm_mpd_command newCommand;
        if (b_insert)
            newCommand.cmd = CMD_INS;
        else
            newCommand.cmd = CMD_ADD;
        newCommand.moveto = playlist_droppos;
        newCommand.type =  static_cast<int>(iter->type);
        newCommand.uri =   iter->uri;
        newCommand.time =   static_cast<int>(iter->time);
        newCommand.artist = iter->artist;
        newCommand.album =  iter->album;
        newCommand.title =  iter->title;
        newCommand.track =  iter->track;

        if (b_insert)
            playlist_modification_list.push_front(newCommand);
        else
            playlist_modification_list.push_back(newCommand);
    }

    itemlist.clear();
}

// calls itself when a dir is found within a dir
void qm_libraryView::append_to_modlist_dir(QString path, bool b_insert)
{
    qm_itemList itemlist = mpd_cmd->get_dirlist(path);
    itemlist.sort();

    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        if ( iter->type == TP_DIRECTORY )
            append_to_modlist_dir(iter->uri, b_insert);
        else
            if ( iter->type == TP_SONG  || iter->type == TP_STREAM )
            {
                qm_mpd_command newCommand;
                if (b_insert)
                    newCommand.cmd = CMD_INS;
                else
                    newCommand.cmd = CMD_ADD;
                newCommand.moveto = playlist_droppos;
                newCommand.type =   static_cast<int>(iter->type);
                newCommand.uri =   iter->uri;
                newCommand.time =   static_cast<int>(iter->time);
                newCommand.artist = iter->artist;
                newCommand.album =  iter->album;
                newCommand.title =  iter->title;
                newCommand.track =  iter->track;
                if (b_insert)
                    playlist_modification_list.push_front(newCommand);
                else
                    playlist_modification_list.push_back(newCommand);
            }
    }
    itemlist.clear();
}


void qm_libraryView::append_to_modlist_plist(QString playlist, bool b_insert)
{
    qm_itemList itemlist = mpd_cmd->get_items_for_playlist(playlist);

    if (itemlist.empty())
        return;

    std::list<qm_listItemInfo>::iterator iter;
    for (iter = itemlist.begin(); iter != itemlist.end(); ++iter)
    {
        qm_mpd_command newCommand;
        if (b_insert)
            newCommand.cmd = CMD_INS;
        else
            newCommand.cmd = CMD_ADD;
        newCommand.uri = iter->uri;
        newCommand.moveto = playlist_droppos;

        if (iter->type == TP_STREAM)
        {
            newCommand.artist = "Stream";
            newCommand.time = 0;
            newCommand.album = tr("Info in player");
            newCommand.track = "";
            newCommand.type = TP_STREAM;
            if (b_insert)
                playlist_modification_list.push_front(newCommand);
            else
                playlist_modification_list.push_back(newCommand);
        }
        else
        {
            newCommand.time = static_cast<int>(iter->time);
            newCommand.type = TP_SONG;
            newCommand.artist = iter->artist;
            newCommand.album = iter->album;
            newCommand.title = iter->title;
            newCommand.track = iter->track;
            if (b_insert)
                playlist_modification_list.push_front(newCommand);
            else
                playlist_modification_list.push_back(newCommand);
        }
    }
}

// drop from lib on plist: find out what was dropped
void qm_libraryView::on_playlist_dropreceived(int pos)
{
    if (pos == -1) // drop on empty list
    {
        playlist_droppos = 0;
        modify_playlist(true, false);
    }
    else // drop on existing list
    {
        playlist_droppos = pos;
        modify_playlist(false, true);
    }
}


void qm_libraryView::startDrag(Qt::DropActions da)
{
    QMimeData *data;
    QModelIndexList indexes = selectedIndexes();
    if (indexes.count() > 0)
    {
        data = model()->mimeData(indexes);
        if (data == nullptr)
            return;
    }
    else
        return;
    QDrag *drag = new QDrag(this);
    drag->setPixmap(pxb_dragdrop);
    drag->setMimeData(data);
    drag->exec(da, Qt::IgnoreAction);
}


void qm_libraryView::set_auto_columns()
{
    // column_count == 0 : starting up (set in constructor)
    // column_count == 1 : artists, genres, playlists, directories
    // column_count == 2 : albums, titles : col 0,1 both variable
    // column_count == 3 : timestamp, year : col 0,1 variable, col 2 fixed
    // Last column always has setStretchLastSection(true)

    if (column_count == 0) // startup
    {
        if (config != nullptr)
            column_count = config->lib_column_count;
        else
            column_count = 1;
    }

    if (column_count == 1)
    {
        hvw_library->setSectionResizeMode(0, QHeaderView::Stretch);
    }

    if (column_count == 2)
    {
        if (config->library_autocols)
        {
            hvw_library->setSectionResizeMode(0, QHeaderView::Fixed);
        }
        else
        {
            hvw_library->setSectionResizeMode(0, QHeaderView::Interactive);
        }
    }

    if (column_count == 3)
    {
        if (config->library_autocols)
        {
            hvw_library->setSectionResizeMode(0, QHeaderView::Fixed);
            hvw_library->setSectionResizeMode(1, QHeaderView::Fixed);
        }
        else
        {
            hvw_library->setSectionResizeMode(0, QHeaderView::Interactive);
            hvw_library->setSectionResizeMode(1, QHeaderView::Interactive);
        }
    }

    resize_columns();
}


void qm_libraryView::set_column_count(int count)
{
    column_count = count;
    setColumnCount(count);
    config->lib_column_count = count;
}


void qm_libraryView::set_themed_icons(bool dark_theme)
{
    if (!dark_theme)
    {
        ic_a_append = QIcon(":/br_appendtoplist");
        ic_a_loadtags = QIcon(":/pl_br_update");
        ic_a_opendir = QIcon(":/pl_br_dir");
        ic_a_tagedit = QIcon(":/pl_br_tagedit");
        ic_a_collapse = QIcon(":/br_collapse");
        ic_dot = QIcon(":/br_dot");
        ic_track = QIcon(":/br_track");
        ic_album = QIcon(":/br_album");
        ic_artist = QIcon(":/br_artist");
        ic_genre = QIcon(":/br_genre");
        ic_playlist = QIcon(":/br_playlist");
        ic_dir = QIcon(":/pl_br_dir");
        ic_stream =  QIcon(":/br_stream");
        pxb_dragdrop = QPixmap(":/br_dragdrop");
    }
    else
    {
        ic_a_append = QIcon(":/br_appendtoplist.alt");
        ic_a_loadtags = QIcon(":/pl_br_update.alt");
        ic_a_opendir = QIcon(":/pl_br_dir.alt");
        ic_a_tagedit = QIcon(":/pl_br_tagedit.alt");
        ic_a_collapse = QIcon(":/br_collapse.alt");
        ic_dot = QIcon(":/br_dot.alt");
        ic_track = QIcon(":/br_track.alt");
        ic_album = QIcon(":/br_album.alt");
        ic_artist = QIcon(":/br_artist.alt");
        ic_genre = QIcon(":/br_genre.alt");
        ic_playlist = QIcon(":/br_playlist.alt");
        ic_dir = QIcon(":/pl_br_dir.alt");
        ic_stream =  QIcon(":/br_stream.alt");
        pxb_dragdrop = QPixmap(":/br_dragdrop.alt");
    }
    // not themed
    ic_a_newplaylist = QIcon(":/br_play");
    ic_a_delete = QIcon(":/br_reddelete");
    ic_delete = QIcon(":/br_reddelete");
    ic_check = QIcon(":/br_check");
}


void qm_libraryView::set_last_column_width()
{
    last_column_width = get_string_width(string_last_column);
}


void qm_libraryView::resize_columns()
{
    // column_count == 0 : startup (should never get here)
    // column_count == 1 : artists, genres, playlists, folders : nothing to do
    // column_count == 2 : albums : col 0 and 1 both variable
    // column_count == 3 : timestamp, year : col 0 and 1 variable, col 2 fixed
    // column_count == 3 : titles: col 0, 1 and 2 variable

    if ( column_count == 1)
    {
        setColumnWidth(0, viewport()->width());
        return;
    }

    int maxsize = 0;
    int leading = 45;
    // Column 0 uses about 45 leading pixels for the icon and the 'expand arrow'.
    // In title-mode only an icon is shown, but the 'arrow' space is still used.
    // We take it off to handle the text only, and give it back in setColumnWidth().

    if (config->library_autocols)
    {
        if ( column_count == 2)
        {
            int w_available = viewport()->width();
            int hint0 = sizeHintForColumn(0);
            int hint1 = sizeHintForColumn(1);

            if ( (hint1 <  w_available/2))
                maxsize = (w_available - leading) - hint1;
            else
                maxsize = (w_available - leading) / 2 ;

            if (hint0 - leading > maxsize)
            {
                setColumnWidth(0, maxsize + leading);
                w_available -= (maxsize + leading);
            }
            else
            {
                setColumnWidth(0, hint0);
                w_available -= (hint0);
            }

            setColumnWidth(1, w_available);
            // last col has setStretchLastSection(true)
         }

        if ( column_count == 3)
        {
            bool title_mode = (config->browser_libmode == LB_ID_TITLE ||
                        (config->browser_libmode == LB_ID_SEARCH && config->browser_searchmode == SR_ID_TITLE ));

            if (title_mode)
            {
                int w_available = viewport()->width();
                int hint0 = sizeHintForColumn(0);
                int hint1 = sizeHintForColumn(1);
                int hint2 = sizeHintForColumn(2);

                if ( (hint1 + hint2 <  ( w_available/3)*2) )
                    maxsize = w_available - (leading + hint1 + hint2);
                else
                    maxsize = (w_available - leading) / 3 ;

                if (hint0 - leading > maxsize)
                {
                    setColumnWidth(0, maxsize + leading);
                    w_available -= (maxsize + leading);
                }
                else
                {
                    setColumnWidth(0, hint0);
                    w_available -= (hint0);
                }

                if ( (hint2 <  w_available/2))
                    maxsize = w_available - hint2;
                else
                    maxsize = w_available / 2 ;

                if (hint1 > maxsize)
                {
                    setColumnWidth(1, maxsize);
                    w_available -= (maxsize);
                }
                else
                {
                    setColumnWidth(1, hint1);
                    w_available -= (hint1);
                }

                setColumnWidth(2, w_available);
                // last col has setStretchLastSection(true)
            }
            else // not title_mode
            {
                // reserve space  for the last column
                int w_available = viewport()->width() - last_column_width;
                int hint0 = sizeHintForColumn(0);
                int hint1 = sizeHintForColumn(1);

                if ( (hint1 <  w_available/2))
                    maxsize = (w_available - leading) - hint1;
                else
                    maxsize = (w_available - leading) / 2 ;

                if (hint0 - leading > maxsize)
                {
                    setColumnWidth(0, maxsize + leading);
                    w_available -= (maxsize + leading);
                }
                else
                {
                    setColumnWidth(0, hint0);
                    w_available -= (hint0);
                }

                maxsize = w_available;

                if (hint1 > maxsize)
                {
                    setColumnWidth(1, maxsize);
                    w_available -= maxsize;
                }
                else
                {
                    setColumnWidth(1, hint1);
                    w_available -= hint1;
                }

                // give the last the reserved space
                w_available += last_column_width;
                setColumnWidth(2, w_available);
            }
        }
    }
}


void qm_libraryView::resizeEvent(QResizeEvent *event)
{
    // act every 6 pixels
    resize_countdown++;
    if (resize_countdown >= 6)
    {
        resize_countdown = 0;
        resize_columns();
    }

    event->accept();
}


int qm_libraryView::get_string_width(QString str)
{
    QLabel lb_render;
    lb_render.setFont(hvw_library->font());
    lb_render.setText(str);
    int width = (lb_render.minimumSizeHint()).width();
    return width;
}

// called from player
void qm_libraryView::set_actions()
{
    // disabled/enabled in on_selection_changed()
    if (b_opendir_tagedit_set)
    {
        a_tagedit->setEnabled(config->tag_editor_installed);
        a_opendir->setEnabled(config->file_manager_installed);
    }
}


qm_libraryView::~qm_libraryView()
{}
