2017-07-21 18:21:34 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskListView.h"
|
|
|
|
#include "QskAspect.h"
|
2018-08-03 08:15:28 +02:00
|
|
|
#include "QskColorFilter.h"
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
QSK_SUBCONTROL( QskListView, Cell )
|
|
|
|
QSK_SUBCONTROL( QskListView, Text )
|
|
|
|
QSK_SUBCONTROL( QskListView, CellSelected )
|
|
|
|
QSK_SUBCONTROL( QskListView, TextSelected )
|
|
|
|
|
|
|
|
class QskListView::PrivateData
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
public:
|
|
|
|
PrivateData()
|
|
|
|
: preferredWidthFromColumns( false )
|
|
|
|
, alternatingRowColors( false )
|
|
|
|
, selectionMode( QskListView::SingleSelection )
|
|
|
|
, selectedRow( -1 )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QskTextOptions textOptions;
|
|
|
|
bool preferredWidthFromColumns : 1;
|
|
|
|
bool alternatingRowColors : 1;
|
|
|
|
SelectionMode selectionMode : 4;
|
|
|
|
|
|
|
|
int selectedRow;
|
|
|
|
};
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
QskListView::QskListView( QQuickItem* parent )
|
|
|
|
: QskScrollView( parent )
|
|
|
|
, m_data( new PrivateData() )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QskListView::~QskListView()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskListView::setPreferredWidthFromColumns( bool on )
|
|
|
|
{
|
|
|
|
if ( on != m_data->preferredWidthFromColumns )
|
|
|
|
{
|
|
|
|
m_data->preferredWidthFromColumns = on;
|
|
|
|
resetImplicitSize();
|
|
|
|
|
2017-10-30 08:33:43 +01:00
|
|
|
Q_EMIT preferredWidthFromColumnsChanged();
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskListView::preferredWidthFromColumns() const
|
|
|
|
{
|
|
|
|
return m_data->preferredWidthFromColumns;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskListView::setAlternatingRowColors( bool on )
|
|
|
|
{
|
|
|
|
if ( on != m_data->alternatingRowColors )
|
|
|
|
{
|
|
|
|
m_data->alternatingRowColors = on;
|
|
|
|
update();
|
|
|
|
|
|
|
|
Q_EMIT alternatingRowColorsChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskListView::alternatingRowColors() const
|
|
|
|
{
|
|
|
|
return m_data->alternatingRowColors;
|
|
|
|
}
|
|
|
|
|
2017-10-20 13:31:55 +02:00
|
|
|
void QskListView::setTextOptions( const QskTextOptions& textOptions )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
if ( textOptions != m_data->textOptions )
|
|
|
|
{
|
|
|
|
m_data->textOptions = textOptions;
|
|
|
|
updateScrollableSize();
|
|
|
|
|
|
|
|
Q_EMIT textOptionsChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QskTextOptions QskListView::textOptions() const
|
|
|
|
{
|
|
|
|
return m_data->textOptions;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskListView::setSelectedRow( int row )
|
|
|
|
{
|
|
|
|
if ( row < 0 )
|
|
|
|
row = -1;
|
|
|
|
|
|
|
|
if ( row >= rowCount() )
|
|
|
|
{
|
|
|
|
if ( !isComponentComplete() )
|
|
|
|
{
|
|
|
|
// when being called from Qml we delay the checks until
|
|
|
|
// componentComplete
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( row >= rowCount() )
|
|
|
|
row = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( row != m_data->selectedRow )
|
|
|
|
{
|
|
|
|
m_data->selectedRow = row;
|
|
|
|
Q_EMIT selectedRowChanged( row );
|
|
|
|
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int QskListView::selectedRow() const
|
|
|
|
{
|
|
|
|
return m_data->selectedRow;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskListView::setSelectionMode( SelectionMode mode )
|
|
|
|
{
|
|
|
|
if ( mode != m_data->selectionMode )
|
|
|
|
{
|
|
|
|
m_data->selectionMode = mode;
|
|
|
|
|
|
|
|
if ( m_data->selectionMode == NoSelection )
|
|
|
|
setSelectedRow( -1 );
|
|
|
|
|
|
|
|
Q_EMIT selectionModeChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QskListView::SelectionMode QskListView::selectionMode() const
|
|
|
|
{
|
|
|
|
return m_data->selectionMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
QskColorFilter QskListView::graphicFilterAt( int row, int col ) const
|
|
|
|
{
|
|
|
|
Q_UNUSED( row );
|
|
|
|
Q_UNUSED( col );
|
|
|
|
return QskColorFilter();
|
|
|
|
}
|
|
|
|
|
|
|
|
QskAspect::Subcontrol QskListView::textSubControlAt( int row, int col ) const
|
|
|
|
{
|
|
|
|
Q_UNUSED( col );
|
|
|
|
return ( row == selectedRow() ) ? TextSelected : Text;
|
|
|
|
}
|
|
|
|
|
2019-09-10 17:01:47 +02:00
|
|
|
QSizeF QskListView::contentsSizeHint(
|
|
|
|
Qt::SizeHint which, const QSizeF& ) const
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
qreal w = -1.0; // shouldn't we return something ???
|
2019-09-10 17:01:47 +02:00
|
|
|
|
|
|
|
if ( which != Qt::MaximumSize )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2019-09-10 17:01:47 +02:00
|
|
|
if ( m_data->preferredWidthFromColumns )
|
|
|
|
{
|
|
|
|
w = scrollableSize().width();
|
|
|
|
w += metric( QskScrollView::VerticalScrollBar );
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return QSizeF( w, -1.0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskListView::keyPressEvent( QKeyEvent* event )
|
|
|
|
{
|
|
|
|
if ( m_data->selectionMode == NoSelection )
|
2017-11-21 09:05:09 +01:00
|
|
|
{
|
|
|
|
Inherited::keyPressEvent( event );
|
2017-07-21 18:21:34 +02:00
|
|
|
return;
|
2017-11-21 09:05:09 +01:00
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
int row = selectedRow();
|
2017-10-18 20:00:06 +02:00
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
switch ( event->key() )
|
|
|
|
{
|
|
|
|
case Qt::Key_Down:
|
|
|
|
{
|
|
|
|
if ( row < rowCount() - 1 )
|
|
|
|
row++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Qt::Key_Up:
|
|
|
|
{
|
|
|
|
if ( row == -1 )
|
|
|
|
row = rowCount() - 1;
|
|
|
|
|
|
|
|
if ( row != 0 )
|
|
|
|
row--;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Qt::Key_Home:
|
|
|
|
{
|
|
|
|
row = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Qt::Key_End:
|
|
|
|
{
|
|
|
|
row = rowCount() - 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Qt::Key_PageUp:
|
|
|
|
case Qt::Key_PageDown:
|
|
|
|
{
|
|
|
|
// TODO ...
|
2017-11-21 09:05:09 +01:00
|
|
|
return Inherited::keyPressEvent( event );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
2017-11-21 09:05:09 +01:00
|
|
|
return Inherited::keyPressEvent( event );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const int r = selectedRow();
|
|
|
|
|
|
|
|
setSelectedRow( row );
|
|
|
|
|
|
|
|
row = selectedRow();
|
|
|
|
|
|
|
|
if ( row != r )
|
|
|
|
{
|
2018-01-16 12:13:38 +01:00
|
|
|
auto pos = scrollPos();
|
|
|
|
|
2017-12-07 17:12:52 +01:00
|
|
|
const qreal rowPos = row * rowHeight();
|
2017-07-21 18:21:34 +02:00
|
|
|
if ( rowPos < scrollPos().y() )
|
|
|
|
{
|
2018-01-16 12:13:38 +01:00
|
|
|
pos.setY( rowPos );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const QRectF vr = viewContentsRect();
|
|
|
|
|
|
|
|
const double scrolledBottom = scrollPos().y() + vr.height();
|
|
|
|
if ( rowPos + rowHeight() > scrolledBottom )
|
|
|
|
{
|
|
|
|
const double y = rowPos + rowHeight() - vr.height();
|
2018-01-16 12:13:38 +01:00
|
|
|
pos.setY( y );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
2018-01-16 12:13:38 +01:00
|
|
|
|
|
|
|
if ( pos != scrollPos() )
|
|
|
|
{
|
|
|
|
if ( event->isAutoRepeat() )
|
|
|
|
setScrollPos( pos );
|
|
|
|
else
|
|
|
|
scrollTo( pos );
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskListView::keyReleaseEvent( QKeyEvent* event )
|
|
|
|
{
|
|
|
|
Inherited::keyReleaseEvent( event );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskListView::mousePressEvent( QMouseEvent* event )
|
|
|
|
{
|
|
|
|
if ( m_data->selectionMode != NoSelection )
|
|
|
|
{
|
|
|
|
const QRectF vr = viewContentsRect();
|
|
|
|
if ( vr.contains( event->pos() ) )
|
|
|
|
{
|
|
|
|
const int row = ( event->pos().y() - vr.top() + scrollPos().y() ) / rowHeight();
|
|
|
|
if ( row >= 0 && row < rowCount() )
|
|
|
|
setSelectedRow( row );
|
2017-10-25 17:10:50 +02:00
|
|
|
|
|
|
|
return;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
2017-10-25 17:10:50 +02:00
|
|
|
|
|
|
|
Inherited::mousePressEvent( event );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskListView::mouseReleaseEvent( QMouseEvent* event )
|
|
|
|
{
|
|
|
|
Inherited::mouseReleaseEvent( event );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskListView::updateScrollableSize()
|
|
|
|
{
|
|
|
|
const double h = rowCount() * rowHeight();
|
|
|
|
|
2017-12-07 17:12:52 +01:00
|
|
|
qreal w = 0.0;
|
2017-07-21 18:21:34 +02:00
|
|
|
for ( int col = 0; col < columnCount(); col++ )
|
|
|
|
w += columnWidth( col );
|
|
|
|
|
|
|
|
const QSizeF sz = scrollableSize();
|
|
|
|
|
2017-12-07 17:12:52 +01:00
|
|
|
setScrollableSize( QSizeF( w, h ) );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
if ( m_data->preferredWidthFromColumns &&
|
|
|
|
sz.width() != scrollableSize().width() )
|
|
|
|
{
|
|
|
|
resetImplicitSize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskListView::componentComplete()
|
|
|
|
{
|
|
|
|
Inherited::componentComplete();
|
|
|
|
|
|
|
|
if ( m_data->selectedRow >= 0 )
|
|
|
|
{
|
|
|
|
// during Qml instantiation we might have set an invalid
|
|
|
|
// row selection
|
|
|
|
|
|
|
|
if ( m_data->selectedRow >= rowCount() )
|
|
|
|
setSelectedRow( -1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "moc_QskListView.cpp"
|