xbeltree.cpp Example File

dombookmarks/xbeltree.cpp

  /****************************************************************************
  **
  ** Copyright (C) 2016 The Qt Company Ltd.
  ** Contact: https://www.qt.io/licensing/
  **
  ** This file is part of the examples of the Qt Toolkit.
  **
  ** $QT_BEGIN_LICENSE:BSD$
  ** Commercial License Usage
  ** Licensees holding valid commercial Qt licenses may use this file in
  ** accordance with the commercial license agreement provided with the
  ** Software or, alternatively, in accordance with the terms contained in
  ** a written agreement between you and The Qt Company. For licensing terms
  ** and conditions see https://www.qt.io/terms-conditions. For further
  ** information use the contact form at https://www.qt.io/contact-us.
  **
  ** BSD License Usage
  ** Alternatively, you may use this file under the terms of the BSD license
  ** as follows:
  **
  ** "Redistribution and use in source and binary forms, with or without
  ** modification, are permitted provided that the following conditions are
  ** met:
  **   * Redistributions of source code must retain the above copyright
  **     notice, this list of conditions and the following disclaimer.
  **   * Redistributions in binary form must reproduce the above copyright
  **     notice, this list of conditions and the following disclaimer in
  **     the documentation and/or other materials provided with the
  **     distribution.
  **   * Neither the name of The Qt Company Ltd nor the names of its
  **     contributors may be used to endorse or promote products derived
  **     from this software without specific prior written permission.
  **
  **
  ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  **
  ** $QT_END_LICENSE$
  **
  ****************************************************************************/

  #include <QtWidgets>

  #include "xbeltree.h"

  XbelTree::XbelTree(QWidget *parent)
      : QTreeWidget(parent)
  {
      QStringList labels;
      labels << tr("Title") << tr("Location");

      header()->setSectionResizeMode(QHeaderView::Stretch);
      setHeaderLabels(labels);

      folderIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirClosedIcon),
                           QIcon::Normal, QIcon::Off);
      folderIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirOpenIcon),
                           QIcon::Normal, QIcon::On);
      bookmarkIcon.addPixmap(style()->standardPixmap(QStyle::SP_FileIcon));
  }

  bool XbelTree::read(QIODevice *device)
  {
      QString errorStr;
      int errorLine;
      int errorColumn;

      if (!domDocument.setContent(device, true, &errorStr, &errorLine,
                                  &errorColumn)) {
          QMessageBox::information(window(), tr("DOM Bookmarks"),
                                   tr("Parse error at line %1, column %2:\n%3")
                                   .arg(errorLine)
                                   .arg(errorColumn)
                                   .arg(errorStr));
          return false;
      }

      QDomElement root = domDocument.documentElement();
      if (root.tagName() != "xbel") {
          QMessageBox::information(window(), tr("DOM Bookmarks"),
                                   tr("The file is not an XBEL file."));
          return false;
      } else if (root.hasAttribute("version")
                 && root.attribute("version") != "1.0") {
          QMessageBox::information(window(), tr("DOM Bookmarks"),
                                   tr("The file is not an XBEL version 1.0 "
                                      "file."));
          return false;
      }

      clear();

      disconnect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
                 this, SLOT(updateDomElement(QTreeWidgetItem*,int)));

      QDomElement child = root.firstChildElement("folder");
      while (!child.isNull()) {
          parseFolderElement(child);
          child = child.nextSiblingElement("folder");
      }

      connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
              this, SLOT(updateDomElement(QTreeWidgetItem*,int)));

      return true;
  }

  bool XbelTree::write(QIODevice *device)
  {
      const int IndentSize = 4;

      QTextStream out(device);
      domDocument.save(out, IndentSize);
      return true;
  }

  void XbelTree::updateDomElement(QTreeWidgetItem *item, int column)
  {
      QDomElement element = domElementForItem.value(item);
      if (!element.isNull()) {
          if (column == 0) {
              QDomElement oldTitleElement = element.firstChildElement("title");
              QDomElement newTitleElement = domDocument.createElement("title");

              QDomText newTitleText = domDocument.createTextNode(item->text(0));
              newTitleElement.appendChild(newTitleText);

              element.replaceChild(newTitleElement, oldTitleElement);
          } else {
              if (element.tagName() == "bookmark")
                  element.setAttribute("href", item->text(1));
          }
      }
  }

  void XbelTree::parseFolderElement(const QDomElement &element,
                                    QTreeWidgetItem *parentItem)
  {
      QTreeWidgetItem *item = createItem(element, parentItem);

      QString title = element.firstChildElement("title").text();
      if (title.isEmpty())
          title = QObject::tr("Folder");

      item->setFlags(item->flags() | Qt::ItemIsEditable);
      item->setIcon(0, folderIcon);
      item->setText(0, title);

      bool folded = (element.attribute("folded") != "no");
      setItemExpanded(item, !folded);

      QDomElement child = element.firstChildElement();
      while (!child.isNull()) {
          if (child.tagName() == "folder") {
              parseFolderElement(child, item);
          } else if (child.tagName() == "bookmark") {
              QTreeWidgetItem *childItem = createItem(child, item);

              QString title = child.firstChildElement("title").text();
              if (title.isEmpty())
                  title = QObject::tr("Folder");

              childItem->setFlags(item->flags() | Qt::ItemIsEditable);
              childItem->setIcon(0, bookmarkIcon);
              childItem->setText(0, title);
              childItem->setText(1, child.attribute("href"));
          } else if (child.tagName() == "separator") {
              QTreeWidgetItem *childItem = createItem(child, item);
              childItem->setFlags(item->flags() & ~(Qt::ItemIsSelectable | Qt::ItemIsEditable));
              childItem->setText(0, QString(30, 0xB7));
          }
          child = child.nextSiblingElement();
      }
  }

  QTreeWidgetItem *XbelTree::createItem(const QDomElement &element,
                                        QTreeWidgetItem *parentItem)
  {
      QTreeWidgetItem *item;
      if (parentItem) {
          item = new QTreeWidgetItem(parentItem);
      } else {
          item = new QTreeWidgetItem(this);
      }
      domElementForItem.insert(item, element);
      return item;
  }