[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-devel
Subject:    Bug fixes in kross
From:       Dag Andersen <danders () get2net ! dk>
Date:       2008-11-19 8:22:09
Message-ID: 200811190922.09763.danders () get2net ! dk
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


Hi, here is a patch that fixes some bugs in kross.
Please review and commit if ok.
Please CC if questions, I'm not on the list

I *think* the changes are BC but I'm not an expert so please check.
In general, methods, signals and slots are added to the api. Existing method 
signatures are not changed.

Short description of changes:
Fixes bug in ActionCollectionModel when actions or actioncollections are 
inserted/removed.
The model did not pick up the changes properly and also the presentation was 
jumbled because stale indexes where stored.
The changes has been tested with ModelTest from qt labs using  koffice script 
manager.
Action:
* removes itself from parent ActionCollection when deleted.
* emit new signal dataChanged(Action*) when data is changed.
ActionCollection:
* new signals to enable models to pick up on inserted/removed objects.
* emits new signal dataChanged(ActionCollection*) when data is changed.
ActionCollectionModel:
* added slots to pick up on changes in the data structure
-- 
Mvh.
Dag Andersen

[Attachment #5 (text/html)]

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" \
"http://www.w3.org/TR/REC-html40/strict.dtd"><html><head><meta name="qrichtext" \
content="1" /><style type="text/css">p, li { white-space: pre-wrap; \
}</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; \
font-weight:400; font-style:normal;">Hi, here is a patch that fixes some bugs in \
kross.<br> Please review and commit if ok.<br>
Please CC if questions, I'm not on the list<br>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; \
margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; \
-qt-user-state:0;"><br></p>I *think* the changes are BC but I'm not an expert so \
please check.<br> In general, methods, signals and slots are added to the api. \
Existing method signatures are not changed.<br> <p style="-qt-paragraph-type:empty; \
margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; \
-qt-block-indent:0; text-indent:0px; -qt-user-state:0;"><br></p>Short description of \
changes:<br> Fixes bug in ActionCollectionModel when actions or actioncollections are \
inserted/removed.<br> The model did not pick up the changes properly and also the \
presentation was jumbled because stale indexes where stored.<br> The changes has been \
tested with ModelTest from qt labs using  koffice script manager.<br> Action:<br>
* removes itself from parent ActionCollection when deleted.<br>
* emit new signal dataChanged(Action*) when data is changed.<br>
ActionCollection:<br>
* new signals to enable models to pick up on inserted/removed objects.<br>
* emits new signal dataChanged(ActionCollection*) when data is changed.<br>
ActionCollectionModel:<br>
* added slots to pick up on changes in the data structure<br>
-- <br>
Mvh.<br>
Dag Andersen</p></body></html>


["d.diff" (text/x-patch)]

Index: core/actioncollection.h
===================================================================
--- core/actioncollection.h	(revision 886009)
+++ core/actioncollection.h	(working copy)
@@ -33,8 +33,15 @@
 namespace Kross {
 
     /**
-     * The ActionCollection class manages collections of \a Action
-     * instances.
+     * The ActionCollection class manages collections of \a Action instances.
+     * An ActionCollection can have both actions and other collections as children.
+     * Child actions can be accessed using actions() which returns a list of Action \
pointers. +     * Child collections can be accessed using collections() which returns \
a list of collection names. +     * The collection can then be accessed with \
collection(name). +     * To add a child action, call addAction(), and to remove an \
action: removeAction(). +     * To add a child collection, call \
setParentCollection(parent) in the collection you want to add to parent. +     * To \
remove a collection call setParentCollection(0). +     * NOTE: Do not use \
                setParent().
      */
     class KROSSCORE_EXPORT ActionCollection : public QObject
     {
@@ -50,7 +57,7 @@
              * ActionCollection will be child of. If parent is not
              * NULL, this \a ActionCollection instance will register
              * itself as child of the parent \p parent by using the
-             * \a registerCollection method.
+             * \a setParentCollection method.
              */
             explicit ActionCollection(const QString& name, ActionCollection* parent \
= 0);  
@@ -111,11 +118,12 @@
 
             /**
              * \return the parent \a ActionCollection instance this
-             * \collection is child of or NULL oif this collection
+             * \collection is child of or NULL if this collection
              * does not have a parent.
              */
             ActionCollection* parentCollection() const;
-
+            /// Set the parent to @p parent. NOTE: Do not use setParent().
+            void setParentCollection( ActionCollection *parent );
             /**
              * \return true if this collection has a child \a ActionCollection
              * instance which objectName is \p name .
@@ -190,14 +198,38 @@
              */
             void updated();
 
-            //void inserted(ActionCollection* self, ActionCollection* into);
-            //void updated(ActionCollection* self);
-            //void removed(ActionCollection* self, ActionCollection* from);
+            /// This signal is emitted when the data of a child action is changed
+            void dataChanged(Action*);
+            /// This signal is emitted when the data of the ActionCollection is \
changed +            void dataChanged(ActionCollection*);
 
+            /// This signal is emitted just before @p child is added to @p parent
+            void collectionToBeInserted(ActionCollection* child, ActionCollection* \
parent); +            /// This signal is emitted after @p child has been added to @p \
parent +            void collectionInserted(ActionCollection* child, \
ActionCollection* parent); +            /// This signal is emitted before @p child is \
removed from @p parent +            void collectionToBeRemoved(ActionCollection* \
child, ActionCollection* parent); +            /// This signal is emitted after @p \
child has been removed from @p parent +            void \
collectionRemoved(ActionCollection* child, ActionCollection* parent); +
+            /// This signal is emitted just before @p child is added to @p parent
+            void actionToBeInserted(Action* child, ActionCollection* parent);
+            /// This signal is emitted after @p child has been added to @p parent
+            void actionInserted(Action* child, ActionCollection* parent);
+            /// This signal is emitted before @p child is removed from @p parent
+            void actionToBeRemoved(Action* child, ActionCollection* parent);
+            /// This signal is emitted after @p child has been removed from @p \
parent +            void actionRemoved(Action* child, ActionCollection* parent);
+
         protected:
             void registerCollection(ActionCollection* collection);
             void unregisterCollection(const QString& name);
+            void connectSignals(ActionCollection* collection, bool conn);
+            void connectSignals(Action* collection, bool conn);
 
+        private Q_SLOTS:
+            void emitUpdated();
+
         private:
             /// \internal d-pointer class.
             class Private;
Index: core/action.cpp
===================================================================
--- core/action.cpp	(revision 886009)
+++ core/action.cpp	(working copy)
@@ -18,6 +18,7 @@
  ***************************************************************************/
 
 #include "action.h"
+#include "actioncollection.h"
 #include "interpreter.h"
 #include "script.h"
 #include "manager.h"
@@ -139,6 +140,10 @@
         krossdebug( QString("Action::~Action() Dtor name='%1'").arg(objectName()) );
     #endif
     finalize();
+    ActionCollection *coll = qobject_cast<ActionCollection*>(parent());
+    if ( coll ) {
+        coll->removeAction(this);
+    }
     delete d;
 }
 
@@ -246,6 +251,7 @@
 void Action::setDescription(const QString& description)
 {
     d->description = description;
+    emit dataChanged(this);
     emit updated();
 }
 
@@ -258,6 +264,7 @@
 {
     setIcon( KIcon(iconname) );
     d->iconname = iconname;
+    emit dataChanged(this);
     emit updated();
 }
 
@@ -269,6 +276,7 @@
 void Action::setEnabled(bool enabled)
 {
     QAction::setEnabled(enabled);
+    emit dataChanged(this);
     emit updated();
 }
 
@@ -282,6 +290,7 @@
     if( d->code != code ) {
         finalize();
         d->code = code;
+        emit dataChanged(this);
         emit updated();
     }
 }
@@ -299,6 +308,7 @@
         setEnabled( Manager::self().interpreters().contains(interpretername) );
         if (!isEnabled())
             kWarning(410)<<"interpreter not found:"<<interpretername;
+        emit dataChanged(this);
         emit updated();
     }
 }
Index: core/action.h
===================================================================
--- core/action.h	(revision 886009)
+++ core/action.h	(working copy)
@@ -319,6 +319,9 @@
              */
             void updated();
 
+            /// This signal is emitted when the data of the Action is changed
+            void dataChanged(Action*);
+
             /**
              * This signal is emitted before the script got executed.
              */
Index: core/actioncollection.cpp
===================================================================
--- core/actioncollection.cpp	(revision 886009)
+++ core/actioncollection.cpp	(working copy)
@@ -50,6 +50,7 @@
             QString description;
             QString iconname;
             bool enabled;
+            bool blockupdated;
 
             Private(ActionCollection* const p) : parent(p) {}
     };
@@ -57,43 +58,63 @@
 }
 
 ActionCollection::ActionCollection(const QString& name, ActionCollection* parent)
-    : QObject(parent)
-    , d( new Private(parent) )
+    : QObject(0)
+    , d( new Private(0) )
 {
     setObjectName(name);
     d->text = name;
     d->enabled = true;
-    if( d->parent )
-        d->parent->registerCollection(this);
+    d->blockupdated = false;
+
+    setParentCollection(parent);
 }
 
 ActionCollection::~ActionCollection()
 {
-    if( d->parent )
-        d->parent->unregisterCollection(objectName());
+    setParentCollection(0);
     delete d;
 }
 
 QString ActionCollection::name() const { return objectName(); }
 
 QString ActionCollection::text() const { return d->text; }
-void ActionCollection::setText(const QString& text) { d->text = text; emit \
updated(); } +void ActionCollection::setText(const QString& text) { d->text = text; \
emit dataChanged(this); emitUpdated(); }  
 QString ActionCollection::description() const { return d->description; }
-void ActionCollection::setDescription(const QString& description) { d->description = \
description; emit updated(); } +void ActionCollection::setDescription(const QString& \
description) { d->description = description; emit dataChanged(this); emitUpdated(); } \
  QString ActionCollection::iconName() const { return d->iconname; }
-void ActionCollection::setIconName(const QString& iconname) { d->iconname = \
iconname; } +void ActionCollection::setIconName(const QString& iconname) { \
d->iconname = iconname; emit dataChanged(this); }  QIcon ActionCollection::icon() \
const { return KIcon(d->iconname); }  
 bool ActionCollection::isEnabled() const { return d->enabled; }
-void ActionCollection::setEnabled(bool enabled) { d->enabled = enabled; emit \
updated(); } +void ActionCollection::setEnabled(bool enabled) { d->enabled = enabled; \
emit dataChanged(this); emitUpdated(); }  
 ActionCollection* ActionCollection::parentCollection() const
 {
     return d->parent;
 }
 
+void ActionCollection::setParentCollection( ActionCollection *parent )
+{
+    if ( d->parent ) {
+        emit d->parent->collectionToBeRemoved(this, d->parent);
+        d->parent->unregisterCollection( objectName() );
+        setParent( 0 );
+        emit d->parent->collectionRemoved( this, d->parent );
+        d->parent = 0;
+    }
+    setParent(0);
+    if ( parent ) {
+        emit parent->collectionToBeInserted(this, parent);
+        setParent( parent );
+        d->parent = parent;
+        parent->registerCollection( this );
+        emit parent->collectionInserted( this, parent );
+    }
+    emitUpdated();
+}
+
 bool ActionCollection::hasCollection(const QString& name) const
 {
     return d->collections.contains(name);
@@ -116,8 +137,8 @@
     //Q_ASSERT( !name.isNull() );
     d->collections.insert(name, collection);
     d->collectionnames.append(name);
-    connect(collection, SIGNAL(updated()), this, SIGNAL(updated()));
-    //emit updated();
+    connectSignals(collection, true);
+    emitUpdated();
 }
 
 void ActionCollection::unregisterCollection(const QString& name)
@@ -127,8 +148,8 @@
     ActionCollection* collection = d->collections[name];
     d->collectionnames.removeAll(name);
     d->collections.remove(name);
-    disconnect(collection, SIGNAL(updated()), this, SIGNAL(updated()));
-    //emit updated();
+    connectSignals(collection, false);
+    emitUpdated();
 }
 
 QList<Action*> ActionCollection::actions() const
@@ -150,12 +171,15 @@
 void ActionCollection::addAction(const QString& name, Action* action)
 {
     Q_ASSERT( action && ! name.isEmpty() );
+    emit actionToBeInserted(action, this);
     if( d->actionMap.contains(name) )
         d->actionList.removeAll( d->actionMap[name] );
     d->actionMap.insert(name, action);
     d->actionList.append(action);
-    connect(action, SIGNAL(updated()), this, SIGNAL(updated()));
-    emit updated();
+    action->setParent(this); // in case it is not set
+    connectSignals(action, true);
+    emit actionInserted(action, this);
+    emitUpdated();
 }
 
 void ActionCollection::removeAction(const QString& name)
@@ -163,24 +187,74 @@
     if( ! d->actionMap.contains(name) )
         return;
     Action* action = d->actionMap[name];
+    connectSignals(action, false);
+    emit actionToBeRemoved(action, this);
     d->actionList.removeAll(action);
     d->actionMap.remove(name);
-    disconnect(action, SIGNAL(updated()), this, SIGNAL(updated()));
-    emit updated();
+    //krossdebug( QString("ActionCollection::removeAction: %1 \
%2").arg(action->name()).arg(action->parent()->objectName()) ); +    \
action->setParent( 0 ); +    emit actionRemoved(action, this);
+    emitUpdated();
 }
 
 void ActionCollection::removeAction(Action* action)
 {
     Q_ASSERT( action && ! action->objectName().isEmpty() );
-    const QString name = action->objectName();
-    if( ! d->actionMap.contains(name) )
+    if( ! d->actionMap.contains(action->objectName()) ) {
+        Q_ASSERT( ! d->actionList.contains(action) );
         return;
-    d->actionList.removeAll(action);
-    d->actionMap.remove(name);
-    disconnect(action, SIGNAL(updated()), this, SIGNAL(updated()));
-    emit updated();
+    }
+    removeAction( action->objectName() );
 }
 
+void ActionCollection::connectSignals(Action *action, bool conn)
+{
+    if ( conn ) {
+        connect(action, SIGNAL(dataChanged(Action*)), this, \
SIGNAL(dataChanged(Action*))); +        connect(action, SIGNAL(updated()), this, \
SLOT(emitUpdated())); +    } else {
+        disconnect(action, SIGNAL(dataChanged(Action*)), this, \
SIGNAL(dataChanged(Action*))); +        disconnect(action, SIGNAL(updated()), this, \
SLOT(emitUpdated())); +    }
+}
+
+void ActionCollection::connectSignals(ActionCollection *collection, bool conn)
+{
+    if ( conn ) {
+        connect(collection, SIGNAL(dataChanged(Action*)), this, \
SIGNAL(dataChanged(Action*))); +        connect(collection, \
SIGNAL(dataChanged(ActionCollection*)), this, \
SIGNAL(dataChanged(ActionCollection*))); +
+        connect(collection, SIGNAL(collectionToBeInserted(ActionCollection*, \
ActionCollection*)), this, SIGNAL(collectionToBeInserted(ActionCollection*, \
ActionCollection*))); +        connect(collection, \
SIGNAL(collectionInserted(ActionCollection*, ActionCollection*)), this, \
SIGNAL(collectionInserted(ActionCollection*, ActionCollection*))); +        \
connect(collection, SIGNAL(collectionToBeRemoved(ActionCollection*, \
ActionCollection*)), this, SIGNAL(collectionToBeRemoved(ActionCollection*, \
ActionCollection*))); +        connect(collection, \
SIGNAL(collectionRemoved(ActionCollection*, ActionCollection*)), this, \
SIGNAL(collectionRemoved(ActionCollection*, ActionCollection*))); +
+        connect(collection, SIGNAL(actionToBeInserted(Action*, ActionCollection*)), \
this, SIGNAL(actionToBeInserted(Action*, ActionCollection*))); +        \
connect(collection, SIGNAL(actionInserted(Action*, ActionCollection*)), this, \
SIGNAL(actionInserted(Action*, ActionCollection*))); +        connect(collection, \
SIGNAL(actionToBeRemoved(Action*, ActionCollection*)), this, \
SIGNAL(actionToBeRemoved(Action*, ActionCollection*))); +        connect(collection, \
SIGNAL(actionRemoved(Action*, ActionCollection*)), this, \
SIGNAL(actionRemoved(Action*, ActionCollection*))); +        connect(collection, \
SIGNAL(updated()), this, SLOT(emitUpdated())); +    } else {
+        disconnect(collection, SIGNAL(dataChanged(ActionCollection*)), this, \
SIGNAL(dataChanged(ActionCollection*))); +
+        disconnect(collection, SIGNAL(collectionToBeInserted(ActionCollection*, \
ActionCollection*)), this, SIGNAL(collectionToBeInserted(ActionCollection*, \
ActionCollection*))); +        disconnect(collection, \
SIGNAL(collectionInserted(ActionCollection*, ActionCollection*)), this, \
SIGNAL(collectionInserted(ActionCollection*, ActionCollection*))); +        \
disconnect(collection, SIGNAL(collectionToBeRemoved(ActionCollection*, \
ActionCollection*)), this, SIGNAL(collectionToBeRemoved(ActionCollection*, \
ActionCollection*))); +        disconnect(collection, \
SIGNAL(collectionRemoved(ActionCollection*, ActionCollection*)), this, \
SIGNAL(collectionRemoved(ActionCollection*, ActionCollection*))); +
+        disconnect(collection, SIGNAL(actionToBeInserted(Action*, \
ActionCollection*)), this, SIGNAL(actionToBeInserted(Action*, ActionCollection*))); + \
disconnect(collection, SIGNAL(actionInserted(Action*, ActionCollection*)), this, \
SIGNAL(actionInserted(Action*, ActionCollection*))); +        disconnect(collection, \
SIGNAL(actionToBeRemoved(Action*, ActionCollection*)), this, \
SIGNAL(actionToBeRemoved(Action*, ActionCollection*))); +        \
disconnect(collection, SIGNAL(actionRemoved(Action*, ActionCollection*)), this, \
SIGNAL(actionRemoved(Action*, ActionCollection*))); +        disconnect(collection, \
SIGNAL(updated()), this, SLOT(emitUpdated())); +    }
+}
+
+void ActionCollection::emitUpdated()
+{
+    if (!d->blockupdated) emit updated();
+}
+
 /*********************************************************************
  * Unserialize from XML / QIODevice / file / resource to child
  * ActionCollection's and Action's this ActionCollection has.
@@ -192,7 +266,7 @@
         krossdebug( QString("ActionCollection::readXml \
tagName=\"%1\"").arg(element.tagName()) );  #endif
 
-    blockSignals(true); // block updated() signals and emit it only once if \
everything is done +    d->blockupdated = true; // block updated() signals and emit \
it only once if everything is done  bool ok = true;
     QDomNodeList list = element.childNodes();
     const int size = list.size();
@@ -213,6 +287,7 @@
             ActionCollection* c = d->collections.contains(name) ? \
d->collections[name] : QPointer<ActionCollection>(0);  if( ! c )
                 c = new ActionCollection(name, this);
+
             c->setText( text.isEmpty() ? name : text );
             c->setDescription( description.isEmpty() ? c->text() : description );
             c->setIconName( iconname );
@@ -245,8 +320,8 @@
         //else if( ! fromXml(elem) ) ok = false;
     }
 
-    blockSignals(false); // unblock signals
-    emit updated();
+    d->blockupdated = false; // unblock signals
+    emitUpdated();
     return ok;
 }
 
Index: ui/model.cpp
===================================================================
--- ui/model.cpp	(revision 886009)
+++ ui/model.cpp	(working copy)
@@ -34,105 +34,173 @@
 
 namespace Kross {
 
-    /// \internal item representation.
-    class ActionCollectionModelItem : public QObject
-    {
-        public:
-            enum Type { ActionType, CollectionType };
-            const Type type;
-            union {
-                Action* action;
-                ActionCollection* collection;
-            };
-            QVector<ActionCollectionModelItem*> children;
-            const QModelIndex parent;
-
-            QString name() const { return type == ActionType ? action->name() : \
                collection->name(); }
-
-            explicit ActionCollectionModelItem(Action* a, const QModelIndex& p = \
                QModelIndex(), ActionCollectionModelItem* parentitem = 0)
-                : QObject(parentitem), type(ActionType), action(a), parent(p)
-            {
-            }
-
-            explicit ActionCollectionModelItem(ActionCollection* c, const \
                QModelIndex& p = QModelIndex(), ActionCollectionModelItem* parentitem \
                = 0)
-                : QObject(parentitem), type(CollectionType), collection(c), \
                parent(p)
-            {
-            }
-    };
-
     /// \internal d-pointer class.
     class ActionCollectionModel::Private
     {
         public:
             ActionCollection* collection;
-            ActionCollectionModelItem* item;
             Mode mode;
-
-            template <class T>
-            ActionCollectionModelItem* childItem( ActionCollectionModelItem* item,
-                                                  const QModelIndex& parent,
-                                                  int row,
-                                                  int column,
-                                                  T value );
     };
 
 }
 
-template <class T>
-ActionCollectionModelItem* ActionCollectionModel::Private::childItem(
-    ActionCollectionModelItem* item,
-    const QModelIndex& parent,
-    int row,
-    int column,
-    T value )
-{
-    Q_UNUSED(column);
-    ActionCollectionModelItem* childItem = 0;
-    if ( row < item->children.count() && item->children.at(row) != 0 ) {
-        childItem = item->children.at(row);
-    }
-    else {
-        childItem = new ActionCollectionModelItem(value,parent,item);
-        item->children.resize(row+1);
-        item->children[row] = childItem;
-    }
-    return childItem;
-}
-
 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->item = 0;
-    d->item = new ActionCollectionModelItem( d->collection );
     d->mode = mode;
     //setSupportedDragActions(Qt::MoveAction);
-    QObject::connect(d->collection, SIGNAL(updated()), this, SLOT(slotUpdated()));
+
+    //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->item;
     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 );
+    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 );
+    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();
+    //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)
 {
-    ActionCollectionModelItem* item = index.isValid() ? \
                static_cast<ActionCollectionModelItem*>(index.internalPointer()) : 0;
-    return (item && item->type == ActionCollectionModelItem::ActionType) ? \
item->action : 0; +    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)
 {
-    ActionCollectionModelItem* item = index.isValid() ? \
                static_cast<ActionCollectionModelItem*>(index.internalPointer()) : 0;
-    return (item && item->type == ActionCollectionModelItem::CollectionType) ? \
item->collection : 0; +    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
@@ -142,41 +210,39 @@
 
 int ActionCollectionModel::rowCount(const QModelIndex& index) const
 {
-    ActionCollectionModelItem* item = index.isValid() ? \
                static_cast<ActionCollectionModelItem*>(index.internalPointer()) : \
                d->item;
-    Q_ASSERT( item );
-    if( item->type == ActionCollectionModelItem::CollectionType )
-        return item->collection->actions().count() + \
                item->collection->collections().count();
-    return 0;
+    if ( action( index) ) {
+        return 0;
+    }
+    ActionCollection* par = index.isValid() ? collection( index ) : d->collection;
+    Q_ASSERT( par != 0 );
+    int rows = par->actions().count() + par->collections().count();
+    return rows;
 }
 
 QModelIndex ActionCollectionModel::index(int row, int column, const QModelIndex& \
parent) const  {
-    ActionCollectionModelItem* item = parent.isValid() ? \
                static_cast<ActionCollectionModelItem*>(parent.internalPointer()) : \
                d->item;
-    Q_ASSERT( item && item->type == ActionCollectionModelItem::CollectionType );
-    const int count = item->collection->actions().count();
-    if( row < count ) {
-        Action* action = dynamic_cast< Action* >( \
                item->collection->actions().value(row) );
-        if( action )
-        {
-            return createIndex(row, \
                column,d->childItem(item,parent,row,column,action));
-        }
+    if ( ! hasIndex( row, column, parent ) ) {
+        return QModelIndex();
     }
-    else {
-        QString name = item->collection->collections().value(row - count);
-        ActionCollection* collection = item->collection->collection(name);
-        if( collection )
-        {
-            return createIndex(row, \
                column,d->childItem(item,parent,row,column,collection));
-        }
+    ActionCollection* par = parent.isValid() ? collection( parent ) : d->collection;
+    if ( par == 0 ) {
+        // safety: may happen if parent index is an action (ModelTest tests this)
+        return QModelIndex();
     }
-    return QModelIndex();
+    return createIndex( row, column, par );
 }
 
 QModelIndex ActionCollectionModel::parent(const QModelIndex& index) const
 {
-    if( ! index.isValid() )
+    if( ! index.isValid() ) {
         return QModelIndex();
-    return static_cast<ActionCollectionModelItem*>(index.internalPointer())->parent;
+    }
+    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
@@ -198,56 +264,56 @@
 QVariant ActionCollectionModel::data(const QModelIndex& index, int role) const
 {
     if( index.isValid() ) {
-        ActionCollectionModelItem* item = \
                static_cast<ActionCollectionModelItem*>(index.internalPointer());
-        switch( item->type ) {
-            case ActionCollectionModelItem::ActionType: {
-                switch( role ) {
-                    case Qt::DecorationRole: {
-                        if( d->mode & Icons )
-                            if( ! item->action->iconName().isEmpty() )
-                                return item->action->icon();
-                    } break;
-                    case Qt::DisplayRole:
-                        return item->action->text().remove('&');
-                    case Qt::ToolTipRole: // fall through
-                    case Qt::WhatsThisRole: {
-                        if( d->mode & ToolTips ) {
-                            const QString file = QFileInfo( item->action->file() \
                ).fileName();
-                            return QString("<qt><b>%1</b><br>%2</qt>")
-                                .arg( file.isEmpty() ? item->action->name() : file )
-                                .arg( item->action->description() );
-                        }
-                    } break;
-                    case Qt::CheckStateRole: {
-                        if( d->mode & UserCheckable )
-                            return item->action->isEnabled();
-                    } break;
-                    default: break;
-                }
-            } break;
-            case ActionCollectionModelItem::CollectionType: {
-                switch( role ) {
-                    case Qt::DecorationRole: {
-                        if( d->mode & Icons )
-                            if( ! item->collection->iconName().isEmpty() )
-                                return item->collection->icon();
-                    } break;
-                    case Qt::DisplayRole:
-                        return item->collection->text();
-                    case Qt::ToolTipRole: // fall through
-                    case Qt::WhatsThisRole: {
-                        if( d->mode & ToolTips )
-                            return \
QString("<qt><b>%1</b><br>%2</qt>").arg(item->collection->text()).arg(item->collection->description());
                
-                    } break;
-                    case Qt::CheckStateRole: {
-                        if( d->mode & UserCheckable )
-                            return item->collection->isEnabled();
-                    } break;
-                    default: break;
-                }
-            } break;
-            default: break;
+        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 act->text().remove( '&' );
+                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();
 }
@@ -257,24 +323,25 @@
     Q_UNUSED(value);
     if( ! index.isValid() /*|| ! (d->mode & UserCheckable)*/ )
         return false;
-    ActionCollectionModelItem* item = \
                static_cast<ActionCollectionModelItem*>(index.internalPointer());
-    switch( item->type ) {
-        case ActionCollectionModelItem::ActionType: {
-            switch( role ) {
-                //case Qt::EditRole: item->action->setText( value.toString() ); \
                break;
-                case Qt::CheckStateRole: item->action->setEnabled( ! \
                item->action->isEnabled() ); break;
-                default: return false;
-            }
-        } break;
-        case ActionCollectionModelItem::CollectionType: {
-            switch( role ) {
-                //case Qt::EditRole: item->collection->setText( value.toString() ); \
                break;
-                case Qt::CheckStateRole: item->collection->setEnabled( ! \
                item->collection->isEnabled() ); break;
-                default: return false;
-            }
-        } break;
-        default: 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;
 }
@@ -285,17 +352,15 @@
     if( ! parent.isValid() )
         return false;
 
-    ActionCollectionModelItem* parentitem = \
                static_cast<ActionCollectionModelItem*>(parent.internalPointer());
-    switch( parentitem->type ) {
-        case ActionCollectionModelItem::ActionType: {
-            krossdebug( QString("ActionCollectionModel::insertRows: parentindex is \
                Action with name=%1").arg(parentitem->action->name()) );
-        } break;
-        case ActionCollectionModelItem::CollectionType: {
-            krossdebug( QString("ActionCollectionModel::insertRows: parentindex is \
                ActionCollection with name=%1").arg(parentitem->collection->name()) \
                );
-        } break;
-        default: break;
+    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);
 }
 
@@ -326,11 +391,27 @@
 QString fullPath(const QModelIndex& index)
 {
     if( ! index.isValid() ) return QString();
-    ActionCollectionModelItem* item = \
                static_cast<ActionCollectionModelItem*>(index.internalPointer());
-    QString n = item->name();
-    if( item->type == ActionCollectionModelItem::CollectionType ) n += '/';
-    QString p = fullPath( item->parent ); //recursive
-    return p.isNull() ? n : ( p.endsWith('/') ? p + n : p + '/' + n );
+    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
@@ -386,19 +467,16 @@
     krossdebug( QString("ActionCollectionModel::dropMimeData: \
                beginRow=%1").arg(beginRow) );
     */
 
-    ActionCollectionModelItem* targetparentitem = parent.isValid() ? \
                static_cast<ActionCollectionModelItem*>(parent.internalPointer()) : \
                d->item;
-    switch( targetparentitem->type ) {
-        case ActionCollectionModelItem::ActionType: {
-            krossdebug( QString("ActionCollectionModel::dropMimeData: parentindex is \
                Action with name=%1").arg(targetparentitem->action->name()) );
-        } break;
-        case ActionCollectionModelItem::CollectionType: {
-            krossdebug( QString("ActionCollectionModel::dropMimeData: parentindex is \
                ActionCollection with \
                name=%1").arg(targetparentitem->collection->name()) );
-        } break;
-        default: break;
+    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);
 }
@@ -418,6 +496,7 @@
 {
     setSourceModel( model ? model : new ActionCollectionModel(this) );
     setFilterCaseSensitivity(Qt::CaseInsensitive);
+    setDynamicSortFilter(true);
 }
 
 ActionCollectionProxyModel::~ActionCollectionProxyModel()
@@ -432,22 +511,23 @@
 
 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;
-    ActionCollectionModelItem* item = \
                static_cast<ActionCollectionModelItem*>(index.internalPointer());
-    switch( item->type ) {
-            case ActionCollectionModelItem::ActionType: {
-                if( ! item->action->isEnabled() )
-                    return false;
-                return QSortFilterProxyModel::filterAcceptsRow(source_row, \
                source_parent);
-            } break;
-            case ActionCollectionModelItem::CollectionType: {
-                if( ! item->collection->isEnabled() )
-                    return false;
-            } break;
-            default: break;
+
+    Action *action = ActionCollectionModel::action( index );
+    if ( action ) {
+        if( ! action->isEnabled() )
+            return false;
+        return QSortFilterProxyModel::filterAcceptsRow( source_row, source_parent );
     }
+    ActionCollection *collection = ActionCollectionModel::collection( index );
+    if( collection ) {
+        if ( ! collection->isEnabled() ) {
+            return false;
+        }
+    }
     return true;
 }
 
Index: ui/model.h
===================================================================
--- ui/model.h	(revision 886009)
+++ ui/model.h	(working copy)
@@ -30,11 +30,18 @@
     // Forward declarations.
     class Action;
     class ActionCollection;
+    class ActionCollectionModelItem;
 
     /**
      * The ActionCollectionModel class implements a QAbstractItemModel to provide
      * a model for views of a \a ActionCollection instance that manages a
      * collection of \a Action instances.
+     *
+     * Important implementation detatils:
+     * \li An action can not have children.
+     * \li A collection can have both collections and actions as children.
+     * \li This model lists actions before collections.
+     * \li The internalPointer() of QModelIndex is used to hold a pointer to the \
                parent collection.
      */
     class KROSSUI_EXPORT ActionCollectionModel : public QAbstractItemModel
     {
@@ -71,6 +78,11 @@
 
             virtual Qt::DropActions supportedDropActions() const;
 
+            QModelIndex indexForCollection( ActionCollection *collection ) const;
+            QModelIndex indexForAction( Action *action ) const;
+            /// Return the root collection
+            ActionCollection *rootCollection() const;
+
             /**
             * \return the \a Action instance the as argument passed QModelIndex
             * represents or NULL if the QModelIndex is not a \a Action .
@@ -83,9 +95,25 @@
             */
             static ActionCollection* collection(const QModelIndex& index);
 
+        protected:
+            /// @returns the row number of the @p collection
+            int rowNumber( ActionCollection *collection ) const;
+
         private Q_SLOTS:
             void slotUpdated();
 
+            void slotDataChanged( ActionCollection* );
+            void slotDataChanged( Action* );
+
+            void slotCollectionToBeInserted( ActionCollection* child, \
ActionCollection* parent ); +            void slotCollectionInserted( \
ActionCollection* child, ActionCollection* parent ); +            void \
slotCollectionToBeRemoved( ActionCollection* child, ActionCollection* parent ); +     \
void slotCollectionRemoved( ActionCollection* child, ActionCollection* parent ); +
+            void slotActionToBeInserted( Action* child, ActionCollection* parent );
+            void slotActionInserted( Action* child, ActionCollection* parent );
+            void slotActionToBeRemoved( Action* child, ActionCollection* parent );
+            void slotActionRemoved( Action* child, ActionCollection* parent );
         private:
             /// \internal d-pointer class.
             class Private;



>> Visit http://mail.kde.org/mailman/listinfo/kde-devel#unsub to unsubscribe <<


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic