Beispiel #1
0
QModelIndex FlatProxyModel::mapToSource(const QModelIndex &proxyIndex) const
{
    if (!proxyIndex.isValid())
        return QModelIndex();

    Q_ASSERT(proxyIndex.model() == this);
    Q_ASSERT(_rootSourceItem);

    int row = proxyIndex.row();
    QModelIndex sourceParent;
    SourceItem *sourceItem = _rootSourceItem->findChild(row);
    while (sourceItem) {
        if (sourceItem->pos() == row) {
            return sourceModel()->index(sourceItem->sourceRow(), proxyIndex.column(), sourceParent);
        }
        else {
            sourceParent = sourceModel()->index(sourceItem->sourceRow(), 0, sourceParent);
            sourceItem = sourceItem->findChild(row);
        }
    }

    qWarning() << "FlatProxyModel::mapToSource(): couldn't find source index for" << proxyIndex;
    Q_ASSERT(false);
    return QModelIndex(); // make compilers happy :)
}
Beispiel #2
0
void SourceView::updateSourceItems()
{
    setColumnWidth(1, 50);
    setColumnWidth(2, _costType2 ? 50:0);
    // Allow resizing of column 2
    setColumnWidthMode(2, QListView::Maximum);
    
    if (_costType)
      setColumnText(1, _costType->name());
    if (_costType2)
      setColumnText(2, _costType2->name());

    SourceItem* si;
    QListViewItem* item  = firstChild();
    for (;item;item = item->nextSibling()) {
	si = (SourceItem*)item;
	TraceLine* l = si->line();
	if (!l) continue;

	si->updateCost();

	QListViewItem *next, *i  = si->firstChild();
	for (;i;i = next) {
	    next = i->nextSibling();
	    ((SourceItem*)i)->updateCost();
	}
    }

    if (!_costType2) {
      setColumnWidthMode(2, QListView::Manual);
      setColumnWidth(2, 0);
    }
}
Beispiel #3
0
QModelIndex FlatProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
{
    if (!sourceIndex.isValid())
        return QModelIndex();

    SourceItem *sourceItem = sourceToInternal(sourceIndex);
    Q_ASSERT(sourceItem);
    return createIndex(sourceItem->pos(), sourceIndex.column(), sourceItem);
}
Beispiel #4
0
FlatProxyModel::SourceItem *FlatProxyModel::insertSubTreeHelper(SourceItem *parentItem, SourceItem *lastItem_, const QModelIndex &source_idx)
{
    SourceItem *lastItem = lastItem_;
    SourceItem *newItem = 0;
    for (int row = 0; row < sourceModel()->rowCount(source_idx); row++) {
        newItem = new SourceItem(row, parentItem);
        newItem->setPos(lastItem->pos() + 1);
        lastItem->setNext(newItem);
        lastItem = insertSubTreeHelper(newItem, newItem, sourceModel()->index(row, 0, source_idx));
    }
    return lastItem;
}
Beispiel #5
0
void SourceView::doUpdate(int changeType)
{
  // Special case ?
  if (changeType == selectedItemChanged) {

      if (!_selectedItem) {
	  clearSelection();
	  return;
      }

      TraceLine* sLine = 0;
      if (_selectedItem->type() == TraceItem::Line)
	  sLine = (TraceLine*) _selectedItem;
      if (_selectedItem->type() == TraceItem::Instr)
	  sLine = ((TraceInstr*)_selectedItem)->line();

      SourceItem* si = (SourceItem*)QListView::selectedItem();
      if (si) {
	  if (si->line() == sLine) return;
	  if (si->lineCall() &&
	      (si->lineCall()->call()->called() == _selectedItem)) return;
      }

      QListViewItem *item, *item2;
      for (item = firstChild();item;item = item->nextSibling()) {
	  si = (SourceItem*)item;
	  if (si->line() == sLine) {
	      ensureItemVisible(item);
              _inSelectionUpdate = true;
	      setCurrentItem(item);
              _inSelectionUpdate = false;
	      break;
	  }
	  item2 = item->firstChild();
	  for (;item2;item2 = item2->nextSibling()) {
	      si = (SourceItem*)item2;
	      if (!si->lineCall()) continue;
	      if (si->lineCall()->call()->called() == _selectedItem) {
		  ensureItemVisible(item2);
                  _inSelectionUpdate = true;
		  setCurrentItem(item2);
                  _inSelectionUpdate = false;
		  break;
	      }
	  }
	  if (item2) break;
      }
      return;
  }

  if (changeType == groupTypeChanged) {
    QListViewItem *item, *item2;
    for (item = firstChild();item;item = item->nextSibling())
      for (item2 = item->firstChild();item2;item2 = item2->nextSibling())
        ((SourceItem*)item2)->updateGroup();
  }

  refresh();
}
Beispiel #6
0
void SourceItemDelegate::paint(QPainter *painter,
			       const QStyleOptionViewItem &option,
			       const QModelIndex &index) const
{
    int column = index.column();
    SourceItem* item = static_cast<SourceItem*>(index.internalPointer());

    QColor color;
    if ( !item->inside() || ((column==1) || (column==2)))
      color = option.palette.color( QPalette::Button );
    else if ((item->lineCall() || item->lineJump()) && column>2)
      color = option.palette.color( QPalette::Midlight );
    if (color.isValid())
        _parent->model()->setData(index, color, Qt::BackgroundRole);

    if(column==3)
        paintArrows(painter, option, index);
    else
        QItemDelegate::paint(painter, option, index);
}
Beispiel #7
0
void
LovedTracksItem::activate()
{
    if ( !m_lovedTracksPage )
    {
        SourceItem* par = dynamic_cast< SourceItem* >( parent() );
        PlaylistViewPage* pv = new PlaylistViewPage( ViewManager::instance()->widget() );
        pv->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::LovedPlaylist, TomahawkUtils::Original, QSize( 128, 128 ) ) );

        TopLovedTracksModel* raModel = new TopLovedTracksModel( pv );
        raModel->setTitle( text() );

        TrackItemDelegate* del = new TrackItemDelegate( TrackItemDelegate::LovedTracks, pv->view()->trackView(), pv->view()->trackView()->proxyModel() );
        pv->view()->trackView()->setPlaylistItemDelegate( del );

        pv->view()->trackView()->setEmptyTip( tr( "Sorry, we could not find any of your Favorites!" ) );
        if ( !par )
        {
            raModel->setDescription( tr( "The most loved tracks from all your friends" ) );
            pv->view()->setGuid( QString( "lovedtracks" ) );
        }
        else
        {
            if ( par->source()->isLocal() )
                raModel->setDescription( tr( "All of your loved tracks" ) );
            else
                raModel->setDescription( tr( "All of %1's loved tracks" ).arg( par->source()->friendlyName() ) );

            pv->view()->setGuid( QString( "lovedtracks/%1" ).arg( par->source()->nodeId() ) );
        }

        pv->view()->trackView()->setPlayableModel( raModel );
        raModel->setSource( !par ? source_ptr() : par->source() );

        m_lovedTracksPage = pv;
    }

    ViewManager::instance()->show( m_lovedTracksPage );
    model()->linkSourceItemToPage( this, m_lovedTracksPage );
}
Beispiel #8
0
QSize
SourceDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
    SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
    SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );

    if ( type == SourcesModel::Source || type == SourcesModel::ScriptCollection )
    {
        SourceItem* colItem = qobject_cast< SourceItem* >( item );
        return QSize( option.rect.width(), ( colItem && colItem->source() && colItem->source()->isLocal() ) ? 0 : option.fontMetrics.height() * 3.2 );
    }
    else if ( type == SourcesModel::Divider )
    {
        return QSize( option.rect.width(), TomahawkUtils::DpiScaler::scaledY( m_parent, 6 ) );
    }
    else if ( type == SourcesModel::Group )
    {
        const int groupSpacer = index.row() > 0 ? option.fontMetrics.height() * 2.5 : option.fontMetrics.height() * 1.8;
        return QSize( option.rect.width(), option.fontMetrics.height() + groupSpacer );
    }
    else
        return QSize( option.rect.width(), option.fontMetrics.height() * 1.8 ); //QStyledItemDelegate::sizeHint( option, index ) );
}
Beispiel #9
0
QModelIndex FlatProxyModel::index(int row, int column, const QModelIndex &parent) const
{
    if (parent.isValid()) {
        qWarning() << "FlatProxyModel::index() called with valid parent:" << parent;
        return QModelIndex();
    }

    if (!_rootSourceItem) {
        qWarning() << "FlatProxyModel::index() while model has no root Item";
        return QModelIndex();
    }

    SourceItem *item = _rootSourceItem;
    while (item->pos() != row) {
        item = item->findChild(row);
        if (!item) {
            qWarning() << "FlatProxyModel::index() no such row:" << row;
            return QModelIndex();
        }
    }

    Q_ASSERT(item->pos() == row);
    return createIndex(row, column, item);
}
Beispiel #10
0
QItemSelection FlatProxyModel::mapSelectionToSource(const QItemSelection &proxySelection) const
{
    QItemSelection sourceSelection;

    for (int i = 0; i < proxySelection.count(); i++) {
        const QItemSelectionRange &range = proxySelection[i];

        SourceItem *topLeftItem = 0;
        SourceItem *bottomRightItem = 0;
        SourceItem *currentItem = static_cast<SourceItem *>(range.topLeft().internalPointer());
        int row = range.topLeft().row();
        int left = range.topLeft().column();
        int right = range.bottomRight().column();
        while (currentItem && row <= range.bottomRight().row()) {
            Q_ASSERT(currentItem->pos() == row);
            if (!topLeftItem)
                topLeftItem = currentItem;

            if (currentItem->parent() == topLeftItem->parent()) {
                bottomRightItem = currentItem;
            }
            else {
                Q_ASSERT(topLeftItem && bottomRightItem);
                sourceSelection << QItemSelectionRange(mapToSource(createIndex(topLeftItem->pos(), left, topLeftItem)), mapToSource(createIndex(bottomRightItem->pos(), right, bottomRightItem)));
                topLeftItem = 0;
                bottomRightItem = 0;
            }

            // update loop vars
            currentItem = currentItem->next();
            row++;
        }

        if (topLeftItem && bottomRightItem) { // there should be one range left.
            sourceSelection << QItemSelectionRange(mapToSource(createIndex(topLeftItem->pos(), left, topLeftItem)), mapToSource(createIndex(bottomRightItem->pos(), right, bottomRightItem)));
        }
    }

    return sourceSelection;
}
Beispiel #11
0
void
SourceTreeView::setupMenus()
{
    m_playlistMenu.clear();
    m_roPlaylistMenu.clear();
    m_latchMenu.clear();
    m_privacyMenu.clear();

    bool readonly = true;
    SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt();

    if ( type == SourcesModel::StaticPlaylist || type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station )
    {
        const PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex );
        const playlist_ptr playlist = item->playlist();

        if ( !playlist.isNull() )
        {
            readonly = !playlist->author()->isLocal();
        }
    }

    QAction* latchOnAction = ActionCollection::instance()->getAction( "latchOn" );
    m_latchMenu.addAction( latchOnAction );

    m_privacyMenu.addAction( ActionCollection::instance()->getAction( "togglePrivacy" ) );

    if ( type == SourcesModel::Collection )
    {
        SourceItem* item = itemFromIndex< SourceItem >( m_contextMenuIndex );
        source_ptr source = item->source();
        if ( !source.isNull() )
        {
            if ( m_latchManager->isLatched( source ) )
            {
                QAction *latchOffAction = ActionCollection::instance()->getAction( "latchOff" );
                m_latchMenu.addAction( latchOffAction );
                connect( latchOffAction, SIGNAL( triggered() ), SLOT( latchOff() ) );
                m_latchMenu.addSeparator();
                QAction *latchRealtimeAction = ActionCollection::instance()->getAction( "realtimeFollowingAlong" );
                latchRealtimeAction->setChecked( source->playlistInterface()->latchMode() == Tomahawk::PlaylistModes::RealTime );
                m_latchMenu.addAction( latchRealtimeAction );
                connect( latchRealtimeAction, SIGNAL( toggled( bool ) ), SLOT( latchModeToggled( bool ) ) );
            }
        }
    }

    QAction *loadPlaylistAction = ActionCollection::instance()->getAction( "loadPlaylist" );
    m_playlistMenu.addAction( loadPlaylistAction );
    QAction *renamePlaylistAction = ActionCollection::instance()->getAction( "renamePlaylist" );
    m_playlistMenu.addAction( renamePlaylistAction );
    m_playlistMenu.addSeparator();

    QAction *copyPlaylistAction = m_playlistMenu.addAction( tr( "&Copy Link" ) );
    QAction *deletePlaylistAction = m_playlistMenu.addAction( tr( "&Delete %1" ).arg( SourcesModel::rowTypeToString( type ) ) );

    QString addToText;
    if ( type == SourcesModel::StaticPlaylist )
        addToText = tr( "Add to my Playlists" );
    if ( type == SourcesModel::AutomaticPlaylist )
        addToText = tr( "Add to my Automatic Playlists" );
    else if ( type == SourcesModel::Station )
        addToText = tr( "Add to my Stations" );

    QAction *addToLocalAction = m_roPlaylistMenu.addAction( addToText );

    m_roPlaylistMenu.addAction( copyPlaylistAction );
    deletePlaylistAction->setEnabled( !readonly );
    renamePlaylistAction->setEnabled( !readonly );
    addToLocalAction->setEnabled( readonly );

    // Handle any custom actions registered for playlists
    if ( type == SourcesModel::StaticPlaylist && !readonly &&
        !ActionCollection::instance()->getAction( ActionCollection::LocalPlaylists ).isEmpty() )
    {
        m_playlistMenu.addSeparator();

        const PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex );
        const playlist_ptr playlist = item->playlist();
        foreach ( QAction* action, ActionCollection::instance()->getAction( ActionCollection::LocalPlaylists ) )
        {
            if ( QObject* notifier = ActionCollection::instance()->actionNotifier( action ) )
            {
                QMetaObject::invokeMethod( notifier, "aboutToShow", Qt::DirectConnection, Q_ARG( QAction*, action ), Q_ARG( Tomahawk::playlist_ptr, playlist ) );
            }

            action->setProperty( "payload", QVariant::fromValue< playlist_ptr >( playlist ) );
            m_playlistMenu.addAction( action );
        }
Beispiel #12
0
void
SourceTreeView::setupMenus()
{
    m_playlistMenu.clear();
    m_roPlaylistMenu.clear();
    m_latchMenu.clear();
    m_privacyMenu.clear();

    bool readonly = true;
    SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt();
    if ( type == SourcesModel::StaticPlaylist || type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station )
    {

        PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex );
        playlist_ptr playlist = item->playlist();
        if ( !playlist.isNull() )
        {
            readonly = !playlist->author()->isLocal();
        }
    }

    QAction* latchOnAction = ActionCollection::instance()->getAction( "latchOn" );
    m_latchMenu.addAction( latchOnAction );

    m_privacyMenu.addAction( ActionCollection::instance()->getAction( "togglePrivacy" ) );

    if ( type == SourcesModel::Collection )
    {
        SourceItem* item = itemFromIndex< SourceItem >( m_contextMenuIndex );
        source_ptr source = item->source();
        if ( !source.isNull() )
        {
            if ( m_latchManager->isLatched( source ) )
            {
                QAction *latchOffAction = ActionCollection::instance()->getAction( "latchOff" );
                m_latchMenu.addAction( latchOffAction );
                connect( latchOffAction, SIGNAL( triggered() ), SLOT( latchOff() ) );
                m_latchMenu.addSeparator();
                QAction *latchRealtimeAction = ActionCollection::instance()->getAction( "realtimeFollowingAlong" );
                latchRealtimeAction->setChecked( source->playlistInterface()->latchMode() == Tomahawk::PlaylistInterface::RealTime );
                m_latchMenu.addAction( latchRealtimeAction );
                connect( latchRealtimeAction, SIGNAL( toggled( bool ) ), SLOT( latchModeToggled( bool ) ) );
            }
        }
    }

    QAction *loadPlaylistAction = ActionCollection::instance()->getAction( "loadPlaylist" );
    m_playlistMenu.addAction( loadPlaylistAction );
    QAction *renamePlaylistAction = ActionCollection::instance()->getAction( "renamePlaylist" );
    m_playlistMenu.addAction( renamePlaylistAction );
    m_playlistMenu.addSeparator();

    QAction *copyPlaylistAction = m_playlistMenu.addAction( tr( "&Copy Link" ) );
    QAction *deletePlaylistAction = m_playlistMenu.addAction( tr( "&Delete %1" ).arg( SourcesModel::rowTypeToString( type ) ) );

    QString addToText = QString( "Add to my %1" );
    if ( type == SourcesModel::StaticPlaylist )
        addToText = addToText.arg( "Playlists" );
    if ( type == SourcesModel::AutomaticPlaylist )
        addToText = addToText.arg( "Automatic Playlists" );
    else if ( type == SourcesModel::Station )
        addToText = addToText.arg( "Stations" );

    QAction *addToLocalAction = m_roPlaylistMenu.addAction( tr( addToText.toUtf8(), "Adds the given playlist, dynamic playlist, or station to the users's own list" ) );

    m_roPlaylistMenu.addAction( copyPlaylistAction );
    deletePlaylistAction->setEnabled( !readonly );
    renamePlaylistAction->setEnabled( !readonly );
    addToLocalAction->setEnabled( readonly );

    if ( type == SourcesModel::StaticPlaylist )
        copyPlaylistAction->setText( tr( "&Export Playlist" ) );

    connect( loadPlaylistAction,   SIGNAL( triggered() ), SLOT( loadPlaylist() ) );
    connect( renamePlaylistAction, SIGNAL( triggered() ), SLOT( renamePlaylist() ) );
    connect( deletePlaylistAction, SIGNAL( triggered() ), SLOT( deletePlaylist() ) );
    connect( copyPlaylistAction,   SIGNAL( triggered() ), SLOT( copyPlaylistLink() ) );
    connect( addToLocalAction,     SIGNAL( triggered() ), SLOT( addToLocal() ) );
    connect( latchOnAction,        SIGNAL( triggered() ), SLOT( latchOnOrCatchUp() ), Qt::QueuedConnection );
}
Beispiel #13
0
void SourceItemDelegate::paintArrows(QPainter *p,
				     const QStyleOptionViewItem &option,
				     const QModelIndex &index) const
{
    QTreeWidget *lv = _parent;
    if ( !lv ) return;
    SourceView* sv = (SourceView*) lv;
    SourceItem* item = static_cast<SourceItem*>(index.internalPointer());
    const QRect& rect = option.rect;
    int height = rect.height();

    p->save();
    drawBackground(p, option, index);
    p->translate(rect.topLeft());

    int marg = 1;
    int yy = height/2, y1, y2;
    QColor c;

    int start = -1, end = -1;

    TraceLineJump* lineJump = item->lineJump();
    uint lineno = item->lineno();
    TraceLineCall* lineCall = item->lineCall();

    // draw line borders, detect start/stop of a line
    for(int i=0; i< item->jumpCount(); i++) {
        TraceLineJump* jump = item->jump(i);
        if (jump == 0) continue;

        y1 = 0;
        y2 = height;
        if (lineJump &&
            (lineJump->lineTo() == jump->lineTo()) &&
            (jump->lineFrom()->lineno() == lineno)) {

            if (start<0) start = i;
            if (lineJump == jump) {
                if (jump->lineTo()->lineno() <= lineno)
                    y2 = yy;
                else
                    y1 = yy;
            }
        }
        else if (!lineJump && !lineCall &&
                 (jump->lineTo()->lineno() == lineno)) {
            if (end<0) end = i;
            if (jump->lineFrom()->lineno() < lineno)
                y2 = yy;
            else
                y1 = yy;
        }

        c = jump->isCondJump() ? Qt::red : Qt::blue;
        p->fillRect( marg + 6*i, y1, 4, y2, c);
        p->setPen(c.light());
        p->drawLine( marg + 6*i, y1, marg + 6*i, y2);
        p->setPen(c.dark());
        p->drawLine( marg + 6*i +3, y1, marg + 6*i +3, y2);
    }

    // draw start/stop horizontal line
    int x, y = yy-2, w, h = 4;
    if (start >= 0) {
        c = item->jump(start)->isCondJump() ? Qt::red : Qt::blue;
        x = marg + 6*start;
        w = 6*(sv->arrowLevels() - start) + 10;
        p->fillRect( x, y, w, h, c);
        p->setPen(c.light());
        p->drawLine(x, y, x+w-1, y);
        p->drawLine(x, y, x, y+h-1);
        p->setPen(c.dark());
        p->drawLine(x+w-1, y, x+w-1, y+h-1);
        p->drawLine(x+1, y+h-1, x+w-1, y+h-1);
    }
    if (end >= 0) {
        c = item->jump(end)->isCondJump() ? Qt::red : Qt::blue;
        x = marg + 6*end;
        w = 6*(sv->arrowLevels() - end) + 10;

        QPolygon a;
        a.putPoints(0, 8, x,y+h,
                    x,y, x+w-8,y, x+w-8,y-2,
                    x+w,yy,
                    x+w-8,y+h+2, x+w-8,y+h,
                    x,y+h);
        p->setBrush(c);
        p->drawConvexPolygon(a);

        p->setPen(c.light());
        p->drawPolyline(a.constData(), 5);
        p->setPen(c.dark());
        p->drawPolyline(a.constData() + 4, 2);
        p->setPen(c.light());
        p->drawPolyline(a.constData() + 5, 2);
        p->setPen(c.dark());
        p->drawPolyline(a.constData() + 6, 2);
    }

    // draw inner vertical line for start/stop
    // this overwrites borders of horizontal line
    for(int i=0;i< item->jumpCount();i++) {
        TraceLineJump* jump = item->jump(i);
        if (jump == 0) continue;

        c = jump->isCondJump() ? Qt::red : Qt::blue;

        if (jump->lineFrom()->lineno() == lineno) {
            bool drawUp = true;
            if (jump->lineTo()->lineno() == lineno)
                if (start<0) drawUp = false;
            if (jump->lineTo()->lineno() > lineno) drawUp = false;
            if (drawUp)
                p->fillRect( marg + 6*i +1, 0, 2, yy, c);
            else
                p->fillRect( marg + 6*i +1, yy, 2, height-yy, c);
        }
        else if (jump->lineTo()->lineno() == lineno) {
            if (end<0) end = i;
            if (jump->lineFrom()->lineno() < lineno)
                p->fillRect( marg + 6*i +1, 0, 2, yy, c);
            else
                p->fillRect( marg + 6*i +1, yy, 2, height-yy, c);
        }
    }
    p->restore();
}
Beispiel #14
0
void
SourceDelegate::paintSource( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
    painter->save();
    painter->setPen( Qt::black );
    QFont font = painter->font();
    font.setPointSize( TomahawkUtils::defaultFontSize() );
    painter->setFont( font );

    SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
    SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );

    const int iconRectVertMargin = m_margin / 4;
    const QRect iconRect = option.rect.adjusted( m_margin / 2 + m_margin / 4, iconRectVertMargin, -option.rect.width() + option.rect.height() + m_margin / 4, -iconRectVertMargin );
    QString name = index.data().toString();
    QPixmap avatar;
    int figWidth = 0;
    bool isPlaying = false;
    QString desc;
    QString tracks;

    bool shouldDrawDropHint = false;

    if ( type == SourcesModel::Source )
    {
        // If the user is about to drop a track on a peer
        QRect itemsRect = option.rect;
        QPoint cursorPos = m_parent->mapFromGlobal( QCursor::pos() );
        bool cursorInRect = itemsRect.contains( cursorPos );
        if ( cursorInRect && m_dropHoverIndex.isValid() && m_dropHoverIndex == index )
            shouldDrawDropHint = true;

        SourceItem* colItem = qobject_cast< SourceItem* >( item );
        Q_ASSERT( colItem );
        bool status = !( !colItem->source() || !colItem->source()->isOnline() );

        if ( colItem->source() && !colItem->source()->isLocal() )
        {
            if ( status )
            {
                tracks = QString::number( colItem->source()->trackCount() );
                if ( shouldDrawDropHint )
                    figWidth = iconRect.width();
                name = colItem->source()->friendlyName();
            }

            avatar = colItem->pixmap( iconRect.size() );
            isPlaying = !colItem->source()->currentTrack().isNull();
            desc = colItem->source()->textStatus();
            if ( colItem->source().isNull() )
                desc = tr( "All available tracks" );
        }
    }
    else if ( type == SourcesModel::ScriptCollection )
    {
        ScriptCollectionItem* scItem = qobject_cast< ScriptCollectionItem* >( item );
        Q_ASSERT( scItem );

        if ( !scItem->collection().isNull() )
        {
            int trackCount = scItem->collection()->trackCount();
            if ( trackCount >= 0 )
            {
                tracks = QString::number( trackCount );
                figWidth = painter->fontMetrics().width( tracks );
            }
            name = scItem->collection()->itemName();
        }

        avatar = scItem->icon().pixmap( iconRect.size() );
        desc = qobject_cast< Tomahawk::ScriptCollection* >( scItem->collection().data() )->description();
    }

    painter->setOpacity( 1.0 );
    painter->drawPixmap( iconRect, avatar );

    QRect textRect = option.rect.adjusted( iconRect.width() + m_margin, m_margin / 6 + m_margin / 32, -figWidth - ( figWidth ? m_margin : 0 ), 0 );
    QString text = painter->fontMetrics().elidedText( name, Qt::ElideRight, textRect.width() );
    {
        QTextOption to;
        to.setWrapMode( QTextOption::NoWrap );
        painter->setOpacity( 0.7 );
        painter->drawText( textRect, text, to );
    }

    textRect = option.rect.adjusted( iconRect.width() + m_margin, option.rect.height() / 2, -figWidth - ( figWidth ? m_margin : 0 ), -m_margin / 4 );

    if ( type == SourcesModel::Source )
    {
        SourceItem* colItem = qobject_cast< SourceItem* >( item );
        Q_ASSERT( colItem );

        bool privacyOn = TomahawkSettings::instance()->privateListeningMode() == TomahawkSettings::FullyPrivate;
        if ( !colItem->source().isNull() && colItem->source()->isLocal() && privacyOn )
        {
            QRect pmRect = textRect;
            pmRect.setRight( pmRect.left() + pmRect.height() );
            ActionCollection::instance()->getAction( "togglePrivacy" )->icon().paint( painter, pmRect );
            textRect.adjust( pmRect.width() + m_margin / 8, 0, 0, 0 );
        }
        if ( ( isPlaying || ( !colItem->source().isNull() && colItem->source()->isLocal() ) ) && !shouldDrawDropHint )
        {
            // Show a listen icon
            TomahawkUtils::ImageType listenAlongPixmap = TomahawkUtils::Invalid;
            TomahawkUtils::ImageType realtimeListeningAlongPixmap = TomahawkUtils::Invalid;
            if ( index.data( SourcesModel::LatchedOnRole ).toBool() )
            {
                // Currently listening along
                listenAlongPixmap = TomahawkUtils::HeadphonesOn;
                if ( !colItem->source()->isLocal() )
                {
                    realtimeListeningAlongPixmap =
                        colItem->source()->playlistInterface()->latchMode() == Tomahawk::PlaylistModes::RealTime ?
                            TomahawkUtils::PadlockClosed : TomahawkUtils::PadlockOpen;
                }
            }
            else if ( !colItem->source()->isLocal() )
            {
                listenAlongPixmap = TomahawkUtils::HeadphonesOff;
            }

            if ( listenAlongPixmap != TomahawkUtils::Invalid )
            {
                QRect pmRect = textRect;
                pmRect.setRight( pmRect.left() + pmRect.height() );
                painter->drawPixmap( pmRect, TomahawkUtils::defaultPixmap( listenAlongPixmap, TomahawkUtils::Original, pmRect.size() ) );
                textRect.adjust( pmRect.width() + m_margin / 8, 0, 0, 0 );

                m_headphoneRects[ index ] = pmRect;
            }
            else
                m_headphoneRects.remove( index );

            if ( realtimeListeningAlongPixmap != TomahawkUtils::Invalid )
            {
                QRect pmRect = textRect;
                pmRect.setRight( pmRect.left() + pmRect.height() );
                painter->drawPixmap( pmRect, TomahawkUtils::defaultPixmap( realtimeListeningAlongPixmap, TomahawkUtils::Original, pmRect.size() ) );
                textRect.adjust( pmRect.width() + m_margin / 8, 0, 0, 0 );

                m_lockRects[ index ] = pmRect;
            }
            else
                m_lockRects.remove( index );
        }
    }

    painter->save();
    if ( m_trackHovered == index )
    {
        QFont font = painter->font();
        font.setUnderline( true );
        painter->setFont( font );
    }
    textRect.adjust( 0, 0, 0, m_margin / 16 );

    if ( shouldDrawDropHint )
    {
        desc = tr( "Drop to send tracks" );
    }

    text = painter->fontMetrics().elidedText( desc, Qt::ElideRight, textRect.width() - m_margin / 4 );
    {
        QTextOption to( Qt::AlignVCenter );
        to.setWrapMode( QTextOption::NoWrap );

        painter->setOpacity( 0.4 );
        painter->drawText( textRect, text, to );
    }
    painter->restore();

    bool shouldPaintTrackCount = false;
    if ( type == SourcesModel::Source )
    {
        SourceItem* colItem = qobject_cast< SourceItem* >( item );
        Q_ASSERT( colItem );

        if ( colItem->source() && colItem->source()->currentTrack() && colItem->source()->state() == Tomahawk::SYNCED )
            m_trackRects[ index ] = textRect.adjusted( 0, 0, -textRect.width() + painter->fontMetrics().width( text ), 0 );
        else
            m_trackRects.remove( index );
    }
    else if ( type == SourcesModel::ScriptCollection )
    {
        if ( !tracks.isEmpty() )
            shouldPaintTrackCount = true;
    }

    if ( shouldPaintTrackCount || shouldDrawDropHint )
    {
        if ( shouldDrawDropHint )
        {
            const QRect figRect = option.rect.adjusted( option.rect.width() - figWidth - iconRectVertMargin, iconRectVertMargin, -iconRectVertMargin, -iconRectVertMargin );
            painter->drawPixmap( figRect, TomahawkUtils::defaultPixmap( TomahawkUtils::Inbox, TomahawkUtils::Original, figRect.size() ) );
        }
        else
        {
            const QRect figRect = option.rect.adjusted( option.rect.width() - figWidth - m_margin / 2, 0, -m_margin / 2, 0 );
            painter->drawText( figRect, tracks, QTextOption( Qt::AlignVCenter | Qt::AlignRight ) );
        }
    }

    painter->restore();
}
Beispiel #15
0
QItemSelection FlatProxyModel::mapSelectionFromSource(const QItemSelection &sourceSelection) const
{
    QList<_RangeRect> newRanges;
    QHash<QModelIndex, SourceItem *> itemLookup;
    // basics steps of the loop:
    // 1. convert each source ItemSelectionRange to a mapped Range (internal one for easier post processing)
    // 2. insert it into the list of previously mapped Ranges sorted by top location
    for (int i = 0; i < sourceSelection.count(); i++) {
        const QItemSelectionRange &currentRange = sourceSelection[i];
        QModelIndex currentParent = currentRange.topLeft().parent();
        Q_ASSERT(currentParent == currentRange.bottomRight().parent());

        SourceItem *parentItem = 0;
        if (!itemLookup.contains(currentParent)) {
            parentItem = sourceToInternal(currentParent);
            itemLookup[currentParent] = parentItem;
        }
        else {
            parentItem = itemLookup[currentParent];
        }

        _RangeRect newRange = { currentRange.topLeft().column(), currentRange.bottomRight().column(),
                                currentRange.topLeft().row(), currentRange.bottomRight().row(),
                                parentItem->child(currentRange.topLeft().row()), parentItem->child(currentRange.bottomRight().row()) };

        if (newRanges.isEmpty()) {
            newRanges << newRange;
            continue;
        }

        _RangeRect &first = newRanges[0];
        if (newRange < first) {
            newRanges.prepend(newRange);
            continue;
        }

        bool inserted = false;
        for (int j = 0; j < newRanges.count() - 1; j++) {
            _RangeRect &a = newRanges[j];
            _RangeRect &b = newRanges[j + 1];

            if (a < newRange && newRange < b) {
                newRanges[j + 1] = newRange;
                inserted = true;
                break;
            }
        }
        if (inserted)
            continue;

        _RangeRect &last = newRanges[newRanges.count() - 1];
        if (last < newRange) {
            newRanges.append(newRange);
            continue;
        }

        Q_ASSERT(false);
    }

    // we've got a sorted list of ranges now. so we can easily check if there is a possibility to merge
    for (int i = newRanges.count() - 1; i > 0; i--) {
        _RangeRect &a = newRanges[i - 1];
        _RangeRect &b = newRanges[i];
        if (a.left != b.left || a.right != b.right)
            continue;

        if (a.bottom < b.top - 1) {
            continue;
        }

        // all merge checks passed!
        if (b.bottom > a.bottom) {
            a.bottom = b.bottom;
            a.bottomItem = b.bottomItem;
        } // otherwise b is totally enclosed in a -> nothing to do but drop b.
        newRanges.removeAt(i);
    }

    QItemSelection proxySelection;
    for (int i = 0; i < newRanges.count(); i++) {
        _RangeRect &r = newRanges[i];
        proxySelection << QItemSelectionRange(createIndex(r.top, r.left, r.topItem), createIndex(r.bottom, r.right, r.bottomItem));
    }
    return proxySelection;
}
Beispiel #16
0
bool
SourceDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
{
    QMouseEvent* mEvent = 0;
    switch ( event->type() )
    {
//        case QEvent::MouseTrackingChange:
        case QEvent::MouseButtonDblClick:
        case QEvent::MouseButtonPress:
        case QEvent::MouseButtonRelease:
        case QEvent::MouseMove:
            mEvent = static_cast< QMouseEvent* >( event );
        default:
            break;
    }

    bool hoveringTrack = false;
    if ( m_trackRects.contains( index ) && mEvent )
    {
        const QRect trackRect = m_trackRects[ index ];
        hoveringTrack = trackRect.contains( mEvent->pos() );

        if ( hoveringTrack )
        {
            if ( m_trackHovered != index )
            {
                m_trackHovered = index;
                QMetaObject::invokeMethod( m_parent, "update", Qt::QueuedConnection, Q_ARG( QModelIndex, index ) );
            }
        }
    }
    if ( !hoveringTrack )
    {
        if ( m_trackHovered.isValid() )
            QMetaObject::invokeMethod( m_parent, "update", Qt::QueuedConnection, Q_ARG( QModelIndex, m_trackHovered ) );

        m_trackHovered = QPersistentModelIndex();
    }

    bool lockRectContainsClick = false, headphonesRectContainsClick = false;
    if ( m_headphoneRects.contains( index ) && mEvent )
    {
        const QRect headphoneRect = m_headphoneRects[ index ];
        headphonesRectContainsClick = headphoneRect.contains( mEvent->pos() );
    }
    if ( m_lockRects.contains( index ) && mEvent )
    {
        const QRect lockRect = m_lockRects[ index ];
        lockRectContainsClick = lockRect.contains( mEvent->pos() );
    }

    if ( event->type() == QEvent::MouseMove )
    {
        if ( hoveringTrack || lockRectContainsClick || headphonesRectContainsClick )
            m_parent->setCursor( Qt::PointingHandCursor );
        else
            m_parent->setCursor( Qt::ArrowCursor );
    }

    if ( event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonPress )
    {
        SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );
        if ( type == SourcesModel::TemporaryPage || type == SourcesModel::DeletablePage || type == SourcesModel::RemovablePage )
        {
            SourceTreeItem* gpi = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
            Q_ASSERT( gpi );

            QStyleOptionViewItemV4 o = option;
            initStyleOption( &o, index );
            const int padding = m_margin / 8;
            const QRect r( o.rect.right() - padding - m_iconHeight, padding + o.rect.y(), m_iconHeight, m_iconHeight );

            if ( r.contains( mEvent->pos() ) )
            {
                if ( event->type() == QEvent::MouseButtonRelease && mEvent->button() == Qt::LeftButton )
                {
                    gpi->removeFromList();

                    // Send a new mouse event to the view, since if the mouse is now over another item's delete area we want it to show up
                    QMouseEvent* ev = new QMouseEvent( QEvent::MouseMove, m_parent->viewport()->mapFromGlobal( QCursor::pos() ), Qt::NoButton, Qt::NoButton, Qt::NoModifier );
                    QApplication::postEvent( m_parent->viewport(), ev );
                }

                return true;
            }
        }
        else if ( type == SourcesModel::Source )
        {
            SourceItem* colItem = qobject_cast< SourceItem* >( index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >() );
            Q_ASSERT( colItem );

            if ( hoveringTrack && colItem->source() && colItem->source()->currentTrack() )
            {
                if ( event->type() == QEvent::MouseButtonRelease && mEvent->button() == Qt::LeftButton )
                {
                    ViewManager::instance()->show( colItem->source()->currentTrack() );
                    return true;
                }
                else if ( event->type() == QEvent::MouseButtonPress && mEvent->button() == Qt::RightButton )
                {
                    Tomahawk::ContextMenu* contextMenu = new Tomahawk::ContextMenu( m_parent );
                    contextMenu->setQuery( colItem->source()->currentTrack() );
                    contextMenu->exec( QCursor::pos() );
                    return true;
                }
            }

            if ( !colItem->source().isNull() && !colItem->source()->currentTrack().isNull() && !colItem->source()->isLocal() )
            {
                if ( headphonesRectContainsClick || lockRectContainsClick )
                {
                    if ( event->type() == QEvent::MouseButtonRelease && mEvent->button() == Qt::LeftButton )
                    {
                        if ( headphonesRectContainsClick )
                        {
                            if ( index.data( SourcesModel::LatchedOnRole ).toBool() )
                                // unlatch
                                emit latchOff( colItem->source() );
                            else
                                emit latchOn( colItem->source() );
                        }
                        else // it's in the lock rect
                            emit toggleRealtimeLatch( colItem->source(), !index.data( SourcesModel::LatchedRealtimeRole ).toBool() );
                    }
                    return true;
                }
            }
        }
        else if ( event->type() == QEvent::MouseButtonRelease && mEvent->button() == Qt::LeftButton && type == SourcesModel::StaticPlaylist )
        {
            PlaylistItem* plItem = qobject_cast< PlaylistItem* >( index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >() );
            Q_ASSERT( plItem );

            if ( plItem->canSubscribe() && !plItem->subscribedIcon().isNull() )
            {
                const int padding = m_margin / 16;
                const int imgWidth = option.rect.height() - 2 * padding;
                const QRect subRect( option.rect.right() - padding - imgWidth, option.rect.top() + padding, imgWidth, imgWidth );

                if ( subRect.contains( mEvent->pos() ) )
                {
                    // Toggle playlist subscription
                    plItem->setSubscribed( !plItem->subscribed() );
                }
            }
        }
    }

    // We emit our own clicked() signal instead of relying on QTreeView's, because that is fired whether or not a delegate accepts
    // a mouse press event. Since we want to swallow click events when they are on headphones other action items, here we make sure we only
    // emit if we really want to
    if ( event->type() == QEvent::MouseButtonRelease && mEvent->button() == Qt::LeftButton )
    {
        if ( m_lastClicked == -1 )
        {
            m_lastClicked = QDateTime::currentMSecsSinceEpoch();
            emit clicked( index );
        }
        else
        {
            qint64 elapsed = QDateTime::currentMSecsSinceEpoch() - m_lastClicked;
            if ( elapsed < QApplication::doubleClickInterval() )
            {
                m_lastClicked = -1;
                emit doubleClicked( index );
            } else
            {
                m_lastClicked = QDateTime::currentMSecsSinceEpoch();
                emit clicked( index );
            }
        }
    }

    return QStyledItemDelegate::editorEvent( event, model, option, index );
}
Beispiel #17
0
void FlatProxyModel::removeSubTree(const QModelIndex &source_idx, bool emitRemove)
{
    SourceItem *sourceItem = sourceToInternal(source_idx);
    if (!sourceItem)
        return;

    SourceItem *prevItem = sourceItem->parent();
    if (sourceItem->sourceRow() > 0) {
        prevItem = prevItem->child(sourceItem->sourceRow() - 1);
        while (prevItem->childCount() > 0) {
            prevItem = prevItem->child(prevItem->childCount() - 1);
        }
    }

    SourceItem *lastItem = sourceItem;
    while (lastItem->childCount() > 0) {
        lastItem = lastItem->child(lastItem->childCount() - 1);
    }

    if (emitRemove)
        beginRemoveRows(QModelIndex(), sourceItem->pos(), lastItem->pos());

    int nextPos = 0;
    if (prevItem) {
        prevItem->setNext(lastItem->next());
        nextPos = prevItem->pos() + 1;
    }

    SourceItem *nextItem = lastItem->next();
    while (nextItem) {
        nextItem->setPos(nextPos);
        nextPos++;
        nextItem = nextItem->next();
    }

    sourceItem->parent()->removeChild(sourceItem);
    delete sourceItem;

    if (emitRemove)
        endRemoveRows();
}
Beispiel #18
0
void FlatProxyModel::insertSubTree(const QModelIndex &source_idx, bool emitInsert)
{
    SourceItem *newSubTree = new SourceItem(source_idx.row(), sourceToInternal(sourceModel()->parent(source_idx)));

    if (newSubTree->parent()) {
        newSubTree->setPos(newSubTree->parent()->pos() + source_idx.row() + 1);
    }
    SourceItem *lastItem = insertSubTreeHelper(newSubTree, newSubTree, source_idx);

    Q_ASSERT(lastItem);
    Q_ASSERT(lastItem->next() == 0);

    if (emitInsert)
        beginInsertRows(QModelIndex(), newSubTree->pos(), lastItem->pos());

    if (newSubTree->parent()) {
        if (newSubTree->parent()->childCount() > source_idx.row()) {
            SourceItem *next = newSubTree->parent()->child(source_idx.row());
            lastItem->setNext(next);
            int nextPos = lastItem->pos() + 1;
            while (next) {
                next->setPos(nextPos);
                next = next->next();
                nextPos++;
            }
        }
        if (source_idx.row() > 0) {
            SourceItem *previous = newSubTree->parent()->child(source_idx.row() - 1);
            while (previous->childCount() > 0) {
                previous = previous->child(previous->childCount() - 1);
            }
            previous->setNext(newSubTree);
        }
        else {
            newSubTree->parent()->setNext(newSubTree);
        }
    }
    else {
        _rootSourceItem = newSubTree;
    }

    if (emitInsert)
        endInsertRows();
}