diff --git a/kcm_hotkeys/hotkeys_model.cpp b/kcm_hotkeys/hotkeys_model.cpp index 8703f83..daeb068 100644 --- a/kcm_hotkeys/hotkeys_model.cpp +++ b/kcm_hotkeys/hotkeys_model.cpp @@ -1,710 +1,710 @@ /* Copyright (C) 2008 Michael Jansen This library 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 library 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 library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "hotkeys_model.h" #include "action_data/simple_action_data.h" #include "action_data/menuentry_shortcut_action_data.h" #include "action_data/action_data_group.h" #include #include #include #include - +#include static KHotKeys::ActionDataBase *findElement( void *ptr ,KHotKeys::ActionDataGroup *root) { Q_ASSERT(root); if (!root) return NULL; KHotKeys::ActionDataBase *match = NULL; Q_FOREACH( KHotKeys::ActionDataBase *element, root->children()) { if (ptr == element) { match = element; break; } if (KHotKeys::ActionDataGroup *subGroup = dynamic_cast(element)) { match = findElement(ptr, subGroup); if (match) break; } } return match; } KHotkeysModel::KHotkeysModel( QObject *parent ) : QAbstractItemModel(parent) ,_settings() ,_actions(0) {} KHotkeysModel::~KHotkeysModel() { } QModelIndex KHotkeysModel::addGroup( const QModelIndex & parent ) { KHotKeys::ActionDataGroup *list; if (parent.isValid()) { list = indexToActionDataGroup(parent); } else { list = _actions; } Q_ASSERT(list); beginInsertRows( parent, list->size(), list->size() ); /* KHotKeys:: ActionDataGroup *action = */ new KHotKeys::ActionDataGroup( list, i18n("New Group"), i18n("Comment")); endInsertRows(); return index( list->size()-1, NameColumn, parent ); } // Add a group QModelIndex KHotkeysModel::insertActionData( KHotKeys::ActionDataBase *data, const QModelIndex & parent ) { Q_ASSERT(data); KHotKeys::ActionDataGroup *list; if (parent.isValid()) { list = indexToActionDataGroup(parent); } else { list = _actions; } Q_ASSERT(list); beginInsertRows( parent, list->size(), list->size() ); list->add_child(data); endInsertRows(); return index( list->size()-1, NameColumn, parent ); } int KHotkeysModel::columnCount( const QModelIndex & ) const { return 2; } QVariant KHotkeysModel::data( const QModelIndex &index, int role ) const { // Check that the index is valid if (!index.isValid()) { return QVariant(); } // Get the item behind the index KHotKeys::ActionDataBase *action = indexToActionDataBase(index); Q_ASSERT(action); // Handle CheckStateRole if (role==Qt::CheckStateRole) { switch(index.column()) { case EnabledColumn: // If the parent is enabled we display the state of the object. // If the parent is disabled this object is disabled too. if (action->parent() && !action->parent()->isEnabled()) { return Qt::Unchecked; } return action->isEnabled() ? Qt::Checked : Qt::Unchecked; default: return QVariant(); } } // Display and Tooltip. Tooltip displays the complete name. That's nice if // there is not enough space else if (role==Qt::DisplayRole || role==Qt::ToolTipRole) { switch (index.column()) { case NameColumn: return action->name(); case EnabledColumn: return QVariant(); case IsGroupColumn: return indexToActionDataGroup(index)!=0; case TypeColumn: { const std::type_info &ti = typeid(*action); if (ti==typeid(KHotKeys::SimpleActionData)) return KHotkeysModel::SimpleActionData; else if (ti==typeid(KHotKeys::MenuEntryShortcutActionData)) return KHotkeysModel::SimpleActionData; else if (ti==typeid(KHotKeys::ActionDataGroup)) return KHotkeysModel::ActionDataGroup; else return KHotkeysModel::Other; } default: return QVariant(); } } // Decoration role else if (role==Qt::DecorationRole) { switch (index.column()) { // The 0 is correct here. We want to decorate that column // regardless of the content it has case 0: return dynamic_cast(action) ? QIcon::fromTheme("folder") : QVariant(); default: return QVariant(); } } //Providing the current action name on edit else if (role==Qt::EditRole) { switch (index.column()) { case NameColumn: return action->name(); default: return QVariant(); } } else if (role==Qt::ForegroundRole) { QPalette pal; switch (index.column()) { case NameColumn: if (!action->isEnabled()) { return pal.color(QPalette::Disabled, QPalette::Foreground); } default: return QVariant(); } } // For everything else return QVariant(); } bool KHotkeysModel::dropMimeData( const QMimeData *data ,Qt::DropAction action ,int row ,int column ,const QModelIndex &parent) { Q_UNUSED(column); // We only support move actions and our own mime type if ( (action!=Qt::CopyAction) || !data->hasFormat("application/x-pointer")) { qDebug() << "Drop not supported " << data->formats(); return false; } // Decode the stream QByteArray encodedData = data->data("application/x-pointer"); QDataStream stream(&encodedData, QIODevice::ReadOnly); QList ptrs; while (!stream.atEnd()) { quintptr ptr; stream >> ptr; ptrs << ptr; } // No pointers, nothing to do if (ptrs.empty()) return false; // Get the group we have to drop into. If the drop target is no group get // it's parent and drop behind it int position = row; QModelIndex dropIndex = parent; KHotKeys::ActionDataGroup *dropToGroup = indexToActionDataGroup(dropIndex); if (!dropToGroup) { dropIndex = parent.parent(); dropToGroup = indexToActionDataGroup(dropIndex); position = dropToGroup->children().indexOf(indexToActionDataBase(parent)); } if (position==-1) { position = dropToGroup->size(); } // Do the moves Q_FOREACH(quintptr ptr, ptrs) { KHotKeys::ActionDataBase *element = findElement( reinterpret_cast(ptr), _actions); if (element) moveElement(element, dropToGroup, position); } return true; } void KHotkeysModel::emitChanged(KHotKeys::ActionDataBase *item) { Q_ASSERT( item ); KHotKeys::ActionDataGroup *parent = item->parent(); QModelIndex topLeft; QModelIndex bottomRight; if (!parent) { topLeft = createIndex( 0, 0, _actions ); bottomRight = createIndex( 0, 0, _actions ); } else { int row = parent->children().indexOf(item); topLeft = createIndex( row, 0, parent ); bottomRight = createIndex( row, columnCount(topLeft), parent ); } emit dataChanged( topLeft, bottomRight ); } void KHotkeysModel::exportInputActions( const QModelIndex &index, KConfigBase &config, const QString& id, const KHotKeys::ActionState state, bool mergingAllowed) { KHotKeys::ActionDataBase *element = indexToActionDataBase(index); KHotKeys::ActionDataGroup *group = indexToActionDataGroup(index); settings()->exportTo( group ? group : element->parent(), config, id, state, mergingAllowed); } Qt::ItemFlags KHotkeysModel::flags( const QModelIndex &index ) const { Qt::ItemFlags flags = QAbstractItemModel::flags(index); Q_ASSERT(!(flags & Qt::ItemIsDropEnabled)); Q_ASSERT(!(flags & Qt::ItemIsDragEnabled)); if (!index.isValid()) { return flags | Qt::ItemIsDropEnabled; } KHotKeys::ActionDataBase *element = indexToActionDataBase(index); KHotKeys::ActionDataGroup *actionGroup = indexToActionDataGroup(index); if (!actionGroup) actionGroup = element->parent(); Q_ASSERT(element); Q_ASSERT(actionGroup); // We do not allow dragging for system groups and their elements // We do not allow dropping into systemgroups if (!actionGroup->is_system_group()) { flags |= Qt::ItemIsDragEnabled; flags |= Qt::ItemIsDropEnabled; } // Show a checkbox in column 1 whatever is shown there. switch (index.column()) { case 1: return flags | Qt::ItemIsUserCheckable; default: return flags | Qt::ItemIsEditable; } } // Get header data for section QVariant KHotkeysModel::headerData( int section, Qt::Orientation, int role ) const { if (role!=Qt::DisplayRole) { return QVariant(); } switch (section) { case NameColumn: return QVariant(i18nc("action name", "Name")); case EnabledColumn: return QVariant(); return QVariant(i18nc("action enabled", "Enabled")); case IsGroupColumn: return QVariant(i18n("Type")); default: return QVariant(); } } void KHotkeysModel::importInputActions(const QModelIndex &index, KConfigBase const &config) { KHotKeys::ActionDataGroup *group = indexToActionDataGroup(index); QModelIndex groupIndex = index; if (!group) { group = indexToActionDataBase(index)->parent(); groupIndex = index.parent(); } if (settings()->importFrom(group, config, KHotKeys::ImportAsk, KHotKeys::Retain)) { qDebug(); reset(); save(); } } QModelIndex KHotkeysModel::index( int row, int column, const QModelIndex &parent ) const { KHotKeys::ActionDataGroup *actionGroup = indexToActionDataGroup(parent); if (!actionGroup || row>=actionGroup->children().size() ) { return QModelIndex(); } KHotKeys::ActionDataBase *action = actionGroup->children().at(row); Q_ASSERT( action ); return createIndex( row, column, action ); } // Convert index to ActionDataBase KHotKeys::ActionDataBase *KHotkeysModel::indexToActionDataBase( const QModelIndex &index ) const { if (!index.isValid()) { return _actions; } return static_cast( index.internalPointer() ); } // Convert index to ActionDataGroup KHotKeys::ActionDataGroup *KHotkeysModel::indexToActionDataGroup( const QModelIndex &index ) const { if (!index.isValid()) { return _actions; } return dynamic_cast( indexToActionDataBase(index) ); } void KHotkeysModel::load() { _settings.reread_settings(true); _actions = _settings.actions(); reset(); } QMimeData *KHotkeysModel::mimeData(const QModelIndexList &indexes) const { QMimeData * mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); Q_FOREACH (const QModelIndex &index, indexes) { if (index.isValid() && index.column() == 0) { KHotKeys::ActionDataBase *element = indexToActionDataBase(index); // We use the pointer as id. stream << reinterpret_cast(element); } } mimeData->setData("application/x-pointer", encodedData); return mimeData; } QStringList KHotkeysModel::mimeTypes() const { QStringList types; types << "application/x-pointer"; return types; } bool KHotkeysModel::moveElement( KHotKeys::ActionDataBase *element ,KHotKeys::ActionDataGroup *newGroup ,int position) { Q_ASSERT(element && newGroup); if (!element || !newGroup) return false; // TODO: Make this logic more advanced // We do not allow moving into our systemgroup if (newGroup->is_system_group()) return false; // Make sure we don't move a group to one of it's children or // itself. KHotKeys::ActionDataGroup *tmp = newGroup; do { if (tmp == element) { qDebug() << "Forbidden move" << tmp->name(); return false; } } while((tmp = tmp->parent())); KHotKeys::ActionDataGroup *oldParent = element->parent(); // TODO: Make this logic more advanced // We do not allow moving from our systemgroup if (oldParent->is_system_group()) return false; // Adjust position if oldParent and newGroup are identical if (oldParent == newGroup) { if (oldParent->children().indexOf(element) < position) { --position; } } emit layoutAboutToBeChanged(); // Remove it from it's current place oldParent->remove_child(element); newGroup->add_child(element, position); emit layoutChanged(); return true; } // Get parent object for index QModelIndex KHotkeysModel::parent( const QModelIndex &index ) const { KHotKeys::ActionDataBase *action = indexToActionDataBase(index); if (!action) { return QModelIndex(); } KHotKeys::ActionDataGroup *parent = action->parent(); if (!parent) { return QModelIndex(); } KHotKeys::ActionDataGroup *grandparent = parent->parent(); if (!grandparent) { return QModelIndex(); } int row = grandparent->children().indexOf(parent); return createIndex( row, 0, parent ); } // Remove rows ( items ) bool KHotkeysModel::removeRows( int row, int count, const QModelIndex &parent ) { Q_ASSERT( count == 1 ); beginRemoveRows( parent, row, row+count-1 ); KHotKeys::ActionDataGroup *list; if (parent.isValid()) { list = indexToActionDataGroup(parent); } else { list = _actions; } Q_ASSERT(list); KHotKeys::ActionDataBase *action = indexToActionDataBase(index(row,0,parent)); action->aboutToBeErased(); delete action; endRemoveRows(); return true; } // Number of rows for index int KHotkeysModel::rowCount( const QModelIndex &index ) const { KHotKeys::ActionDataGroup *group = indexToActionDataGroup(index); if (!group) { return 0; } return group->children().count(); } void KHotkeysModel::save() { _settings.write(); } // Set data bool KHotkeysModel::setData( const QModelIndex &index, const QVariant &value, int role ) { if ( !index.isValid() ) { return false; } KHotKeys::ActionDataBase *action = indexToActionDataBase(index); Q_ASSERT( action ); // Handle CheckStateRole if ( role == Qt::CheckStateRole ) { switch(index.column()) { case EnabledColumn: { // If the parent is enabled we display the state of the object. // If the parent is disabled this object is disabled too. if (action->parent() && !action->parent()->isEnabled()) { // TODO: Either show a message box or enhance the gui to // show this item cannot be enabled return false; } value.toInt() == Qt::Checked ? action->enable() : action->disable(); // If this is a group we have to inform the view that all our // childs have changed. They are all disabled now KHotKeys::ActionDataGroup *actionGroup = indexToActionDataGroup(index); if (actionGroup && actionGroup->size()) { Q_EMIT dataChanged( createIndex(0, 0, actionGroup), createIndex(actionGroup->size(), columnCount(index), actionGroup)); } } break; default: return false; } } else if ( role == Qt::EditRole ) { switch ( index.column() ) { case NameColumn: { action->set_name( value.toString() ); } break; default: return false; } } else return false; emit dataChanged( index, index ); return true; } KHotKeys::Settings *KHotkeysModel::settings() { return &_settings; } #include "moc_hotkeys_model.cpp"