Hello,

I'm trying to write a small app for displaying the hierarchical structure
of an xml file using the model/view framework.

To do this, I have created a XmlTreeModel class inherited from
QAbstractItemModel to hold the hierarchical model and a QTreeView to
display it. I have also defined a XmlTreeItem class to handle each single
xml element.
Parsing file and building model is achieved in populate(), parseBranch()
and createItem() functions. For each XmlTreeItem instance, the
corresponding QModelIndex.internalId is the reference identifier. This
Long value is stored into the XmlTreeItem instance itself and also into a
HashMap<Long, XmlTreeItem>. This unique identifier for each XmlTreeItem
instance is used to retrieve data once the model completely built,
especially in the QAbstractModelItem data() function.

Here is the model class code (quite long, sorry) :

public class XmlTreeModel extends QAbstractItemModel {
        private class XmlTreeItem{
                private Long id = null; // QModelIndex internal value ; null if 
not set
                private String name; // xml tag label
                private XmlTreeItem parentItem; // null for root item
                private List<XmlTreeItem> childItems = new 
ArrayList<XmlTreeItem>();

                public XmlTreeItem(String name, XmlTreeItem parent){
                        parentItem = parent;
                        this.name = name;
                        childItems.clear();
                }

                public void appendChild(XmlTreeItem item) {
                        childItems.add(item);
                }

                public XmlTreeItem child(int row) {
                        return childItems.get(row);
                }

                public int childCount() {
                        return childItems.size();
                }

                public int row() {
                        if (parentItem != null)
                                return parentItem.childItems.indexOf(this);

                        return 0;
                }
        }

        private QDomDocument domDocument = new QDomDocument();
        private HashMap<Long, XmlTreeItem> indexes = new HashMap<Long,
XmlTreeItem>();
        private XmlTreeItem rootItem;
        private int nextId = 1;

        public XmlTreeModel(){
                super();
                indexes.clear();
        }

        public boolean populate(QIODevice device) {
                QDomDocument.Result res = domDocument.setContent(device, true);
                if (!res.success) {
                        return false;
                }

                QDomElement rootElement = domDocument.documentElement();
                rootItem = createItem(rootElement, null);

                parseBranch(rootElement, rootItem);

                return true;
        }

        private void parseBranch(QDomElement parentElement, XmlTreeItem 
parentItem){
                QDomElement element = parentElement.firstChildElement();
                while(!element.isNull()){
                        XmlTreeItem item = createItem(element, parentItem);
                        parentItem.appendChild(item);
                        if (!element.firstChildElement().isNull())
                                parseBranch(element, item);
                        element = element.nextSiblingElement();
                }
        }

        private XmlTreeItem createItem(QDomElement element, XmlTreeItem 
parentItem){
                XmlTreeItem item;
                if(parentItem == null)
                        item = new XmlTreeItem(element.tagName(), null);
                else
                        item = new XmlTreeItem(element.tagName(), parentItem);

                QModelIndex index = this.createIndex(item.childCount(), 0, 
nextId);
                indexes.put(index.internalId(), item);
                nextId++;

                item.id = index.internalId();

                return item;
        }

        private QModelIndex getIndex(XmlTreeItem item){
                if(item == null)
                        return null;
                QModelIndex index = this.createIndex(item.row(), 0, 
item.id.intValue());
                return index;
        }

        private XmlTreeItem getItem(QModelIndex index){
                if (index == null)
                        return rootItem;
                return indexes.get(index.internalId());
        }


        @Override
        public int columnCount(QModelIndex parent) {
                return 1;
        }

        @Override
        public Object data(QModelIndex index, int role) {
                if (role == Qt.ItemDataRole.DisplayRole){
                        return indexes.get(index.internalId()).name;
                }
                return null;
        }

        @Override
        public QModelIndex index(int row, int column, QModelIndex parent) {
                if (parent == null)
                        return getIndex(rootItem);

                XmlTreeItem item = getItem(parent).child(row);

                return this.createIndex(item.row(), 0, item.id.intValue());
        }

        @Override
        public QModelIndex parent(QModelIndex child) {
                if(child == null)
                        return null;
                XmlTreeItem item = getItem(child).parentItem;
                return getIndex(item);
        }

        @Override
        public int rowCount(QModelIndex parent) {
                XmlTreeItem item = getItem(parent);
                return item.childItems.size();
        }
}

and here is the main/view class code:

public class XmlTreeView extends QWidget {

        public static void main(String[] args) {
                QApplication.initialize(args);
                new XmlTreeView();
                QApplication.exec();
        }

        public XmlTreeView() {
                QTreeView view = new QTreeView();
                String fileName = QFileDialog
                                .getOpenFileName(view, "Open XML file", 
QDir.currentPath(),
                                                new QFileDialog.Filter("XML 
Files (*.xml)"));
                if (!fileName.isEmpty()) {
                        XmlTreeModel model = new XmlTreeModel();
                        model.populate(new QFile(fileName));
                        view.header().hide();
                        view.setWindowTitle("XMLTreeView: "+fileName);
                        view.setModel(model);
                        view.expandAll();
                        view.show();
                }
        }
}


It works fine excepts when the root tag of my xml file has several
children i.e. the following file is correctly parsed and displayed:

<?xml version="1.0"?>
<root>
  <level1><!--only one level1 child-->
    <level2>
      <level3>
        <level4>
          <level5>100</level5>
        </level4>
      </level3>
      <level3>
        <level4>
          <level5>200</level5>
        </level4>
      </level3>
    </level2>
  </level1>
</root>

..altought this one is not:

<?xml version="1.0"?>
<root>
  <level1><!--first level1 child-->
    <level2>
      <level3>
        <level4>
          <level5>100</level5>
        </level4>
      </level3>
      <level3>
        <level4>
          <level5>200</level5>
        </level4>
      </level3>
    </level2>
  </level1>
  <level1><!--second level1 child-->
     various data...
  </level1>
</root>

Here, the root tag appears twice (both at the root level), and the second
occurrence contains a "fake" hierarchy that is more or less the same as
the first one (some minor variations may appear on some files).
Furthermore selection on this "phantom" hierarchy may cause application
crash.

I can't figure out why this problem occurs only at the first level,
especially because the parseBranch() function is recursive.

Any hint would really be very appreciated.

Thanks

jMax




_______________________________________________
Qt-jambi-interest mailing list
[email protected]
http://lists.trolltech.com/mailman/listinfo/qt-jambi-interest

Reply via email to