kdelibs/kross/ui/model.cpp

542 lines
20 KiB
C++
Raw Normal View History

2014-11-13 01:04:59 +02:00
/***************************************************************************
* model.cpp
* This file is part of the KDE project
* copyright (C) 2006-2007 by Sebastian Sauer (mail@dipe.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
* You should have received a copy of the GNU Library General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
***************************************************************************/
#include "model.h"
#include <kross/core/action.h>
#include <kross/core/actioncollection.h>
#include <kross/core/manager.h>
#include <kglobal.h>
#include <klocale.h>
#include <kdebug.h>
#include <QtCore/QEvent>
#include <QtCore/QMimeData>
#include <QtCore/QPointer>
using namespace Kross;
/******************************************************************************
* ActionCollectionModel
*/
namespace Kross {
/// \internal d-pointer class.
class ActionCollectionModel::Private
{
public:
QPointer<ActionCollection> collection;
Mode mode;
};
}
ActionCollectionModel::ActionCollectionModel(QObject* parent, ActionCollection* collection, Mode mode)
: QAbstractItemModel(parent)
, d( new Private() )
{
//krossdebug( QString( "ActionCollectionModel::ActionCollectionModel:") );
d->collection = collection ? collection : Kross::Manager::self().actionCollection();
d->mode = mode;
//setSupportedDragActions(Qt::MoveAction);
//ActionCollection propagates signals to parent
QObject::connect( d->collection, SIGNAL(dataChanged(Action*)), this, SLOT(slotDataChanged(Action*)) );
QObject::connect( d->collection, SIGNAL(dataChanged(ActionCollection*)), this, SLOT(slotDataChanged(ActionCollection*)) );
QObject::connect( d->collection, SIGNAL(collectionToBeInserted(ActionCollection*,ActionCollection*)), this, SLOT(slotCollectionToBeInserted(ActionCollection*,ActionCollection*)) );
QObject::connect( d->collection, SIGNAL(collectionInserted(ActionCollection*,ActionCollection*)), this, SLOT(slotCollectionInserted(ActionCollection*,ActionCollection*)) );
QObject::connect( d->collection, SIGNAL(collectionToBeRemoved(ActionCollection*,ActionCollection*)), this, SLOT(slotCollectionToBeRemoved(ActionCollection*,ActionCollection*)) );
QObject::connect( d->collection, SIGNAL(collectionRemoved(ActionCollection*,ActionCollection*)), this, SLOT(slotCollectionRemoved(ActionCollection*,ActionCollection*)) );
QObject::connect( d->collection, SIGNAL(actionToBeInserted(Action*,ActionCollection*)), this, SLOT(slotActionToBeInserted(Action*,ActionCollection*)) );
QObject::connect( d->collection, SIGNAL(actionInserted(Action*,ActionCollection*)), this, SLOT(slotActionInserted(Action*,ActionCollection*)) );
QObject::connect( d->collection, SIGNAL(actionToBeRemoved(Action*,ActionCollection*)), this, SLOT(slotActionToBeRemoved(Action*,ActionCollection*)) );
QObject::connect( d->collection, SIGNAL(actionRemoved(Action*,ActionCollection*)), this, SLOT(slotActionRemoved(Action*,ActionCollection*)) );
}
ActionCollectionModel::~ActionCollectionModel()
{
delete d;
}
ActionCollection *ActionCollectionModel::rootCollection() const
{
return d->collection;
}
int ActionCollectionModel::rowNumber( ActionCollection *collection ) const
{
Q_ASSERT( collection != 0 );
ActionCollection *par = collection->parentCollection();
Q_ASSERT( par != 0 );
int row = par->collections().indexOf( collection->objectName() ) + par->actions().count();
return row;
}
QModelIndex ActionCollectionModel::indexForCollection( ActionCollection *collection ) const
{
if ( collection == d->collection ) {
return QModelIndex();
}
return createIndex( rowNumber( collection ), 0, collection->parentCollection() );
}
QModelIndex ActionCollectionModel::indexForAction( Action *act ) const
{
ActionCollection *coll = static_cast<ActionCollection*>( act->parent() );
return createIndex( coll->actions().indexOf( act ), 0, coll );
}
void ActionCollectionModel::slotCollectionToBeInserted( ActionCollection* child, ActionCollection* parent )
{
//krossdebug( QString( "ActionCollectionModel::slotCollectionToBeInserted: %1 %2" ).arg( child->name() ).arg( parent->name( ) ) );
Q_ASSERT( parent );
Q_UNUSED( child )
int row = parent->actions().count() + parent->collections().count(); // we assume child is appended!!
QModelIndex parIdx = indexForCollection( parent );
beginInsertRows( parIdx, row, row );
}
void ActionCollectionModel::slotCollectionInserted( ActionCollection*, ActionCollection* )
{
//krossdebug( QString( "ActionCollectionModel::slotCollectionInserted: %1 %2" ).arg( child->name( ) ).arg( parent->name( ) ) );
endInsertRows();
}
void ActionCollectionModel::slotCollectionToBeRemoved( ActionCollection* child, ActionCollection* parent )
{
//krossdebug( QString( "ActionCollectionModel::slotCollectionToBeRemoved: %1 %2" ).arg( child->name() ).arg( parent->name() ) );
int row = rowNumber( child );
QModelIndex parIdx = indexForCollection( parent );
beginRemoveRows( parIdx, row, row );
}
void ActionCollectionModel::slotCollectionRemoved( ActionCollection*, ActionCollection* )
{
//krossdebug( QString( "ActionCollectionModel::slotCollectionRemoved: %1 %2" ).arg( child->name() ).arg( parent->name() ) );
endRemoveRows();
}
void ActionCollectionModel::slotActionToBeInserted( Action* child, ActionCollection* parent )
{
//krossdebug( QString( "ActionCollectionModel::slotActionInserted: %1 %2" ).arg( child->name() ).arg( parent->name() ) );
Q_ASSERT( parent );
Q_UNUSED( child )
int row = parent->actions().count(); // assume child is appended to actions!!
QModelIndex parIdx = indexForCollection( parent );
beginInsertRows( parIdx, row, row );
}
void ActionCollectionModel::slotActionInserted( Action*, ActionCollection* )
{
//krossdebug( QString( "ActionCollectionModel::slotActionInserted: %1 %2" ).arg( child->name() ).arg( parent->name() ) );
endInsertRows();
}
void ActionCollectionModel::slotActionToBeRemoved( Action* child, ActionCollection* parent )
{
//krossdebug( QString( "ActionCollectionModel::slotActionToBeRemoved: %1 %2" ).arg( child->name() ).arg( parent->name() ) );
Q_ASSERT( parent );
int row = parent->actions().indexOf( child );
QModelIndex parIdx = indexForCollection( parent );
beginRemoveRows( parIdx, row, row );
}
void ActionCollectionModel::slotActionRemoved( Action*, ActionCollection* )
{
//krossdebug( QString( "ActionCollectionModel::slotActionRemoved: %1 %2" ).arg( child->name() ).arg( parent->name() ) );
endRemoveRows();
}
//NOTE: not used anymore, remove?
void ActionCollectionModel::slotUpdated()
{
//emit layoutAboutToBeChanged();
//emit layoutChanged();
}
void ActionCollectionModel::slotDataChanged( ActionCollection* coll )
{
//krossdebug( QString( "ActionCollectionModel::slotDataChanged: %1" ).arg( coll->name() ) );
QModelIndex idx = indexForCollection( coll );
emit dataChanged( idx, idx ); // NOTE: change if more than one column
}
void ActionCollectionModel::slotDataChanged( Action* act )
{
//krossdebug( QString( "ActionCollectionModel::slotDataChanged: %1" ).arg( act->name() ) );
QModelIndex idx = indexForAction( act );
emit dataChanged( idx, idx ); // NOTE: change if more than one column
}
Action* ActionCollectionModel::action(const QModelIndex& index)
{
ActionCollection *par = static_cast<ActionCollection*>( index.internalPointer() );
if ( par == 0 || index.row() >= par->actions().count() ) {
return 0;
}
return par->actions().value( index.row() );
}
ActionCollection* ActionCollectionModel::collection(const QModelIndex& index)
{
ActionCollection *par = static_cast<ActionCollection*>( index.internalPointer() );
if ( par == 0 ) {
return 0;
}
int row = index.row() - par->actions().count();
if ( row < 0 ) {
return 0; // this is probably an action
}
return par->collection( par->collections().value( row) );
}
int ActionCollectionModel::columnCount(const QModelIndex&) const
{
return 1;
}
int ActionCollectionModel::rowCount(const QModelIndex& index) const
{
if ( action( index) ) {
return 0;
}
ActionCollection* par = index.isValid() ? collection( index ) : d->collection.data();
Q_ASSERT_X( par, "ActionCollectionModel::rowCount", "index is not an action nor a collection" );
if (!par) {
kWarning()<<"index is not an action nor a collection"<<index;
return 0;
}
int rows = par->actions().count() + par->collections().count();
return rows;
}
QModelIndex ActionCollectionModel::index(int row, int column, const QModelIndex& parent) const
{
if ( ! hasIndex( row, column, parent ) ) {
return QModelIndex();
}
ActionCollection* par = parent.isValid() ? collection( parent ) : d->collection.data();
if ( par == 0 ) {
// safety: may happen if parent index is an action (ModelTest tests this)
return QModelIndex();
}
return createIndex( row, column, par );
}
QModelIndex ActionCollectionModel::parent(const QModelIndex& index) const
{
if( ! index.isValid() ) {
return QModelIndex();
}
ActionCollection *par = static_cast<ActionCollection*>( index.internalPointer() );
Q_ASSERT( par != 0 );
if ( par == d->collection ) {
return QModelIndex();
}
return createIndex( rowNumber( par ), 0, par->parentCollection() );
}
Qt::ItemFlags ActionCollectionModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
if( ! index.isValid() )
return Qt::ItemIsDropEnabled | flags;
flags |= Qt::ItemIsSelectable;
//flags |= Qt::ItemIsEditable;
flags |= Qt::ItemIsDragEnabled;
flags |= Qt::ItemIsDropEnabled;
if( (index.column() == 0) && (d->mode & UserCheckable) )
flags |= Qt::ItemIsUserCheckable;
return flags;
}
QVariant ActionCollectionModel::data(const QModelIndex& index, int role) const
{
if( index.isValid() ) {
Action *act = action( index );
if ( act ) {
switch( role ) {
case Qt::DecorationRole: {
if( d->mode & Icons )
if( ! act->iconName().isEmpty() )
return act->icon();
} break;
case Qt::DisplayRole:
return KGlobal::locale()->removeAcceleratorMarker( act->text() );
case Qt::ToolTipRole: // fall through
case Qt::WhatsThisRole: {
if( d->mode & ToolTips ) {
const QString file = QFileInfo( act->file() ).fileName();
return QString( "<qt><b>%1</b><br>%2</qt>" )
.arg( file.isEmpty() ? act->name() : file )
.arg( act->description() );
}
} break;
case Qt::CheckStateRole: {
if( d->mode & UserCheckable )
return act->isEnabled() ? Qt::Checked : Qt::Unchecked;
} break;
default: break;
}
return QVariant();
}
ActionCollection *coll = collection( index );
if ( coll ) {
switch( role ) {
case Qt::DecorationRole: {
if( d->mode & Icons )
if( ! coll->iconName().isEmpty() )
return coll->icon();
} break;
case Qt::DisplayRole:
return coll->text();
case Qt::ToolTipRole: // fall through
case Qt::WhatsThisRole: {
if( d->mode & ToolTips )
return QString( "<qt><b>%1</b><br>%2</qt>" ).arg( coll->text() ).arg( coll->description() );
} break;
case Qt::CheckStateRole: {
if( d->mode & UserCheckable )
return coll->isEnabled() ? Qt::Checked : Qt::Unchecked;
} break;
default: break;
}
return QVariant();
}
}
return QVariant();
}
bool ActionCollectionModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
Q_UNUSED(value);
if( ! index.isValid() /*|| ! (d->mode & UserCheckable)*/ )
return false;
Action *act = action( index );
if ( act ) {
switch( role ) {
//case Qt::EditRole: act->setText( value.toString() ); break;
case Qt::CheckStateRole: act->setEnabled( ! act->isEnabled() ); break;
default: return false;
}
return false;
}
ActionCollection *coll = collection( index );
if ( coll ) {
switch( role ) {
//case Qt::EditRole: item->coll->setText( value.toString() ); break;
case Qt::CheckStateRole: coll->setEnabled( ! coll->isEnabled() ); break;
default: return false;
}
return false;
}
//emit dataChanged(index, index);
return true;
}
bool ActionCollectionModel::insertRows(int row, int count, const QModelIndex& parent)
{
krossdebug( QString("ActionCollectionModel::insertRows: row=%1 count=%2").arg(row).arg(count) );
if( ! parent.isValid() )
return false;
ActionCollection* coll = collection( parent );
if ( coll ) {
krossdebug( QString( "ActionCollectionModel::insertRows: parentindex is ActionCollection with name=%1" ).arg( coll->name() ) );
} else {
Action *act = action( parent );
if ( act ) {
krossdebug( QString( "ActionCollectionModel::insertRows: parentindex is Action with name=%1" ).arg( act->name() ) );
}
}
return QAbstractItemModel::insertRows(row, count, parent);
}
bool ActionCollectionModel::removeRows(int row, int count, const QModelIndex& parent)
{
krossdebug( QString("ActionCollectionModel::removeRows: row=%1 count=%2").arg(row).arg(count) );
return QAbstractItemModel::removeRows(row, count, parent);
}
bool ActionCollectionModel::insertColumns(int column, int count, const QModelIndex& parent)
{
krossdebug( QString("ActionCollectionModel::insertColumns: column=%1 count=%2").arg(column).arg(count) );
return QAbstractItemModel::insertColumns(column, count, parent);
}
bool ActionCollectionModel::removeColumns(int column, int count, const QModelIndex& parent)
{
krossdebug( QString("ActionCollectionModel::removeColumns: column=%1 count=%2").arg(column).arg(count) );
return QAbstractItemModel::removeColumns(column, count, parent);
}
QStringList ActionCollectionModel::mimeTypes() const
{
//krossdebug( QString("ActionCollectionModel::mimeTypes") );
return QStringList() << "application/vnd.text.list";
}
QString fullPath(const QModelIndex& index)
{
if( ! index.isValid() ) return QString();
QString n;
Action *a = ActionCollectionModel::action( index );
if ( a ) {
n = a->name();
} else {
ActionCollection *c = ActionCollectionModel::collection( index );
if ( c ) {
n = c->name() + '/';
if ( ! n.endsWith('/' ) )
n += '/';
}
}
ActionCollection* par = static_cast<ActionCollection*>( index.internalPointer() );
for ( ActionCollection *p = par; p != 0; p = par->parentCollection() ) {
QString s = p->name();
if ( ! s.endsWith( '/' ) ) {
s += '/';
}
n = s + n;
}
return n;
}
QMimeData* ActionCollectionModel::mimeData(const QModelIndexList& indexes) const
{
//krossdebug( QString("ActionCollectionModel::mimeData") );
QMimeData* mimeData = new QMimeData();
QByteArray encodedData;
QDataStream stream(&encodedData, QIODevice::WriteOnly);
foreach(const QModelIndex &index, indexes) {
//if( ! index.isValid() ) continue;
//QString text = data(index, Qt::DisplayRole).toString();
QString path = fullPath(index);
if( ! path.isNull() )
stream << path;
}
mimeData->setData("application/vnd.text.list", encodedData);
return mimeData;
}
bool ActionCollectionModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent)
{
krossdebug( QString("ActionCollectionModel::dropMimeData: row=%1 col=%2").arg(row).arg(column) );
if( action == Qt::IgnoreAction ) return true;
if( ! data->hasFormat("application/vnd.text.list") ) return false;
if( column > 0 ) return false;
krossdebug( QString("ActionCollectionModel::dropMimeData: ENCODED DATA:") );
QByteArray encodedData = data->data("application/vnd.text.list");
QDataStream stream(&encodedData, QIODevice::ReadOnly);
QStringList newItems;
int rows = 0;
while( ! stream.atEnd() ) {
QString text;
stream >> text;
newItems << text;
krossdebug( QString(" %1 \"%2\"").arg(rows).arg(text) );
++rows;
}
//FIXME: return false for now since insertRows/removeRows need to be implemented before!
//return false;
/*
int beginRow;
if( row != -1 )
beginRow = row;
else if( parent.isValid() )
beginRow = parent.row();
else
beginRow = rowCount( QModelIndex() );
krossdebug( QString("ActionCollectionModel::dropMimeData: beginRow=%1").arg(beginRow) );
*/
QModelIndex targetindex = index( row, column, parent );
ActionCollection *coll = collection( targetindex );
if ( coll ) {
krossdebug( QString( "ActionCollectionModel::dropMimeData: parentindex is ActionCollection with name=%1" ).arg( coll->name() ) );
} else {
Action *act = this->action( targetindex );
if ( act ) {
krossdebug( QString( "ActionCollectionModel::dropMimeData: parentindex is Action with name=%1" ).arg( act->name() ) );
}
}
return false;
//return QAbstractItemModel::dropMimeData(data, action, row, column, parent);
}
Qt::DropActions ActionCollectionModel::supportedDropActions() const
{
return Qt::CopyAction | Qt::MoveAction | Qt::TargetMoveAction;
//return Qt::CopyAction | Qt::MoveAction | Qt::TargetMoveAction | Qt::LinkAction;
}
/******************************************************************************
* ActionCollectionProxyModel
*/
ActionCollectionProxyModel::ActionCollectionProxyModel(QObject* parent, ActionCollectionModel* model)
: QSortFilterProxyModel(parent)
{
setSourceModel( model ? model : new ActionCollectionModel(this) );
setFilterCaseSensitivity(Qt::CaseInsensitive);
setDynamicSortFilter(true);
}
ActionCollectionProxyModel::~ActionCollectionProxyModel()
{
}
void ActionCollectionProxyModel::setSourceModel(QAbstractItemModel* sourceModel)
{
Q_ASSERT( dynamic_cast< ActionCollectionModel* >(sourceModel) );
QSortFilterProxyModel::setSourceModel(sourceModel);
}
bool ActionCollectionProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
{
//krossdebug( QString( "ActionCollectionProxyModel::filterAcceptsRow: row=%1 parentrow=%2" ).arg( source_row ).arg( source_parent.row() ) );
QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
if( ! index.isValid() )
return false;
Action *action = ActionCollectionModel::action( index );
if ( action ) {
return action->isEnabled() && QSortFilterProxyModel::filterAcceptsRow( source_row, source_parent );
}
ActionCollection *collection = ActionCollectionModel::collection( index );
if( collection ) {
return collection->isEnabled();
}
return true;
}
#include "moc_model.cpp"