Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/gui/qt/playlist/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 14 kB image not shown  

Quelle  playlist_model.cpp   Sprache: C

 

/*****************************************************************************
 * Copyright (C) 2019 VLC authors and VideoLAN
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * ( at your option ) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "playlist_model.hpp"
#include "playlist_model_p.hpp"
#include <algorithm>
#include <cassert>
#include "util/shared_input_item.hpp"
#include "playlist_controller.hpp"

namespace vlc {
namespace playlist {

namespace {

static QVector<PlaylistItem> toVec(vlc_playlist_item_t *const items[],
                                   size_t len)
{
    QVector<PlaylistItem> vec;
    for (size_t i = 0; i < len; ++i)
        vec.push_back(items[i]);
    return vec;
}

template <typename RAW, typename WRAPPER>
static QVector<RAW> toRaw(const QVector<WRAPPER> &items)
{
    QVector<RAW> vec;
    int count = items.size();
    vec.reserve(count);
    for (int i = 0; i < count; ++i)
        vec.push_back(items[i].raw());
    return vec;
}
}

extern "C" { // for C callbacks

static void
on_playlist_items_reset(vlc_playlist_t *playlist,
                        vlc_playlist_item_t *const items[],
                        size_t len, void *userdata)
{
    PlaylistListModelPrivate *that = static_cast<PlaylistListModelPrivate *>(userdata);
    QVector<PlaylistItem> newContent = toVec(items, len);
    that->callAsync([=]() {
        if (that->m_playlist != playlist)
            return;
        that->onItemsReset(std::move(newContent));
    });
}

static void
on_playlist_items_added(vlc_playlist_t *playlist, size_t index,
                        vlc_playlist_item_t *const items[], size_t len,
                        void *userdata)
{
    PlaylistListModelPrivate *that = static_cast<PlaylistListModelPrivate *>(userdata);
    QVector<PlaylistItem> added = toVec(items, len);
    that->callAsync([=]() {
        if (that->m_playlist != playlist)
            return;
        that->onItemsAdded(std::move(added), index);
    });
}

static void
on_playlist_items_moved(vlc_playlist_t *playlist, size_t index, size_t count,
                        size_t target, void *userdata)
{
    PlaylistListModelPrivate *that = static_cast<PlaylistListModelPrivate *>(userdata);
    that->callAsync([=]() {
        if (that->m_playlist != playlist)
            return;
        that->onItemsMoved(index, count, target);
    });
}

static void
on_playlist_items_removed(vlc_playlist_t *playlist, size_t index, size_t count,
                          void *userdata)
{
    PlaylistListModelPrivate *that = static_cast<PlaylistListModelPrivate *>(userdata);
    that->callAsync([=](){
        if (that->m_playlist != playlist)
            return;
        that->onItemsRemoved(index, count);
    });
}

static void
on_playlist_items_updated(vlc_playlist_t *playlist, size_t index,
                          vlc_playlist_item_t *const items[], size_t len,
                          void *userdata)
{
    PlaylistListModelPrivate *that = static_cast<PlaylistListModelPrivate *>(userdata);
    QVector<PlaylistItem> updated = toVec(items, len);
    that->callAsync([=](){
        if (that->m_playlist != playlist)
            return;
        int count = updated.size();
        for (int i = 0; i < count; ++i)
            that->m_items[index + i] = updated[i]; /* sync metadata */
        that->notifyItemsChanged(index, count);
    });
}

static void
on_playlist_current_item_changed(vlc_playlist_t *playlist, ssize_t index,
                                 void *userdata)
{
    PlaylistListModelPrivate *that = static_cast<PlaylistListModelPrivate *>(userdata);
    that->callAsync([=](){
        if (that->m_playlist != playlist)
            return;
        ssize_t oldCurrent = that->m_current;
        that->m_current = index;
        if (oldCurrent != -1)
            that->notifyItemsChanged(oldCurrent, 1, {PlaylistListModel::IsCurrentRole});
        if (index != -1)
            that->notifyItemsChanged(index, 1, {PlaylistListModel::IsCurrentRole});
        emit that->q_func()->currentIndexChanged(index);
    });
}

} // extern "C"

static const struct vlc_playlist_callbacks playlist_callbacks = []{
    struct vlc_playlist_callbacks cbs {};
    cbs.on_items_reset = on_playlist_items_reset;
    cbs.on_items_added = on_playlist_items_added;
    cbs.on_items_moved = on_playlist_items_moved;
    cbs.on_items_removed = on_playlist_items_removed;
    cbs.on_items_updated = on_playlist_items_updated;
    cbs.on_current_index_changed = on_playlist_current_item_changed;
    return cbs;
}();

// private API

PlaylistListModelPrivate::PlaylistListModelPrivate(PlaylistListModel* playlistListModel)
    : q_ptr(playlistListModel)
{
}

PlaylistListModelPrivate::~PlaylistListModelPrivate()
{
    if (m_playlist && m_listener)
    {
        vlc_playlist_locker locker(m_playlist);
        vlc_playlist_RemoveListener(m_playlist, m_listener);
    }
}

void PlaylistListModelPrivate::onItemsReset(const QVector<PlaylistItem>&& newContent)
{
    Q_Q(PlaylistListModel);
    q->beginResetModel();
    m_items = newContent;
    q->endResetModel();

    m_duration = VLCDuration();
    if (m_items.size())
    {
        for(const auto& i : m_items)
        {
            m_duration += i.getDuration();
        }
    }

    emit q->countChanged(m_items.size());
}

void PlaylistListModelPrivate::onItemsAdded(const QVector<PlaylistItem>&& added, size_t index)
{
    Q_Q(PlaylistListModel);
    int count = added.size();
    q->beginInsertRows({}, index, index + count - 1);
    m_items.insert(index, count, nullptr);
    std::move(added.cbegin(), added.cend(), m_items.begin() + index);
    q->endInsertRows();

    for(const auto& i : added)
    {
        m_duration += i.getDuration();
    }

    emit q->countChanged(m_items.size());
}

void PlaylistListModelPrivate::onItemsMoved(size_t index, size_t count, size_t target)
{
    Q_Q(PlaylistListModel);
    size_t qtTarget = target;
    if (qtTarget > index)
        /* Qt interprets the target index as the index of the insertion _before_
       * the move, while the playlist core interprets it as the new index of
       * the slice _after_ the move. */

        qtTarget += count;

    q->beginMoveRows({}, index, index + count - 1, {}, qtTarget);
    if (index < target)
        std::rotate(m_items.begin() + index,
                    m_items.begin() + index + count,
                    m_items.begin() + target + count);
    else
        std::rotate(m_items.begin() + target,
                    m_items.begin() + index,
                    m_items.begin() + index + count);
    q->endMoveRows();
}

void PlaylistListModelPrivate::onItemsRemoved(size_t index, size_t count)
{
    Q_Q(PlaylistListModel);

    for(size_t i = index; i <= index + count - 1; ++i)
    {
        m_duration -= m_items.at(i).getDuration();
    }

    q->beginRemoveRows({}, index, index + count - 1);
    m_items.remove(index, count);
    q->endRemoveRows();

    //maybe we removed the only valid elements
    if (m_duration.toVLCTick() == 0 && m_duration.valid())
    {
        m_duration = VLCDuration();
        for(const auto& i : m_items)
            m_duration += i.getDuration();
    }

    emit q->countChanged(m_items.size());
}


void
PlaylistListModelPrivate::notifyItemsChanged(int idx, int count, const QVector<int> &roles)
{
    Q_Q(PlaylistListModel);
    QModelIndex first = q->index(idx, 0);
    QModelIndex last = q->index(idx + count - 1);
    emit q->dataChanged(first, last, roles);
}

// public API

PlaylistListModel::PlaylistListModel(QObject *parent)
    : QAbstractListModel(parent)
    , d_ptr(new PlaylistListModelPrivate(this))
{
}

PlaylistListModel::PlaylistListModel(vlc_playlist_t *raw_playlist, QObject *parent)
    : QAbstractListModel(parent)
    , d_ptr(new PlaylistListModelPrivate(this))
{
    setPlaylist(Playlist(raw_playlist));
}

PlaylistListModel::~PlaylistListModel()
{
}

QHash<int, QByteArray>
PlaylistListModel::roleNames() const
{
    return {
        { FilterRole, QByteArrayLiteral("filter") },
        { PreparsedRole, QByteArrayLiteral("preparsed") },
        { TitleRole, QByteArrayLiteral("title") },
        { DurationRole, QByteArrayLiteral("duration") },
        { IsCurrentRole, QByteArrayLiteral("isCurrent") },
        { ArtistRole , QByteArrayLiteral("artist") },
        { AlbumRole  , QByteArrayLiteral("album") },
        { ArtworkRole, QByteArrayLiteral("artwork") },
        { UrlRole, QByteArrayLiteral("url") }
    };
}

int
PlaylistListModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    Q_D(const PlaylistListModel);
    if (! d->m_playlist)
        return 0;
    return d->m_items.size();
}

VLCDuration
PlaylistListModel::getDuration() const
{
    Q_D(const PlaylistListModel);
    return d->m_duration;
}

PlaylistItem
PlaylistListModel::itemAt(int index) const
{
    Q_D(const PlaylistListModel);
    return d->m_items[index];
}

void PlaylistListModel::removeItems(const QVector<int>& indexes)
{
    Q_D(PlaylistListModel);
    if (!d->m_playlist)
        return;
    if (indexes.size() == 0)
        return;
    QVector<vlc_playlist_item_t *> itemsToRemove;
    std::transform(indexes.begin(), indexes.end(),std::back_inserter(itemsToRemove), [&]&nbsp;(int index) {
        return d->m_items[index].raw();
    });

    {
        vlc_playlist_locker locker(d->m_playlist);
        int ret = vlc_playlist_RequestRemove(d->m_playlist, itemsToRemove.constData(),
                                             itemsToRemove.size(), indexes[0]);
        if (ret != VLC_SUCCESS)
            throw std::bad_alloc();
    }
}

/**
 * Return the target position *after* the move has been applied, knowing the
 * index *before* the move and the list of indexes to move.
 *
 * The core playlist interprets the move target as the index of the (first)
 * item *after* the move. During a drag&drop, we know the index *before* the
 * move.
 */

static int
getMovePostTarget(const QVector<int> &sortedIndexesToMove, int preTarget)
{
    int postTarget = preTarget;
    for (int index : sortedIndexesToMove)
    {
        if (index >= preTarget)
            break;
        postTarget--;
    }
    return postTarget;
}

void
PlaylistListModel::moveItems(const QVector<int> &sortedIndexes, int target,
                             bool isPreTarget)
{
    Q_D(PlaylistListModel);
    if (!d->m_playlist)
        return;
    if (sortedIndexes.size() == 0)
        return;
    QVector<vlc_playlist_item_t*> itemsToMove;
    std::transform(sortedIndexes.begin(), sortedIndexes.end(),
                   std::back_inserter(itemsToMove),
                   [&] (int index) {
                       return d->m_items[index].raw();
                   });

    if (isPreTarget) {
        /* convert pre-target to post-target */
        target = getMovePostTarget(sortedIndexes, target);
    }

    vlc_playlist_locker locker(d->m_playlist);
    int ret = vlc_playlist_RequestMove(d->m_playlist, itemsToMove.constData(),
                                       itemsToMove.size(), target,
                                       sortedIndexes[0]);
    if (ret != VLC_SUCCESS)
        throw std::bad_alloc();
}

void
PlaylistListModel::moveItemsPre(const QVector<int> &sortedIndexes, int preTarget)
{
    return moveItems(sortedIndexes, preTarget, true);
}

void
PlaylistListModel::moveItemsPost(const QVector<int> &sortedIndexes,
                                 int postTarget)
{
    return moveItems(sortedIndexes, postTarget, false);
}

int PlaylistListModel::getCurrentIndex() const
{
    Q_D(const PlaylistListModel);
    return d->m_current;
}

/* Q_INVOKABLE */
QVariantList PlaylistListModel::getItemsForIndexes(const QVector<int> & indexes) const
{
    Q_D(const PlaylistListModel);

    QVariantList items;

    for (int index : indexes)
    {
        if (index < 0 || index >= d->m_items.count())
            continue;

        vlc_playlist_item_t * item = d->m_items[index].raw();

        if (item == nullptr)
            continue;

        input_item_t * media = vlc_playlist_item_GetMedia(item);

        if (media == nullptr)
            continue;

        items.append(QVariant::fromValue(SharedInputItem(media, true)));
    }

    return items;
}

Playlist PlaylistListModel::getPlaylist() const
{
    Q_D(const PlaylistListModel);
    if (!d->m_playlist)
        return {};
    return Playlist(d->m_playlist);
}

void PlaylistListModel::setPlaylist(vlc_playlist_t* playlist)
{
    Q_D(PlaylistListModel);
    if (d->m_playlist && d->m_listener)
    {
        vlc_playlist_locker locker(d->m_playlist);
        vlc_playlist_RemoveListener(d->m_playlist, d->m_listener);
        d->m_playlist = nullptr;
        d->m_listener = nullptr;
    }
    if (playlist)
    {
        vlc_playlist_locker locker(playlist);
        d->m_playlist = playlist;
        d->m_listener = vlc_playlist_AddListener(d->m_playlist, &playlist_callbacks, d, true);
    }
    emit playlistChanged( Playlist(d->m_playlist) );
}

void PlaylistListModel::setPlaylist(const Playlist& playlist)
{
    setPlaylist(playlist.m_playlist);
}

QVariant
PlaylistListModel::data(const QModelIndex &index, int role) const
{
    Q_D(const PlaylistListModel);
    if (!d->m_playlist)
        return {};

    ssize_t row = index.row();
    if (row < 0 || row >= d->m_items.size())
        return {};

    switch (role)
    {
    case FilterRole:
        return QVariant::fromValue<QString>(data(index, TitleRole).toString() +
                                            QStringLiteral("\n") +
                                            data(index, ArtistRole).toString() +
                                            QStringLiteral("\n") +
                                            data(index, AlbumRole).toString());
    case TitleRole:
        return d->m_items[row].getTitle();
    case IsCurrentRole:
        return row == d->m_current;
    case DurationRole:
        return QVariant::fromValue<VLCDuration>(d->m_items[row].getDuration());
    case ArtistRole:
        return d->m_items[row].getArtist();
    case AlbumRole:
        return d->m_items[row].getAlbum();
    case ArtworkRole:
        return d->m_items[row].getArtwork();
    case UrlRole:
        return d->m_items[row].getUrl();
    case PlaylistListModel::PreparsedRole:
        return d->m_items[row].preparsed();
    default:
        return {};
    }
}

} // namespace playlist
} // namespace vlc

Messung
CHZG
849910094

¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.