Exemple #1
0
/*!
  \internal
  \fn void SelectedItem::keyPressEvent(QKeyEvent *event)
  Calls \l{function}{moveRequested(Direction)} in response to Qt::Key_Right, Qt::Key_Left,
  Qt::Key_Up or Qt::Key_Down. Calls triggerItemSelected() in response to Qt::Key_Select or
  Qt::Key_Return. For all other keys, the default functionality applies.
  If there is no current item, does nothing.
*/
void SelectedItem::keyPressEvent(QKeyEvent *event)
{
    if ( !currentItem ) {
        qWarning("SelectedItem::keyPressEvent(...): No current item.");
        QGraphicsRectItem::keyPressEvent(event);
        return;
    }

    switch( event->key() ) {
    case Qt::Key_Right:
        if ( Qtopia::mousePreferred() || event->isAutoRepeat() && destItem )
            return;
        moveRequested(Right);
        break;
    case Qt::Key_Left:
        if ( Qtopia::mousePreferred() || event->isAutoRepeat() && destItem )
            return;
        moveRequested(Left);
        break;
    case Qt::Key_Up:
        if ( Qtopia::mousePreferred() || event->isAutoRepeat() && destItem )
            return;
        moveRequested(Up);
        break;
    case Qt::Key_Down:
        if ( Qtopia::mousePreferred() || event->isAutoRepeat() && destItem )
            return;
        moveRequested(Down);
        break;
    case Qt::Key_Select: // Qtopia pad
    case Qt::Key_Return: // otherwise
        if ( event->isAutoRepeat())
            return;
        setActive(true);
        pressed = true;
        if ( destItem ) {
            // User has chosen to move to a new destination already, so they want to select
            // that one.
            triggerItemPressed(destItem);
        } else {
            triggerItemPressed(currentItem);
        }
        break;
    default:
        if ( event->isAutoRepeat())
            return;
        QGraphicsRectItem::keyPressEvent(event);
        return;
    }
}
void packetAdmin::createPacket()
{
    QThread* newThread = new QThread();
    packet *newPacket = new packet();

    newPacket->moveToThread(newThread);
    connect(newPacket, SIGNAL(moveRequested()), newThread, SLOT(start()));
    connect(newThread, SIGNAL(started()), newPacket, SLOT(move()));
    connect(newPacket, SIGNAL(finished()), newThread, SLOT(quit()), Qt::DirectConnection);              // (1)
    connect(newPacket, SIGNAL(deletePacket(packet*)), this, SLOT(deletePacketFromList(packet*)));
    connect(newPacket, SIGNAL(loosePacket()), this, SLOT(increaseLostPackets()));

    newPacket->requestMoving();
    _packets.append(newPacket);
    _threads.append(newThread);
}
// Set top-level layout to show cards.
// Entry conditions:
// - mCardWidgetsList contains CardWidgets from previous layout (any
//   widgets not reused should be cleaned up)
// Exit requirements:
// - mCardsList must be set to the list of cards
// - mCardWidgetsList must contain all CardWidgets in the layout
void
GridCardViewerWidget::setCards( const QList<CardDataSharedPtr>& cards )
{
    // No need to lay everything out again if nothing changed.
    if( mCardsList == cards ) return;

    mCardsList = cards;

    //
    // Performance gets bad if creating all new widgets from scratch,
    // especially when images are scaled.  Instead need to extract the
    // widgets from the layout, then only create new stuff as needed.
    //
    
    // Liberate the widgets we want to retain before clearing out the layout.
    for( auto w : mCardWidgetsList )
    {
        w->setParent( 0 );
    }
    for( int col = 0; col < 3; ++col )
    {
        mTopColButtons[col]->setParent( 0 );
        mBottomColButtons[col]->setParent( 0 );
    }
    for( int row = 0; row < 3; ++row )
    {
        mLeftRowButtons[row]->setParent( 0 );
        mRightRowButtons[row]->setParent( 0 );
    }

    // Our grid layout will be actually deleted below by clearLayout, but
    // need to null out our pointer.
    mGridCardsLayout = nullptr;

    // Remove any previously created widget from the alertable set.
    clearAlertableSubwidgets();

    // Clear out the top-level layout - we're rebuilding it here.
    qtutils::clearLayout( mLayout );

    // Function to clean up cardwidgets in the tracking list.
    auto cleanupCardWidgetsListFn = [this]() {
            for( auto w : mCardWidgetsList )
            {
                w->deleteLater();
            }
            mCardWidgetsList.clear();
        };

    // At this point everything is cleared.  Finish cleanup and exit if
    // there aren't exactly 9 cards in the list.
    if( mCardsList.size() != 9 )
    {
        // Zero is normal, but non-zero is not.
        if( mCardsList.size() > 0 )
        {
            mLogger->warn( "card list size ({}) != 9, cannot perform grid layout!", cards.size() );
        }

        // Clean up any cardwidgets remaining in the original list.
        cleanupCardWidgetsListFn();

        return;
    }

    // This will contain all widgets once they're created/reused.
    QList<CardWidget*> newCardWidgetsList;

    // This local function picks a matching already-created CardWidget from
    // our tracking list to speed up the overall "setCards" operation which happens
    // on every sort, categorize, etc.
    auto takeWidgetFromCardWidgetsList =
        [this]( const CardDataSharedPtr& cardDataSharedPtr ) -> CardWidget* {
            for( int i = 0; i < mCardWidgetsList.count(); ++i ) {
                CardWidget* w = mCardWidgetsList[i];
                if( w->getCardData() == cardDataSharedPtr ) {
                    mLogger->debug( "reusing CardWidget for name={} muid={}",
                            cardDataSharedPtr->getName(), cardDataSharedPtr->getMultiverseId() );
                    mCardWidgetsList.takeAt( i );
                    w->resetTraits();
                    updateCardWidgetSelectedAppearance( w );
                    return w;
                }
            }
            return nullptr;
        };

    // This local function creates and connects a CardWidget.
    auto createCardWidget =
        [this]( const CardDataSharedPtr& cardDataSharedPtr ) -> CardWidget* {
            mLogger->debug( "creating CardWidget name={} muid={}", cardDataSharedPtr->getName(), cardDataSharedPtr->getMultiverseId() );
            QString card = QString::fromStdString( cardDataSharedPtr->getName() );

            CardWidget* cardWidget = new CardWidget( cardDataSharedPtr,
                                                     mImageLoaderFactory,
                                                     QSize( 223, 310 ),
                                                     mLoggingConfig.createChildConfig( "cardwidget" ) );
            cardWidget->setZoomFactor( mZoomFactor );
            updateCardWidgetSelectedAppearance( cardWidget );
            cardWidget->loadImage();
            connect(cardWidget, SIGNAL(preselectRequested()),
                    this, SLOT(handleCardPreselectRequested()));
            connect(cardWidget, SIGNAL(selectRequested()),
                    this, SLOT(handleCardSelectRequested()));
            connect(cardWidget, SIGNAL(moveRequested()),
                    this, SLOT(handleCardMoveRequested()));
            cardWidget->setContextMenuPolicy( Qt::CustomContextMenu );
            connect(cardWidget, SIGNAL(customContextMenuRequested(const QPoint&)),
                    this, SLOT(handleCardContextMenu(const QPoint&)));
            return cardWidget;
        };

    //
    // Lay out the cards and buttons in a grid.
    //

    // This widget shouldn't be needed but Qt gets confused when the
    // layout is added directly.  Having a widget own it seems to help.
    QWidget* gridCardsLayoutWidget = new QWidget();

    // The widget needs to turn red when the alert is active.
    addAlertableSubwidget( gridCardsLayoutWidget );

    mGridCardsLayout = new QGridLayout( gridCardsLayoutWidget );

    // Center the gridlayout using a QHBoxLayout and add to parent layout
    // before adding widgets as mentioned in Qt docs.
    QHBoxLayout* alignmentLayout = new QHBoxLayout();
    alignmentLayout->addStretch();
    alignmentLayout->addWidget( gridCardsLayoutWidget );
    alignmentLayout->addStretch();
    mLayout->addLayout( alignmentLayout );

    // Lay out column buttons.
    for( int col = 0; col < 3; ++col )
    {
        mGridCardsLayout->addWidget( mTopColButtons[col], 0, 1 + col, Qt::AlignCenter );
        mGridCardsLayout->addWidget( mBottomColButtons[col], 4, 1 + col, Qt::AlignCenter );
    }

    // Lay out row buttons.
    for( int row = 0; row < 3; ++row )
    {
        mGridCardsLayout->addWidget( mLeftRowButtons[row],  1 + row, 0, Qt::AlignCenter );
        mGridCardsLayout->addWidget( mRightRowButtons[row], 1 + row, 4, Qt::AlignCenter );
    }

    updateButtonVisibility();

    // Create card widgets and add to layout.
    for( int i = 0; i < 9; ++i )
    {
        auto cardDataSharedPtr = mCardsList[i];

        // Look for an existing card widget that matches our card data,
        // and extract it from the list if found.
        CardWidget* cardWidget = nullptr;
        cardWidget = takeWidgetFromCardWidgetsList( cardDataSharedPtr );

        if( !cardWidget )
        {
            // The widget doesn't exist.  Create it.
            cardWidget = createCardWidget( cardDataSharedPtr );
        }
        mGridCardsLayout->addWidget( cardWidget, 1+ i/3, 1 + i%3 );
        newCardWidgetsList.push_back( cardWidget );
    }

    if( mFooterSpacing > 0 ) mLayout->addSpacing( mFooterSpacing );

    // This keeps everything pushed nicely to the top of the main area.
    mLayout->addStretch();

    // Clean up any cardwidgets remaining in the original list.
    cleanupCardWidgetsListFn();

    // Old is new.
    mCardWidgetsList = newCardWidgetsList;
}