Xml, QAbstractItemModel, TreeView und undo/redo Framework

Alles rund um die Programmierung mit Qt
Antworten
unflexibel
Beiträge: 1
Registriert: 20. August 2010 11:37

Xml, QAbstractItemModel, TreeView und undo/redo Framework

Beitrag von unflexibel »

Hallo,

ich bin neu in Qt und dabei mich einzuarbeiten.

Ich will ein Programm schreiben, mit dem ich Adressen verwalten kann. Die Daten werden in Xml gespeichert:

Code: Alles auswählen

<?xml version="1.0" encoding="utf-8"?>
   <addressbook>
      <contacts>
         <contact id="Jimmy_Page">
            <name>Jimmy Page</name>
            <city>Heston</city>
            <country>United Kingdom</country>
            <email id="webmail">jimmy.page@ledzeppelin.com</email>
         </contact>
         <contact id="Serj_Tankian">
            <name>Serj Tankian</name>
            <city>Beirut</city>
            <country>Libanon</country>
            <email id="webmail">serj.tankian@soad.com</email>
         </contact>
      </contacts>
   </addressbook>
Es gibt die folgenden Voraussetzungen:
- Xml
- QTreeView
- eigenes Model (QAbstractItemModel)
- undo/redo Framework

Basis meiner Implementierung ist das Qt-Beispiel simpledommodel.

XmlModel : QAbstractItemModel
XmlItem

XmlTreeEditCommand : QCommand
XmlTreeNewCommand : QCommand
XmlTreeRemoveCommand : QCommand

XmlTreeView : QTreeView (für ContextMenu)

Ich habe so weit alles implementiert, das Editieren und Hinzufügen von Einträgen funktioniert. Lediglich das Löschen von Einträgen funktioniert nicht so wie erhofft. Wenn ich ein Element zum Entfernen auswähle, wird immer der letzte <contact> Node innerhalb <contacts> entfernt. Wenn ich dann aber mein Model speichere und die Xml-Datei öffne, wurde das richtige Element entfernt.

Hier mal die - meiner Ansicht nach - wichtigsten Funktionen:

Code: Alles auswählen

bool XmlModel::removeRows(int position, int /*rows*/, const QModelIndex &index)
{
    XmlTreeRemoveCommand *command = new XmlTreeRemoveCommand(index, position, this);
    mUndoStack->push(command);

    return true;
}

void XmlModel::emitDataChanged(const QModelIndex &index)
{
    emit dataChanged(index, index);
}

XmlItem *XmlModel::getItem(const QModelIndex &index) const
{
    if (index.isValid())
    {
        XmlItem *item = static_cast<XmlItem*>(index.internalPointer());
        if (item)
        {
            return item;
        }
    }

    return mRootItem;
}

Code: Alles auswählen

class XmlTreeRemoveCommand : public QUndoCommand
{
public:
    XmlTreeRemoveCommand(const QModelIndex &index, int position, XmlModel *model);

    void undo();
    void redo();

private:
    QModelIndex mIndex;
    int mPosition;
    XmlModel *mXmlModel;
    QDomNode mOldNode;
};


void XmlTreeRemoveCommand::undo()
{
    QDomNode parent = mXmlModel->getItem(mIndex)->node();
    QModelIndex preNodeIndex = mXmlModel->index(mPosition - 1, 0, mIndex);
    QDomNode preNode = mXmlModel->getItem(preNodeIndex)->node();

    mXmlModel->beginInsertRows(mIndex, mPosition, mPosition);

    QString s = "insert " + mOldNode.toElement().attribute("id") +
                " after " + preNode.toElement().attribute("id");
    qDebug(s.toAscii());

    parent.insertAfter(mOldNode, preNode);

    mXmlModel->endInsertRows();
    mXmlModel->emitDataChanged(mIndex);
}


void XmlTreeRemoveCommand::redo()
{
    QDomNode parent = mXmlModel->getItem(mIndex)->node();
    QDomNode child = parent.childNodes().at(mPosition);

    mXmlModel->beginRemoveRows(mIndex, mPosition, mPosition);

    QDomNode removed = parent.removeChild(child);
    if (removed.isNull())
    {
        qDebug("could not remove node");
    }
    else
    {
        s = "removed node: " + removed.toElement().attribute("id");
        qDebug(s.toAscii());

        mOldNode = removed;
        mXmlModel->endRemoveRows();
        mXmlModel->emitDataChanged(mIndex);
    }
}
Bin für jeden Hinweis dankbar.

Vielen Dank schon mal

ach ja... im Anhang ist der gesamte Sourcecode
Dateianhänge
TestApplication.zip
(12.31 KiB) 169-mal heruntergeladen
Antworten