Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  qml_menu_wrapper.cpp   Sprache: C

 

/*****************************************************************************
 * Copyright (C) 2020 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.
 *****************************************************************************/

#include "qml_menu_wrapper.hpp"
#include "menus.hpp"
#include "medialibrary/medialib.hpp"
#include "medialibrary/mlplaylistlistmodel.hpp"
#include "medialibrary/mlplaylistmodel.hpp"
#include "medialibrary/mlbookmarkmodel.hpp"
#include "network/networkdevicemodel.hpp"
#include "network/networkmediamodel.hpp"
#include "player/player_controller.hpp"
#include "playlist/playlist_controller.hpp"
#include "playlist/playlist_model.hpp"
#include "dialogs/dialogs_provider.hpp"
#include "util/colorizedsvgicon.hpp"
#include "maininterface/navigationmodel.hpp"

// Qt includes
#include <QPainter>
#include <QSignalMapper>
#include <QScreen>
#include <QActionGroup>
#include <QAbstractProxyModel>

namespace
{
    QIcon sortIcon(QWidget *widget, int order)
    {
        assert(order == Qt::AscendingOrder || order == Qt::DescendingOrder);

        QStyleOptionHeader headerOption;
        headerOption.initFrom(widget);
        headerOption.sortIndicator = (order == Qt::AscendingOrder)
                ? QStyleOptionHeader::SortDown
                : QStyleOptionHeader::SortUp;

        QStyle *style = qApp->style();
        int arrowsize = style->pixelMetric(QStyle::PM_HeaderMarkSize, &headerOption, widget);
        if (arrowsize <= 0)
            arrowsize = 32;

        qreal dpr = widget ? widget->devicePixelRatioF() : 1.0;
        headerOption.rect = QRect(0, 0, arrowsize, arrowsize);

        QPixmap arrow(arrowsize * dpr, arrowsize * dpr);
        arrow.setDevicePixelRatio(dpr);
        arrow.fill(Qt::transparent);

        {
            QPainter arrowPainter(&arrow);
            style->drawPrimitive(QStyle::PE_IndicatorHeaderArrow, &headerOption, &arrowPainter, widget);
        }

        return QIcon(arrow);
    }
}

void StringListMenu::popup(const QPoint &point, const QVariantList &stringList)
{
    assert(m_ctx);
    QMenu *m = newMenu();

    for (int i = 0; i != stringList.size(); ++i)
    {
        const QVariant& variant = stringList[i];
        QString str;
        QString icon;

        if (variant.typeId() == QMetaType::QString)
        {
            str = variant.toString();
        }
        else
        {
            assert(variant.typeId() == QMetaType::QVariantMap);
            const auto variantMap = variant.toMap();

            str = variantMap[QStringLiteral("text")].toString();
            icon = variantMap[QStringLiteral("icon_svg")].toString();
        }

        const auto action = m->addAction(str, this, [this, i, str]()
                                         {
                                             emit selected(i, str);
                                         });

        if (!icon.isEmpty())
        {
            assert(action);
            action->setIcon(ColorizedSvgIcon::colorizedIconForWidget(icon, m));
        }
    }

    m->popup(point);
}

QMenu *BasicMenuContainer::newMenu()
{
    QMenu *m = new VLCMenu(m_ctx->getIntf());
    m->setAttribute(Qt::WA_DeleteOnClose);
    if (m_prevMenu)
    {
        setVisible(false);
        m_prevMenu->disconnect(this);
    }

    m_prevMenu = m;
    connect(m, &QMenu::aboutToShow, this, [this](){ setVisible(true);});
    connect(m, &QMenu::aboutToHide, this, [this](){ setVisible(false);});
    return m;
}

void BasicMenuContainer::setVisible(bool visible)
{
    if (m_visible == visible) return;

    m_visible = visible;
    emit visibleChanged();
}

// SortMenu

void SortMenu::popup(const QPoint &point, const bool popupAbovePoint, const QVariantList &model)
{
    assert(m_ctx);
    m_menu = std::make_unique<VLCMenu>(m_ctx->getIntf());

    connect( m_menu.get(), &QMenu::aboutToShow, this, [this]() {
        m_shown = true;
        shownChanged();
    } );
    connect( m_menu.get(), &QMenu::aboutToHide, this, [this]() {
        m_shown = false;
        shownChanged();
    } );

    const auto actionGroup = new QActionGroup(m_menu.get());
    actionGroup->setExclusive(true);

    // model => [{text: "", checked: <bool>, order: <sort order> if checked else <invalid>}...]
    for (int i = 0; i != model.size(); ++i)
    {
        const auto obj = model[i].toMap();

        auto action = m_menu->addAction(obj.value("text").toString());
        action->setActionGroup(actionGroup);
        action->setCheckable(true);

        const bool checked = obj.value("checked").toBool();
        action->setChecked(checked);

        if (checked)
            action->setIcon(sortIcon(m_menu.get(), obj.value("order").toInt()));

        connect(action, &QAction::triggered, this, [this, i]()
        {
            emit selected(i);
        });
    }

    onPopup(m_menu.get());

    if (popupAbovePoint)
        m_menu->popup(QPoint(point.x(), point.y() - m_menu->sizeHint().height()));
    else
        m_menu->popup(point);
}

void SortMenu::close()
{
    if (m_menu)
        m_menu->close();
}

// Protected functions

/* virtual */ void SortMenu::onPopup(QMenu *) {}

// SortMenuVideo

// Protected SortMenu reimplementation

void SortMenuVideo::onPopup(QMenu * menu) /* override */
{
    if (!m_ctx)
        return;

    menu->addSeparator();

    struct
    {
        const char * title;

        MainCtx::Grouping grouping;
    }
    entries[] =
    {
        { N_("Do not group videos"), MainCtx::GROUPING_NONE },
        { N_("Group by name"), MainCtx::GROUPING_NAME },
        { N_("Group by folder"), MainCtx::GROUPING_FOLDER },
    };

    QActionGroup * group = new QActionGroup(this);

    int index = m_ctx->grouping();

    for (size_t i = 0; i < ARRAY_SIZE(entries); i++)
    {
        QAction * action = menu->addAction(qtr(entries[i].title));

        action->setCheckable(true);

        MainCtx::Grouping grouping = entries[i].grouping;

        connect(action, &QAction::triggered, this, [this, grouping]()
        {
            emit this->grouping(grouping);
        });

        group->addAction(action);

        if (index == grouping)
            action->setChecked(true);
    }
}

void SortMenuAlbums::onPopup(QMenu *menu)
{
    if (!m_sectionsVisible)
        return;

    assert(m_ctx);
    assert(menu);

    menu->addSeparator();

    QAction *action = menu->addAction(qtr("Album sections"));
    action->setCheckable(true);
    action->setChecked(m_ctx->albumSections());
    connect(action, &QAction::toggled, this, [this] (bool enabled) {
        if (Q_LIKELY(m_ctx))
            m_ctx->setAlbumSections(enabled);
    });
}

QmlGlobalMenu::QmlGlobalMenu(QObject *parent)
    : VLCMenuBar(parent)
{
}

void QmlGlobalMenu::popup(QPoint pos)
{
    if (!m_ctx)
        return;

    qt_intf_t* p_intf = m_ctx->getIntf();
    if (!p_intf)
        return;

    m_menu = std::make_unique<VLCMenu>(m_ctx->getIntf());
    QMenu* submenu;

    connect( m_menu.get(), &QMenu::aboutToShow, this, [this]() {
        m_shown = true;
        shownChanged();
        aboutToShow();
    });
    connect( m_menu.get(), &QMenu::aboutToHide, this, [this]() {
        m_shown = false;
        shownChanged();
        aboutToHide();
    });

    submenu = m_menu->addMenu(qtr( "&Media" ));
    FileMenu( p_intf, submenu );

    /* Dynamic menus, rebuilt before being showed */
    submenu = m_menu->addMenu(qtr( "P&layback" ));
    NavigMenu( p_intf, submenu );

    submenu = m_menu->addMenu(qtr( "&Audio" ));
    AudioMenu( p_intf, submenu );

    submenu = m_menu->addMenu(qtr( "&Video" ));
    VideoMenu( p_intf, submenu );

    submenu = m_menu->addMenu(qtr( "Subti&tle" ));
    SubtitleMenu( p_intf, submenu );

    submenu = m_menu->addMenu(qtr( "Tool&s" ));
    ToolsMenu( p_intf, submenu );

    /* View menu, a bit different */
    submenu = m_menu->addMenu(qtr( "V&iew" ));
    ViewMenu( p_intf, submenu );

    submenu = m_menu->addMenu(qtr( "&Help" ));
    HelpMenu( p_intf, submenu );

    m_menu->popup(pos);
}

void QmlGlobalMenu::close()
{
    if (m_menu)
        m_menu->close();
}

QmlMenuBarMenu::QmlMenuBarMenu(QmlMenuBar* menubar, QWidget* parent)
    : QMenu(parent)
    , m_menubar(menubar)
{}

QmlMenuBarMenu::~QmlMenuBarMenu()
{
}

void QmlMenuBarMenu::mouseMoveEvent(QMouseEvent* mouseEvent)
{
    QPoint globalPos =m_menubar-> m_menu->mapToGlobal(mouseEvent->pos());
    if (m_menubar->getmenubar()->contains(m_menubar->getmenubar()->mapFromGlobal(globalPos))
        && !m_menubar->m_button->contains(m_menubar->m_button->mapFromGlobal(globalPos)))
    {
        m_menubar->setopenMenuOnHover(true);
        close();
        return;
    }
    QMenu::mouseMoveEvent(mouseEvent);
}

void QmlMenuBarMenu::keyPressEvent(QKeyEvent * event)
{
    QMenu::keyPressEvent(event);
    if (!event->isAccepted()
        && (event->key() == Qt::Key_Left  || event->key() == Qt::Key_Right))
    {
        event->accept();
        emit m_menubar->navigateMenu(event->key() == Qt::Key_Left ? -1 : 1);
    }
}

void QmlMenuBarMenu::keyReleaseEvent(QKeyEvent * event)
{
    QMenu::keyReleaseEvent(event);
}

QmlMenuBar::QmlMenuBar(QObject *parent)
    : VLCMenuBar(parent)
{
}

 QString QmlMenuBar::menuEntryTitle(MenuEntry entry)
{
    switch (entry)
    {
    case MEDIA:
        return qtr("&Media");
    case PLAYBACK:
        return qtr("&Playback");
    case VIDEO:
        return qtr("&Video");
    case AUDIO:
        return qtr("&Audio");
    case SUBTITLE:
        return qtr("&Subtitle");
    case TOOL:
        return qtr("&Tools");
    case VIEW:
        return qtr("V&iew");
    case HELP:
        return qtr("&Help");
    }
    vlc_assert_unreachable();
    return "";
}

void QmlMenuBar::popupMenuCommon( QQuickItem* button, std::function<void(QMenu*)> createMenuFunc)
{
    if (!m_ctx || !m_menubar || !button)
        return;

    qt_intf_t* p_intf = m_ctx->getIntf();
    if (!p_intf)
        return;

    m_menu = std::make_unique<QmlMenuBarMenu>(this);
    createMenuFunc(m_menu.get());
    m_button = button;
    m_openMenuOnHover = false;
    connect(m_menu.get(), &QMenu::aboutToHide, this, &QmlMenuBar::onMenuClosed);
    QPointF position = button->mapToGlobal(QPoint(0, button->height()));
    m_menu->popup(position.toPoint());
}


void QmlMenuBar::setupMenuEntry(QMenu* menu, MenuEntry entry)
{
    qt_intf_t* p_intf = m_ctx->getIntf();
    switch (entry) {
    case MEDIA:
        FileMenu(p_intf, menu);
        break;
    case PLAYBACK:
        NavigMenu(p_intf, menu);
        break;
    case VIDEO:
        VideoMenu(p_intf, menu);
        break;
    case AUDIO:
        AudioMenu(p_intf, menu);
        break;
    case SUBTITLE:
        SubtitleMenu(p_intf, menu);
        break;
    case TOOL:
        ToolsMenu(p_intf, menu);
        break;
    case VIEW:
        ViewMenu( p_intf, menu );
        break;
    case HELP:
        HelpMenu( p_intf, menu );
        break;
    default:
        vlc_assert_unreachable();
    };
}

void QmlMenuBar::popupMenuEntry(QQuickItem* button, MenuEntry entry)
{
    popupMenuCommon(button, [this, entry](QMenu* menu) {
        setupMenuEntry(menu, entry);
    });
}

void QmlMenuBar::popupMediaMenu( QQuickItem* button )
{
    popupMenuCommon(button, [this](QMenu* menu) {
        qt_intf_t* p_intf = m_ctx->getIntf();
        FileMenu( p_intf, menu );
    });
}

void QmlMenuBar::popupPlaybackMenu( QQuickItem* button )
{
    popupMenuCommon(button, [this](QMenu* menu) {
        NavigMenu( m_ctx->getIntf(), menu );
    });
}

void QmlMenuBar::popupAudioMenu(QQuickItem* button )
{
    popupMenuCommon(button, [this](QMenu* menu) {
        AudioMenu( m_ctx->getIntf(), menu );
    });
}

void QmlMenuBar::popupVideoMenu( QQuickItem* button )
{
    popupMenuCommon(button, [this](QMenu* menu) {
        VideoMenu( m_ctx->getIntf(), menu );
    });
}

void QmlMenuBar::popupSubtitleMenu( QQuickItem* button )
{
    popupMenuCommon(button, [this](QMenu* menu) {
        SubtitleMenu( m_ctx->getIntf(), menu );
    });
}


void QmlMenuBar::popupToolsMenu( QQuickItem* button )
{
    popupMenuCommon(button, [this](QMenu* menu) {
        ToolsMenu( m_ctx->getIntf(), menu );
    });
}

void QmlMenuBar::popupViewMenu(QQuickItem* button )
{
    popupMenuCommon(button, [this](QMenu* menu) {
        qt_intf_t* p_intf = m_ctx->getIntf();
        ViewMenu( p_intf, menu );
    });
}

void QmlMenuBar::popupHelpMenu( QQuickItem* button )
{
    popupMenuCommon(button, [this](QMenu* menu) {
        qt_intf_t* p_intf = m_ctx->getIntf();
        HelpMenu( p_intf, menu );
    });
}

void QmlMenuBar::popupExtraActionsMenu( QQuickItem* button, const QList<MenuEntry>& extraActions )
{
    popupMenuCommon(button, [this, extraActions](QMenu* menu) {
        for (auto action: extraActions) {
            QMenu* subMenu = menu->addMenu(menuEntryTitle(action));
            setupMenuEntry(subMenu, action);
        }
    });
}

void QmlMenuBar::onMenuClosed()
{
    if (!m_openMenuOnHover)
        emit menuClosed();
}

// QmlMenuPositioner

/* explicit */ QmlMenuPositioner::QmlMenuPositioner(QObject * parent) : QObject(parent) {}

// Interface

void QmlMenuPositioner::popup(QMenu * menu, const QPoint & position, bool above)
{
    menu->removeEventFilter(this);

    if (above == false)
    {
        menu->popup(position);

        return;
    }

    m_position = position;

    menu->installEventFilter(this);

    // NOTE: QMenu::height() returns an invalid height until the initial popup call.
    menu->popup(position);
}

// Public events

bool QmlMenuPositioner::eventFilter(QObject * object, QEvent * event)
{
    if (event->type() == QEvent::Resize)
    {
        QScreen * screen = QGuiApplication::screenAt(m_position);

        if (screen == nullptr)
            return QObject::eventFilter(object, event);

        QMenu * menu = static_cast<QMenu *> (object);

        int width  = menu->width();
        int height = menu->height();

        QRect geometry = screen->availableGeometry();

        int x = geometry.x();
        int y = geometry.y();

        // NOTE: We want a position within the screen boundaries.

        x = qBound(x, m_position.x(), x + geometry.width() - width);

        y = qBound(y, m_position.y() - height, y + geometry.height() - height);

        menu->move(QPoint(x, y));
    }

    return QObject::eventFilter(object, event);
}

// QmlBookmarkMenu

/* explicit */ QmlBookmarkMenu::QmlBookmarkMenu(QObject * parent)
    : QObject(parent)
{}

// Interface

/* Q_INVOKABLE */ void QmlBookmarkMenu::popup(const QPoint & position, bool above)
{
    if (m_ctx == nullptr || m_player == nullptr)
        return;

    m_menu = std::make_unique<VLCMenu>(m_ctx->getIntf());

    connect(m_menu.get(), &QMenu::aboutToHide, this, &QmlBookmarkMenu::aboutToHide);
    connect(m_menu.get(), &QMenu::aboutToShow, this, &QmlBookmarkMenu::aboutToShow);

    QAction * sectionTitles    = m_menu->addSection(qtr("Titles"));
    QAction * sectionChapters  = m_menu->addSection(qtr("Chapters"));
    QAction * sectionBookmarks = nullptr;

    if (m_ctx->hasMediaLibrary())
        sectionBookmarks = m_menu->addSection(qtr("Bookmarks"));

    // Titles

    TitleListModel * titles = m_player->getTitles();

    sectionTitles->setVisible(titles->rowCount() != 0);

    ListMenuHelper * helper = new ListMenuHelper(m_menu.get(), titles, sectionChapters, m_menu.get());

    connect(helper, &ListMenuHelper::select, [titles](int index, bool)
    {
        titles->setData(titles->index(index), true, Qt::CheckStateRole);
    });

    connect(helper, &ListMenuHelper::countChanged, [sectionTitles](int count)
    {
        // NOTE: The section should only be visible when the model has content.
        sectionTitles->setVisible(count != 0);
    });

    // Chapters

    ChapterListModel * chapters = m_player->getChapters();

    sectionChapters->setVisible(chapters->rowCount() != 0);

    helper = new ListMenuHelper(m_menu.get(), chapters, sectionBookmarks, m_menu.get());

    connect(helper, &ListMenuHelper::select, [chapters](int index, bool)
    {
        chapters->setData(chapters->index(index), true, Qt::CheckStateRole);
    });

    connect(helper, &ListMenuHelper::countChanged, [sectionChapters](int count)
    {
        // NOTE: The section should only be visible when the model has content.
        sectionChapters->setVisible(count != 0);
    });

    // Bookmarks
    if (m_ctx->hasMediaLibrary())
    {
 m_menu->addAction(qtr("&Manage"), THEDP, &DialogsProvider::bookmarksDialog )->setShortcut(QKeySequence("Ctrl+B"));
        m_menu->addSeparator();

        MLBookmarkModel * bookmarks = new MLBookmarkModel(m_menu.get());
        bookmarks->setPlayer(m_player->getPlayer());
        bookmarks->setMl(m_ctx->getMediaLibrary());

        helper = new ListMenuHelper(m_menu.get(), bookmarks, nullptr, m_menu.get());

        connect(helper, &ListMenuHelper::select, [bookmarks](int index, bool)
        {
            bookmarks->select(bookmarks->index(index, 0));
        });
    }

    m_positioner.popup(m_menu.get(), position, above);
}

void QmlBookmarkMenu::close()
{
    if (m_menu)
        m_menu->close();
}

// QmlProgramMenu

/* explicit */ QmlProgramMenu::QmlProgramMenu(QObject * parent)
    : QObject(parent)
{}

// Interface

/* Q_INVOKABLE */ void QmlProgramMenu::popup(const QPoint & position, bool above)
{
    assert(m_ctx);
    if (m_player == nullptr)
        return;

    m_menu = std::make_unique<VLCMenu>(m_ctx->getIntf());

    connect(m_menu.get(), &QMenu::aboutToHide, this, &QmlProgramMenu::aboutToHide);
    connect(m_menu.get(), &QMenu::aboutToShow, this, &QmlProgramMenu::aboutToShow);

    m_menu->addSection(qtr("Programs"));

    ProgramListModel * programs = m_player->getPrograms();

    ListMenuHelper * helper = new ListMenuHelper(m_menu.get(), programs, nullptr, m_menu.get());

    connect(helper, &ListMenuHelper::select, [programs](int index, bool)
    {
        programs->setData(programs->index(index), true, Qt::CheckStateRole);
    });

    m_positioner.popup(m_menu.get(), position, above);
}

void QmlProgramMenu::close()
{
    if (m_menu)
        m_menu->close();
}

// QmlRendererMenu

/* explicit */ QmlRendererMenu::QmlRendererMenu(QObject * parent)
    : QObject(parent)
{}

// Interface

/* Q_INVOKABLE */ void QmlRendererMenu::popup(const QPoint & position, bool above)
{
    if (m_ctx == nullptr)
        return;

    m_menu = std::make_unique<RendererMenu>(nullptr, m_ctx->getIntf(), m_ctx->getIntf()->p_mainPlayerController);

    connect(m_menu.get(), &QMenu::aboutToHide, this, &QmlRendererMenu::aboutToHide);
    connect(m_menu.get(), &QMenu::aboutToShow, this, &QmlRendererMenu::aboutToShow);

    m_positioner.popup(m_menu.get(), position, above);
}

void QmlRendererMenu::close()
{
    if (m_menu)
        m_menu->close();
}

// Tracks

// QmlTrackMenu

/* explicit */ QmlTrackMenu::QmlTrackMenu(QObject * parent) : QObject(parent) {}

// Interface

/* Q_INVOKABLE */ void QmlTrackMenu::popup(const QPoint & position)
{
    assert(m_ctx);
    m_menu = std::make_unique<VLCMenu>(m_ctx->getIntf());

    beforePopup(m_menu.get());

    m_menu->popup(position);
}

// QmlSubtitleMenu

/* explicit */ QmlSubtitleMenu::QmlSubtitleMenu(QObject * parent) : QmlTrackMenu(parent) {}

// Protected QmlTrackMenu implementation

void QmlSubtitleMenu::beforePopup(QMenu * menu) /* override */
{
    menu->addAction(qtr("Open file"), this, [this]()
    {
        emit triggered(Open);
    });

    menu->addAction(QIcon(":/menu/sync.svg"), qtr("Synchronize"), this, [this]()
    {
        emit triggered(Synchronize);
    });

    menu->addAction(ColorizedSvgIcon::colorizedIconForWidget(":/menu/download.svg", menu), qtr("Search online"), this, [this]()
    {
        emit triggered(Download);
    });

    menu->addSeparator();

    QAction * action = menu->addAction(qtr("Select multiple"), this, [this]()
    {
        TrackListModel * tracks = this->m_player->getSubtitleTracks();

        tracks->setMultiSelect(!(tracks->getMultiSelect()));
    });

    action->setCheckable(true);

    action->setChecked(m_player->getSubtitleTracks()->getMultiSelect());
}

// QmlAudioMenu

/* explicit */ QmlAudioMenu::QmlAudioMenu(QObject * parent) : QmlTrackMenu(parent) {}

// Protected QmlTrackMenu implementation

void QmlAudioMenu::beforePopup(QMenu * menu) /* override */
{
    menu->addAction(qtr("Open file"), this, [this]()
    {
        emit triggered(Open);
    });

    menu->addAction(QIcon(":/menu/sync.svg"), qtr("Synchronize"), this, [this]()
    {
        emit triggered(Synchronize);
    });
}

QmlAudioContextMenu::QmlAudioContextMenu(QObject *parent)
    : VLCMenuBar(parent)
{
}

void QmlAudioContextMenu::popup(const QPoint & position)
{
    if (!m_ctx)
        return;

    qt_intf_t* p_intf = m_ctx->getIntf();
    if (!p_intf)
        return;

    m_menu.reset(PopupMenu(p_intf, false));
    if (m_menu)
        m_menu->popup(position);
}

//=================================================================================================
// PlaylistListContextMenu
//=================================================================================================

PlaylistListContextMenu::PlaylistListContextMenu(QObject * parent)
    : BasicMenuContainer(parent)
{}


void PlaylistListContextMenu::popup(const QModelIndexList & selected, QPoint pos, QVariantMap)
{
    assert(m_ctx);

    if (!m_model)
        return;

    QVariantList ids;

    for (const QModelIndex & modelIndex : selected)
        ids.push_back(m_model->data(modelIndex, MLPlaylistListModel::PLAYLIST_ID));

    auto menu = newMenu();

    MediaLib * ml = m_model->ml();

    QAction * action = menu->addAction(qtr("Add and play"));

    connect(action, &QAction::triggered, [ml, ids]() {
        ml->addAndPlay(ids);
    });

    action = menu->addAction(qtr("Enqueue"));

    connect(action, &QAction::triggered, [ml, ids]() {
        ml->addToPlaylist(ids);
    });

    if (ids.count() == 1)
    {
        action = menu->addAction(qtr("Rename"));

        QModelIndex index = selected.first();

        connect(action, &QAction::triggered, [this, index]() {
            m_model->showDialogRename(index);
        });
    }

    action = menu->addAction(qtr("Delete"));

    connect(action, &QAction::triggered, this, &PlaylistListContextMenu::requestDeleteSelectedPlaylists);

    menu->popup(pos);
}

//=================================================================================================
// PlaylistMediaContextMenu
//=================================================================================================


void PlaylistMediaContextMenu::popup(const QModelIndexList & selected, QPoint pos,
                                     QVariantMap options)
{
    assert(m_ctx);

    if (!m_model)
        return;

    QVariantList ids;

    for (const QModelIndex& modelIndex : selected)
        ids.push_back(m_model->data(modelIndex, MLPlaylistModel::MEDIA_ID));

    auto menu =newMenu();

    MediaLib * ml = m_model->ml();

    QAction * action = menu->addAction(qtr("Add and play"));

    connect(action, &QAction::triggered, [ml, ids]() {
        ml->addAndPlay(ids);
    });

    action = menu->addAction(qtr("Enqueue"));

    connect(action, &QAction::triggered, [ml, ids]() {
        ml->addToPlaylist(ids);
    });

    action = menu->addAction(qtr("Add to playlist"));

    connect(action, &QAction::triggered, [ids]() {
        DialogsProvider::getInstance()->playlistsDialog(ids);
    });

    action = menu->addAction(qtr("Play as audio"));

    connect(action, &QAction::triggered, [ml, ids]() {
        ml->addAndPlay(ids, {":no-video"});
    });

    if (options.contains("information") && options["information"].typeId() == QMetaType::Int) {
        action = menu->addAction(qtr("Information"));

        QSignalMapper * mapper = new QSignalMapper(menu);

        connect(action, &QAction::triggered, mapper, QOverload<>::of(&QSignalMapper::map));

        mapper->setMapping(action, options["information"].toInt());
        connect(mapper, &QSignalMapper::mappedInt,
                this, &PlaylistMediaContextMenu::showMediaInformation);
    }

    menu->addSeparator();

    action = menu->addAction(qtr("Remove Selected"));

    action->setIcon(QIcon(":/menu/remove.svg"));

    connect(action, &QAction::triggered, [this, selected]() {
        m_model->remove(selected);
    });

    menu->popup(pos);
}

//=================================================================================================

void NetworkMediaContextMenu::popup(const QModelIndexList& selected, QPoint pos)
{
    assert(m_ctx);

    if (!m_model)
        return;

    auto menu = newMenu();
    QAction* action;

    action = menu->addAction( qtr("Add and play") );
    connect(action, &QAction::triggered, [this, selected]( ) {
        m_model->addAndPlay(selected);
    });

    action = menu->addAction( qtr("Enqueue") );
    connect(action, &QAction::triggered, [this, selected]( ) {
        m_model->addToPlaylist(selected);
    });

    action = menu->addAction( qtr("Information") );
    connect(action, &QAction::triggered, [this, selected]( ) {
        if (selected.isEmpty()) return;

        m_model->getItemsForIndexes(selected, [](const QVariantList& items) {
            if (items.isEmpty()) return;

            QVariant firstItem = items.first();

            if (firstItem.canConvert<SharedInputItem>()) {
                 SharedInputItem sii = firstItem.value<SharedInputItem>();
                 DialogsProvider::getInstance()->mediaInfoDialog(sii);
            }
        });
    });

    bool canBeIndexed = false;
    unsigned countIndexed = 0;
    for (const QModelIndex& idx : selected)
    {
        QVariant canIndex = m_model->data(m_model->index(idx.row()), NetworkMediaModel::NETWORK_CANINDEX );
        if (canIndex.isValid() && canIndex.toBool())
            canBeIndexed = true;
        else
            continue;
        QVariant isIndexed = m_model->data(m_model->index(idx.row()), NetworkMediaModel::NETWORK_INDEXED );
        if (!isIndexed.isValid())
            continue;
        if (isIndexed.toBool())
            ++countIndexed;
    }

    if (canBeIndexed)
    {
        bool removeFromML = countIndexed > 0;
        action = menu->addAction(removeFromML
            ? qtr("Remove from Media Library")
            : qtr("Add to Media Library"));

        connect(action, &QAction::triggered, [this, selected, removeFromML]( ) {
            for (const QModelIndex& idx : selected) {
                m_model->setData(m_model->index(idx.row()), !removeFromML, NetworkMediaModel::NETWORK_INDEXED);
            }
        });
    }

    menu->popup(pos);
}

void NetworkDeviceContextMenu::popup(const QModelIndexList& selected, QPoint pos)
{
    assert(m_ctx);

    if (!m_model)
        return;

    auto menu = newMenu();
    QAction* action;

    action = menu->addAction( qtr("Add and play") );
    connect(action, &QAction::triggered, [this, selected]( ) {
        m_model->addAndPlay(selected);
    });

    action = menu->addAction( qtr("Enqueue") );
    connect(action, &QAction::triggered, [this, selected]( ) {
        m_model->addToPlaylist(selected);
    });

    action = menu->addAction( qtr("Information") );
    connect(action, &QAction::triggered, [this, selected]( ) {
        if (selected.isEmpty()) return;

        m_model->getItemsForIndexes(selected, [](const QVariantList& items) {
            if (items.isEmpty()) return;

            QVariant firstItem = items.first();

            if (firstItem.canConvert<SharedInputItem>()) {
                 SharedInputItem sii = firstItem.value<SharedInputItem>();
                 DialogsProvider::getInstance()->mediaInfoDialog(sii);
            }
        });
    });

    menu->popup(pos);
}

PlaylistContextMenu::PlaylistContextMenu(QObject* parent)
    : QObject(parent)
{}

void PlaylistContextMenu::popup(int selectedIndex, QPoint pos )
{
    assert(m_ctx);

    if (!m_controler || !m_model || !m_selectionModel)
        return;

    m_menu = std::make_unique<VLCMenu>(m_ctx->getIntf());
    QAction* action;

    QList<QUrl> selectedUrlList;
    for (const int modelIndex : m_selectionModel->selectedIndexesFlat())
        selectedUrlList.push_back(m_model->itemAt(modelIndex).getUrl());

    PlaylistItem selectedItem;
    if (selectedIndex >= 0)
        selectedItem = m_model->itemAt(selectedIndex);

    if (selectedItem)
    {
        action = m_menu->addAction( qtr("Play") );
        connect(action, &QAction::triggered, [this, selectedIndex]( ) {
            m_controler->goTo(selectedIndex, true);
        });

        m_menu->addSeparator();
    }

    if (m_controler->currentIndex() != -1)
    {
        action = m_menu->addAction( qtr("Jump to current playing"));
        connect(action, &QAction::triggered, this, &PlaylistContextMenu::jumpToCurrentPlaying);
    }

    if (m_selectionModel->hasSelection()) {
        action = m_menu->addAction( qtr("Stream") );
        connect(action, &QAction::triggered, [selectedUrlList]( ) {
            DialogsProvider::getInstance()->streamingDialog(selectedUrlList, false);
        });

        action = m_menu->addAction( qtr("Save") );
        connect(action, &QAction::triggered, [selectedUrlList]( ) {
            DialogsProvider::getInstance()->streamingDialog(selectedUrlList, true);
        });

        m_menu->addSeparator();
    }

    if (selectedItem) {
        action = m_menu->addAction( qtr("Information") );
        action->setIcon(QIcon(":/menu/info.svg"));
        connect(action, &QAction::triggered, [selectedItem]( ) {
            DialogsProvider::getInstance()->mediaInfoDialog(selectedItem);
        });

        m_menu->addSeparator();

        action = m_menu->addAction( qtr("Show Containing Directory...") );
        action->setIcon(QIcon(":/menu/folder.svg"));
        connect(action, &QAction::triggered, [this, selectedItem]( ) {
            m_controler->explore(selectedItem);
        });

        m_menu->addSeparator();
    }

    action = m_menu->addAction( qtr("Add File...") );

    action->setIcon(ColorizedSvgIcon::colorizedIconForWidget(":/menu/add.svg", m_menu.get()));
    connect(action, &QAction::triggered, []( ) {
        DialogsProvider::getInstance()->simpleOpenDialog(false);
    });

    action = m_menu->addAction( qtr("Add Directory...") );
    action->setIcon(ColorizedSvgIcon::colorizedIconForWidget(":/menu/add.svg", m_menu.get()));
    connect(action, &QAction::triggered, []( ) {
        DialogsProvider::getInstance()->PLAppendDir();
    });

    action = m_menu->addAction( qtr("Advanced Open...") );
    action->setIcon(ColorizedSvgIcon::colorizedIconForWidget(":/menu/add.svg", m_menu.get()));
    connect(action, &QAction::triggered, []( ) {
        DialogsProvider::getInstance()->PLAppendDialog();
    });

    m_menu->addSeparator();

    if (m_selectionModel->hasSelection())
    {
        action = m_menu->addAction( qtr("Save Play Queue to File...") );
        connect(action, &QAction::triggered, []( ) {
            DialogsProvider::getInstance()->savePlayingToPlaylist();
        });

        m_menu->addSeparator();

        action = m_menu->addAction( qtr("Remove Selected") );
        action->setIcon(QIcon(":/menu/remove.svg"));
        connect(action, &QAction::triggered, [this]( ) {
            m_model->removeItems(m_selectionModel->selectedIndexesFlat());
        });
    }


    if (m_model->rowCount() > 0)
    {
        action = m_menu->addAction( qtr("Clear the play queue") );
        action->setIcon(QIcon(":/menu/clear.svg"));
        connect(action, &QAction::triggered, [this]( ) {
            m_controler->clear();
        });

        m_menu->addSeparator();

        using namespace vlc::playlist;
        PlaylistController::SortKey currentKey = m_controler->getSortKey();
        PlaylistController::SortOrder currentOrder = m_controler->getSortOrder();

        QMenu* sortMenu = m_menu->addMenu(qtr("Sort by"));
        QActionGroup * group = new QActionGroup(sortMenu);

        auto addSortAction = [&](const QString& label, PlaylistController::SortKey key, PlaylistController::SortOrder order) {
            QAction* action = sortMenu->addAction(label);
            connect(action, &QAction::triggered, this, [this, key, order]( ) {
                m_controler->sort(key, order);
            });
            action->setCheckable(true);
            action->setActionGroup(group);
            if (key == currentKey && currentOrder == order)
                action->setChecked(true);
        };

        for (const QVariant& it: m_controler->getSortKeyTitleList())
        {
            const QVariantMap varmap = it.toMap();

            auto key = static_cast<PlaylistController::SortKey>(varmap.value("key").toInt());
            QString label = varmap.value("text").toString();

            addSortAction(qtr("%1 Ascending").arg(label), key, PlaylistController::SORT_ORDER_ASC);
            addSortAction(qtr("%1 Descending").arg(label), key, PlaylistController::SORT_ORDER_DESC);
        }

        action = m_menu->addAction( qtr("Shuffle the play queue") );
        action->setIcon(ColorizedSvgIcon::colorizedIconForWidget(":/menu/ic_fluent_arrow_shuffle.svg", m_menu.get()));
        connect(action, &QAction::triggered, this, [this]( ) {
            m_controler->shuffle();
        });

        if (m_proxyModel)
        {
            if (m_proxyModel->rowCount() != m_model->rowCount())
            {
                m_menu->addSeparator();

                // Actions that are available when the view uses a proxy model:

                action = m_menu->addAction( qtr("Discard the filtered out items"));
                connect(action, &QAction::triggered, [this]( ) {
                    bool proceed = true;

                    if (const auto dp = DialogsProvider::getInstance())
                    {
                        proceed = dp->questionDialog(QStringLiteral("Discard the filtered out items"),
                                                     QStringLiteral("Do you really want to discard the items that are not displayed at the moment?"));
                    }

                    const auto count = m_model->rowCount() - m_proxyModel->rowCount();

                    if (proceed && (count > 0))
                    {
                        QList<int> items;
                        items.reserve(count);

                        for (int i = 0; i < m_model->rowCount(); ++i)
                        {
                            const auto mappedIndex = m_proxyModel->mapFromSource(m_model->index(i, 0));

                            if (!mappedIndex.isValid() || !(m_proxyModel->checkIndex(mappedIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid)))
                            {
                                items.push_back(i);
                            }
                        }

                        if (items.count() > 0)
                        {
                            m_model->removeItems(items);
                            emit discardedFilteredOutItems();
                        }
                    }
                });
            }
        }
    }

    m_menu->popup(pos);
}

NavigationBarContextMenu::NavigationBarContextMenu(QObject *parent)
    : BasicMenuContainer(parent)
{

}

void NavigationBarContextMenu::popup(int index, const QPoint& pos, bool setFirstActionAsActive)
{
    assert(m_ctx);
    assert(m_model);

    QMenu *menu = newMenu();
    assert(menu);

    const auto modelIndex = m_model->index(index, 0);
    assert(modelIndex.isValid());

    const auto children = m_model->data(modelIndex, NavigationModel::CHILDREN).value<QList<NavigationModelItem>>();

    if (children.count() <= 0)
    {
        emit pageRequested(m_model->data(modelIndex, NavigationModel::URI).toStringList());
        return;
    }

    populateMenuForChildren(menu, children, setFirstActionAsActive);

    menu->popup(pos);
}

void NavigationBarContextMenu::popup(const QPoint &pos, bool setFirstActionAsActive)
{
    assert(m_ctx);
    assert(m_model);

    QMenu *menu = newMenu();
    assert(menu);

    bool activeActionSet = !setFirstActionAsActive;
    bool menuAdded = false;

    for (int i = 0; i < m_model->rowCount(); ++i)
    {
        const auto modelIndex = m_model->index(i, 0);
        assert(modelIndex.isValid());

        const auto menuTitle = m_model->data(modelIndex, NavigationModel::TITLE).toString();
        const auto menuUri = m_model->data(modelIndex, NavigationModel::URI).toStringList();
        const auto menuIcon = m_model->data(modelIndex, NavigationModel::ICON_SVG).toString();
        const auto menuExpandable = m_model->data(modelIndex, NavigationModel::EXPANDABLE).toBool();
        const auto menuChildren = m_model->data(modelIndex, NavigationModel::CHILDREN).value<QList<NavigationModelItem>>();
        const auto menuDepth = m_model->data(modelIndex, NavigationModel::DEPTH).toInt();

        // We currently do not care about deeper levels:
        if (menuDepth != 0)
            continue;

        if (menuExpandable && menuChildren.size() > 0)
        {
            const auto subMenu = menu->addMenu(menuTitle);

            if (menuIcon.length() > 0)
                subMenu->setIcon(ColorizedSvgIcon::colorizedIconForWidget(menuIcon, subMenu));

            populateMenuForChildren(subMenu, menuChildren, setFirstActionAsActive);

            menuAdded = true;
        }
        else
        {
            const auto action = menu->addAction(menuTitle, [this, menuUri]() {
                emit pageRequested(menuUri);
            });

            if (menuIcon.length() > 0)
                action->setIcon(ColorizedSvgIcon::colorizedIconForWidget(menuIcon, qobject_cast<QWidget*>(menu)));

            if (!activeActionSet && !menuAdded)
            {
                menu->setActiveAction(action);
                activeActionSet = true;
            }
        }
    }

    menu->popup(pos);
}

void NavigationBarContextMenu::populateMenuForChildren(QMenu *menu, const QList<NavigationModelItem> &children, bool setFirstActionAsActive)
{
    assert(m_ctx);
    assert(m_model);
    assert(menu);

    bool activeActionSet = !setFirstActionAsActive;

    for (const auto& child : children)
    {
        const auto childTitle = child.name();
        assert(childTitle.length() > 0);
        const auto childUri = child.uri();
        assert(childUri.length() > 0);
        const auto childIcon = child.icon_svg();

        const auto action = menu->addAction(childTitle, [this, uri = childUri]() {
            emit pageRequested(uri);
        });

        if (childIcon.length() > 0)
            action->setIcon(ColorizedSvgIcon::colorizedIconForWidget(childIcon, qobject_cast<QWidget*>(menu)));

        if (!activeActionSet)
        {
            menu->setActiveAction(action);
            activeActionSet = true;
        }
    }
}

Messung
CHZG
84999994

¤ Dauer der Verarbeitung: 0.8 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104857
#Domains=418018