<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "searchresulttreemodel.h"
#include "searchresulttreeitems.h"
#include "searchresulttreeitemroles.h"

#include <QtGui/QApplication>
#include <QtGui/QFont>
#include <QtGui/QFontMetrics>
#include <QtGui/QColor>
#include <QtGui/QPalette>
#include <QtCore/QDir>
#include <QtCore/QDebug>

using namespace Find;
using namespace Find::Internal;

SearchResultTreeModel::SearchResultTreeModel(QObject *parent)
    : QAbstractItemModel(parent)
    , m_lastAddedResultFile(0)
    , m_showReplaceUI(false)
{
    m_rootItem = new SearchResultTreeItem;
    m_textEditorFont = QFont(QLatin1String("Courier"));
}

SearchResultTreeModel::~SearchResultTreeModel()
{
    delete m_rootItem;
}

void SearchResultTreeModel::setShowReplaceUI(bool show)
{
    m_showReplaceUI = show;
}

void SearchResultTreeModel::setTextEditorFont(const QFont &font)
{
    layoutAboutToBeChanged();
    m_textEditorFont = font;
    layoutChanged();
}

Qt::ItemFlags SearchResultTreeModel::flags(const QModelIndex &index) const
{
    Qt::ItemFlags flags = QAbstractItemModel::flags(index);

    if (index.isValid()) {
        if (const SearchResultTreeItem *item = static_cast<const SearchResultTreeItem*>(index.internalPointer())) {
            if (item->itemType() == SearchResultTreeItem::ResultRow && item->isUserCheckable()) {
                flags |= Qt::ItemIsUserCheckable;
            }
        }
    }

    return flags;
}

QModelIndex SearchResultTreeModel::index(int row, int column,
                                         const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    const SearchResultTreeItem *parentItem;

    if (!parent.isValid())
        parentItem = m_rootItem;
    else
        parentItem = static_cast<const SearchResultTreeItem*>(parent.internalPointer());

    const SearchResultTreeItem *childItem = parentItem->childAt(row);
    if (childItem)
        return createIndex(row, column, (void *)childItem);
    else
        return QModelIndex();
}

QModelIndex SearchResultTreeModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();

    const SearchResultTreeItem *childItem = static_cast<const SearchResultTreeItem*>(index.internalPointer());
    const SearchResultTreeItem *parentItem = childItem->parent();

    if (parentItem == m_rootItem)
        return QModelIndex();

    return createIndex(parentItem->rowOfItem(), 0, (void *)parentItem);
}

int SearchResultTreeModel::rowCount(const QModelIndex &parent) const
{
    if (parent.column() > 0)
        return 0;

    const SearchResultTreeItem *parentItem;

    if (!parent.isValid())
        parentItem = m_rootItem;
    else
        parentItem = static_cast<const SearchResultTreeItem*>(parent.internalPointer());

    return parentItem->childrenCount();
}

int SearchResultTreeModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return 1;
}

QVariant SearchResultTreeModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    const SearchResultTreeItem *item = static_cast<const SearchResultTreeItem*>(index.internalPointer());

    QVariant result;

    if (role == Qt::SizeHintRole)
    {
        const int appFontHeight = QApplication::fontMetrics().height();
        const int editorFontHeight = QFontMetrics(m_textEditorFont).height();
        result = QSize(0, qMax(appFontHeight, editorFontHeight));
    }
    else if (item->itemType() == SearchResultTreeItem::ResultRow)
    {
        const SearchResultTextRow *row = static_cast<const SearchResultTextRow *>(item);
        result = data(row, role);
    }
    else if (item->itemType() == SearchResultTreeItem::ResultFile)
    {
        const SearchResultFile *file = static_cast<const SearchResultFile *>(item);
        result = data(file, role);
    }

    return result;
}

bool SearchResultTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (role == Qt::CheckStateRole) {
        SearchResultTreeItem *item = static_cast<SearchResultTreeItem*>(index.internalPointer());
        SearchResultTextRow *row = static_cast<SearchResultTextRow *>(item);
        Qt::CheckState checkState = static_cast<Qt::CheckState>(value.toInt());
        row->setCheckState(checkState);
        return true;
    }
    return QAbstractItemModel::setData(index, value, role);
}

QVariant SearchResultTreeModel::data(const SearchResultTextRow *row, int role) const
{
    QVariant result;

    switch (role)
    {
    case Qt::CheckStateRole:
        if (row->isUserCheckable())
            result = row->checkState();
        break;
    case Qt::ToolTipRole:
        result = row->rowText().trimmed();
        break;
    case Qt::FontRole:
        result = m_textEditorFont;
        break;
    case ItemDataRoles::ResultLineRole:
    case Qt::DisplayRole:
        result = row->rowText();
        break;
    case ItemDataRoles::ResultIndexRole:
        result = row->index();
        break;
    case ItemDataRoles::ResultLineNumberRole:
        result = row->lineNumber();
        break;
    case ItemDataRoles::SearchTermStartRole:
        result = row->searchTermStart();
        break;
    case ItemDataRoles::SearchTermLengthRole:
        result = row->searchTermLength();
        break;
    case ItemDataRoles::TypeRole:
        result = QLatin1String("row");
        break;
    case ItemDataRoles::FileNameRole:
        {
            if (row->parent()->itemType() == SearchResultTreeItem::ResultFile) {
                const SearchResultFile *file = static_cast<const SearchResultFile *>(row->parent());
                result = file->fileName();
            }
            break;
        }
    default:
        result = QVariant();
        break;
    }

    return result;
}

QVariant SearchResultTreeModel::data(const SearchResultFile *file, int role) const
{
    switch (role)
    {
#if 0
    case Qt::CheckStateRole:
        if (file->isUserCheckable())
            return QVariant(file->checkState());
#endif
    case Qt::BackgroundRole: {
        const QColor baseColor = QApplication::palette().base().color();
        return QVariant(baseColor.darker(105));
        break;
    }
    case Qt::DisplayRole: {
        QString result = QDir::toNativeSeparators(file->fileName());
        result += QLatin1String(" (");
        result += QString::number(file->childrenCount());
        result +=  QLatin1Char(')');
        return QVariant(result);
    }
    case ItemDataRoles::FileNameRole:
    case Qt::ToolTipRole:
        return QVariant(QDir::toNativeSeparators(file->fileName()));
    case ItemDataRoles::ResultLinesCountRole:
        return QVariant(file->childrenCount());
    case ItemDataRoles::TypeRole:
        return QVariant(QLatin1String("file"));
    default:
        break;
    }
    return QVariant();
}

QVariant SearchResultTreeModel::headerData(int section, Qt::Orientation orientation,
                                           int role) const
{
    Q_UNUSED(section)
    Q_UNUSED(orientation)
    Q_UNUSED(role)
    return QVariant();
}

/**
 * Adds a file to the list of results and returns the index at which it was inserted.
 */
int SearchResultTreeModel::addResultFile(const QString &fileName)
{
#ifdef Q_OS_WIN
    if (fileName.contains(QLatin1Char('\\')))
        qWarning("SearchResultTreeModel::appendResultFile: File name with native separators added %s.\n", qPrintable(fileName));
#endif
    m_lastAddedResultFile = new SearchResultFile(fileName, m_rootItem);

    if (m_showReplaceUI) {
        m_lastAddedResultFile->setIsUserCheckable(true);
        m_lastAddedResultFile->setCheckState(Qt::Checked);
    }

    const int index = m_rootItem->insertionIndex(m_lastAddedResultFile);
    beginInsertRows(QModelIndex(), index, index);
    m_rootItem->insertChild(index, m_lastAddedResultFile);
    endInsertRows();
    return index;
}

void SearchResultTreeModel::appendResultLines(const QList<SearchResultItem> &items)
{
    if (!m_lastAddedResultFile)
        return;

    QModelIndex lastFile(createIndex(m_lastAddedResultFile->rowOfItem(), 0, m_lastAddedResultFile));

    beginInsertRows(lastFile, m_lastAddedResultFile->childrenCount(), m_lastAddedResultFile->childrenCount() + items.count());
    foreach (const SearchResultItem &item, items) {
        m_lastAddedResultFile->appendResultLine(item.index,
                                                item.lineNumber,
                                                item.lineText,
                                                item.searchTermStart,
                                                item.searchTermLength);
    }
    endInsertRows();

    dataChanged(lastFile, lastFile); // Make sure that the number after the file name gets updated
}

/**
 * Adds the search result to the list of results, creating a new file entry when
 * necessary. Returns the insertion index when a new file entry was created.
 */
QList<int> SearchResultTreeModel::addResultLines(const QList<SearchResultItem> &items)
{
    QList<int> insertedFileIndices;
    QList<SearchResultItem> itemSet;
    foreach (const SearchResultItem &item, items) {
        if (!m_lastAddedResultFile || (m_lastAddedResultFile->fileName() != item.fileName)) {
            if (!itemSet.isEmpty()) {
                appendResultLines(itemSet);
                itemSet.clear();
            }
            insertedFileIndices << addResultFile(item.fileName);
        }
        itemSet << item;
    }
    if (!itemSet.isEmpty()) {
        appendResultLines(itemSet);
        itemSet.clear();
    }
    return insertedFileIndices;
}

void SearchResultTreeModel::clear()
{
    m_lastAddedResultFile = NULL;
    m_rootItem->clearChildren();
    reset();
}

QModelIndex SearchResultTreeModel::next(const QModelIndex &idx) const
{
    QModelIndex parent = idx.parent();
    if (parent.isValid()) {
        int row = idx.row();
        if (row + 1 < rowCount(parent)) {
            // Same parent
            return index(row + 1, 0, parent);
        } else {
            // Next parent
            int parentRow = parent.row();
            QModelIndex nextParent;
            if (parentRow + 1 < rowCount()) {
                nextParent = index(parentRow + 1, 0);
            } else {
                // Wrap around
                nextParent = index(0,0);
            }
            return nextParent.child(0, 0);
        }
    } else {
        // We are on a top level item
        return idx.child(0,0);
    }
    return QModelIndex();
}

QModelIndex SearchResultTreeModel::prev(const QModelIndex &idx) const
{
    QModelIndex parent = idx.parent();
    if (parent.isValid()) {
        int row = idx.row();
        if (row  > 0) {
            // Same parent
            return index(row - 1, 0, parent);
        } else {
            // Prev parent
            int parentRow = parent.row();
            QModelIndex prevParent;
            if (parentRow > 0 ) {
                prevParent = index(parentRow - 1, 0);
            } else {
                // Wrap around
                prevParent = index(rowCount() - 1, 0);
            }
            return prevParent.child(rowCount(prevParent) - 1, 0);
        }
    } else {
        // We are on a top level item
        int row = idx.row();
        if (row > 0) {
            QModelIndex prevParent = index(row - 1, 0);
            return prevParent.child(rowCount(prevParent) ,0);
        }
    }
    return QModelIndex();
}
<commit_msg>Change a QString concatenation.<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "searchresulttreemodel.h"
#include "searchresulttreeitems.h"
#include "searchresulttreeitemroles.h"

#include <QtGui/QApplication>
#include <QtGui/QFont>
#include <QtGui/QFontMetrics>
#include <QtGui/QColor>
#include <QtGui/QPalette>
#include <QtCore/QDir>
#include <QtCore/QDebug>

using namespace Find;
using namespace Find::Internal;

SearchResultTreeModel::SearchResultTreeModel(QObject *parent)
    : QAbstractItemModel(parent)
    , m_lastAddedResultFile(0)
    , m_showReplaceUI(false)
{
    m_rootItem = new SearchResultTreeItem;
    m_textEditorFont = QFont(QLatin1String("Courier"));
}

SearchResultTreeModel::~SearchResultTreeModel()
{
    delete m_rootItem;
}

void SearchResultTreeModel::setShowReplaceUI(bool show)
{
    m_showReplaceUI = show;
}

void SearchResultTreeModel::setTextEditorFont(const QFont &font)
{
    layoutAboutToBeChanged();
    m_textEditorFont = font;
    layoutChanged();
}

Qt::ItemFlags SearchResultTreeModel::flags(const QModelIndex &index) const
{
    Qt::ItemFlags flags = QAbstractItemModel::flags(index);

    if (index.isValid()) {
        if (const SearchResultTreeItem *item = static_cast<const SearchResultTreeItem*>(index.internalPointer())) {
            if (item->itemType() == SearchResultTreeItem::ResultRow && item->isUserCheckable()) {
                flags |= Qt::ItemIsUserCheckable;
            }
        }
    }

    return flags;
}

QModelIndex SearchResultTreeModel::index(int row, int column,
                                         const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    const SearchResultTreeItem *parentItem;

    if (!parent.isValid())
        parentItem = m_rootItem;
    else
        parentItem = static_cast<const SearchResultTreeItem*>(parent.internalPointer());

    const SearchResultTreeItem *childItem = parentItem->childAt(row);
    if (childItem)
        return createIndex(row, column, (void *)childItem);
    else
        return QModelIndex();
}

QModelIndex SearchResultTreeModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();

    const SearchResultTreeItem *childItem = static_cast<const SearchResultTreeItem*>(index.internalPointer());
    const SearchResultTreeItem *parentItem = childItem->parent();

    if (parentItem == m_rootItem)
        return QModelIndex();

    return createIndex(parentItem->rowOfItem(), 0, (void *)parentItem);
}

int SearchResultTreeModel::rowCount(const QModelIndex &parent) const
{
    if (parent.column() > 0)
        return 0;

    const SearchResultTreeItem *parentItem;

    if (!parent.isValid())
        parentItem = m_rootItem;
    else
        parentItem = static_cast<const SearchResultTreeItem*>(parent.internalPointer());

    return parentItem->childrenCount();
}

int SearchResultTreeModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return 1;
}

QVariant SearchResultTreeModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    const SearchResultTreeItem *item = static_cast<const SearchResultTreeItem*>(index.internalPointer());

    QVariant result;

    if (role == Qt::SizeHintRole)
    {
        const int appFontHeight = QApplication::fontMetrics().height();
        const int editorFontHeight = QFontMetrics(m_textEditorFont).height();
        result = QSize(0, qMax(appFontHeight, editorFontHeight));
    }
    else if (item->itemType() == SearchResultTreeItem::ResultRow)
    {
        const SearchResultTextRow *row = static_cast<const SearchResultTextRow *>(item);
        result = data(row, role);
    }
    else if (item->itemType() == SearchResultTreeItem::ResultFile)
    {
        const SearchResultFile *file = static_cast<const SearchResultFile *>(item);
        result = data(file, role);
    }

    return result;
}

bool SearchResultTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (role == Qt::CheckStateRole) {
        SearchResultTreeItem *item = static_cast<SearchResultTreeItem*>(index.internalPointer());
        SearchResultTextRow *row = static_cast<SearchResultTextRow *>(item);
        Qt::CheckState checkState = static_cast<Qt::CheckState>(value.toInt());
        row->setCheckState(checkState);
        return true;
    }
    return QAbstractItemModel::setData(index, value, role);
}

QVariant SearchResultTreeModel::data(const SearchResultTextRow *row, int role) const
{
    QVariant result;

    switch (role)
    {
    case Qt::CheckStateRole:
        if (row->isUserCheckable())
            result = row->checkState();
        break;
    case Qt::ToolTipRole:
        result = row->rowText().trimmed();
        break;
    case Qt::FontRole:
        result = m_textEditorFont;
        break;
    case ItemDataRoles::ResultLineRole:
    case Qt::DisplayRole:
        result = row->rowText();
        break;
    case ItemDataRoles::ResultIndexRole:
        result = row->index();
        break;
    case ItemDataRoles::ResultLineNumberRole:
        result = row->lineNumber();
        break;
    case ItemDataRoles::SearchTermStartRole:
        result = row->searchTermStart();
        break;
    case ItemDataRoles::SearchTermLengthRole:
        result = row->searchTermLength();
        break;
    case ItemDataRoles::TypeRole:
        result = QLatin1String("row");
        break;
    case ItemDataRoles::FileNameRole:
        {
            if (row->parent()->itemType() == SearchResultTreeItem::ResultFile) {
                const SearchResultFile *file = static_cast<const SearchResultFile *>(row->parent());
                result = file->fileName();
            }
            break;
        }
    default:
        result = QVariant();
        break;
    }

    return result;
}

QVariant SearchResultTreeModel::data(const SearchResultFile *file, int role) const
{
    switch (role)
    {
#if 0
    case Qt::CheckStateRole:
        if (file->isUserCheckable())
            return QVariant(file->checkState());
#endif
    case Qt::BackgroundRole: {
        const QColor baseColor = QApplication::palette().base().color();
        return QVariant(baseColor.darker(105));
        break;
    }
    case Qt::DisplayRole: {
        const QString result =
                QDir::toNativeSeparators(file->fileName())
                + QString::fromLatin1(" (")
                + QString::number(file->childrenCount())
                + QLatin1Char(')');
        return QVariant(result);
    }
    case ItemDataRoles::FileNameRole:
    case Qt::ToolTipRole:
        return QVariant(QDir::toNativeSeparators(file->fileName()));
    case ItemDataRoles::ResultLinesCountRole:
        return QVariant(file->childrenCount());
    case ItemDataRoles::TypeRole:
        return QVariant(QLatin1String("file"));
    default:
        break;
    }
    return QVariant();
}

QVariant SearchResultTreeModel::headerData(int section, Qt::Orientation orientation,
                                           int role) const
{
    Q_UNUSED(section)
    Q_UNUSED(orientation)
    Q_UNUSED(role)
    return QVariant();
}

/**
 * Adds a file to the list of results and returns the index at which it was inserted.
 */
int SearchResultTreeModel::addResultFile(const QString &fileName)
{
#ifdef Q_OS_WIN
    if (fileName.contains(QLatin1Char('\\')))
        qWarning("SearchResultTreeModel::appendResultFile: File name with native separators added %s.\n", qPrintable(fileName));
#endif
    m_lastAddedResultFile = new SearchResultFile(fileName, m_rootItem);

    if (m_showReplaceUI) {
        m_lastAddedResultFile->setIsUserCheckable(true);
        m_lastAddedResultFile->setCheckState(Qt::Checked);
    }

    const int index = m_rootItem->insertionIndex(m_lastAddedResultFile);
    beginInsertRows(QModelIndex(), index, index);
    m_rootItem->insertChild(index, m_lastAddedResultFile);
    endInsertRows();
    return index;
}

void SearchResultTreeModel::appendResultLines(const QList<SearchResultItem> &items)
{
    if (!m_lastAddedResultFile)
        return;

    QModelIndex lastFile(createIndex(m_lastAddedResultFile->rowOfItem(), 0, m_lastAddedResultFile));

    beginInsertRows(lastFile, m_lastAddedResultFile->childrenCount(), m_lastAddedResultFile->childrenCount() + items.count());
    foreach (const SearchResultItem &item, items) {
        m_lastAddedResultFile->appendResultLine(item.index,
                                                item.lineNumber,
                                                item.lineText,
                                                item.searchTermStart,
                                                item.searchTermLength);
    }
    endInsertRows();

    dataChanged(lastFile, lastFile); // Make sure that the number after the file name gets updated
}

/**
 * Adds the search result to the list of results, creating a new file entry when
 * necessary. Returns the insertion index when a new file entry was created.
 */
QList<int> SearchResultTreeModel::addResultLines(const QList<SearchResultItem> &items)
{
    QList<int> insertedFileIndices;
    QList<SearchResultItem> itemSet;
    foreach (const SearchResultItem &item, items) {
        if (!m_lastAddedResultFile || (m_lastAddedResultFile->fileName() != item.fileName)) {
            if (!itemSet.isEmpty()) {
                appendResultLines(itemSet);
                itemSet.clear();
            }
            insertedFileIndices << addResultFile(item.fileName);
        }
        itemSet << item;
    }
    if (!itemSet.isEmpty()) {
        appendResultLines(itemSet);
        itemSet.clear();
    }
    return insertedFileIndices;
}

void SearchResultTreeModel::clear()
{
    m_lastAddedResultFile = NULL;
    m_rootItem->clearChildren();
    reset();
}

QModelIndex SearchResultTreeModel::next(const QModelIndex &idx) const
{
    QModelIndex parent = idx.parent();
    if (parent.isValid()) {
        int row = idx.row();
        if (row + 1 < rowCount(parent)) {
            // Same parent
            return index(row + 1, 0, parent);
        } else {
            // Next parent
            int parentRow = parent.row();
            QModelIndex nextParent;
            if (parentRow + 1 < rowCount()) {
                nextParent = index(parentRow + 1, 0);
            } else {
                // Wrap around
                nextParent = index(0,0);
            }
            return nextParent.child(0, 0);
        }
    } else {
        // We are on a top level item
        return idx.child(0,0);
    }
    return QModelIndex();
}

QModelIndex SearchResultTreeModel::prev(const QModelIndex &idx) const
{
    QModelIndex parent = idx.parent();
    if (parent.isValid()) {
        int row = idx.row();
        if (row  > 0) {
            // Same parent
            return index(row - 1, 0, parent);
        } else {
            // Prev parent
            int parentRow = parent.row();
            QModelIndex prevParent;
            if (parentRow > 0 ) {
                prevParent = index(parentRow - 1, 0);
            } else {
                // Wrap around
                prevParent = index(rowCount() - 1, 0);
            }
            return prevParent.child(rowCount(prevParent) - 1, 0);
        }
    } else {
        // We are on a top level item
        int row = idx.row();
        if (row > 0) {
            QModelIndex prevParent = index(row - 1, 0);
            return prevParent.child(rowCount(prevParent) ,0);
        }
    }
    return QModelIndex();
}
<|endoftext|>


<commit_before>#include "./constraint_updater.h"
#include <Eigen/Geometry>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <vector>
#include <cmath>
#include <utility>
#include <list>
BOOST_GEOMETRY_REGISTER_POINT_2D(Eigen::Vector2i, int, cs::cartesian, x(), y())
#include "./boost_polygon_concepts.h"

ConstraintUpdater::ConstraintUpdater(std::shared_ptr<Graphics::Drawer> drawer,
                                     int width, int height)
  : drawer(drawer), width(width), height(height)
{
}

polygon createBoxPolygon(Eigen::Vector2i center, Eigen::Vector2i size)
{
  polygon p;
  p.outer().push_back(
      Eigen::Vector2i(center.x() - size.x(), center.y() - size.y()));
  p.outer().push_back(
      Eigen::Vector2i(center.x() + size.x(), center.y() - size.y()));
  p.outer().push_back(
      Eigen::Vector2i(center.x() + size.x(), center.y() + size.y()));
  p.outer().push_back(
      Eigen::Vector2i(center.x() - size.x(), center.y() + size.y()));

  return p;
}

template <typename edge>
void ConstraintUpdater::convolveTwoSegements(polygon &polygon, const edge &a,
                                             const edge &b)
{
  auto p = a.first;
  boost::polygon::convolve(p, b.second);
  polygon.outer().push_back(Eigen::Vector2i(p.x(), p.y()));

  p = a.first;
  boost::polygon::convolve(p, b.first);
  polygon.outer().push_back(Eigen::Vector2i(p.x(), p.y()));

  p = a.second;
  boost::polygon::convolve(p, b.first);
  polygon.outer().push_back(Eigen::Vector2i(p.x(), p.y()));

  p = a.second;
  boost::polygon::convolve(p, b.second);
  polygon.outer().push_back(Eigen::Vector2i(p.x(), p.y()));
}

template <typename itrT1, typename itrT2>
void ConstraintUpdater::convolveTwoPointSequences(itrT1 ab, itrT1 ae, itrT2 bb,
                                                  itrT2 be)
{
  if (ab == ae || bb == be)
    return;

  polygon poly;
  auto prev_a = *ab;
  ++ab;
  for (; ab != ae; ++ab)
  {
    auto prev_b = *bb;
    itrT2 tmpb = bb;
    ++tmpb;
    for (; tmpb != be; ++tmpb)
    {
      convolveTwoSegements(poly, std::make_pair(prev_b, *tmpb),
                           std::make_pair(prev_a, *ab));
      prev_b = *tmpb;
    }
    prev_a = *ab;
  }

  polygon convexHull;
  boost::geometry::convex_hull(poly, convexHull);
  drawPolygon(convexHull.outer());
}

template <typename Polygon>
void ConstraintUpdater::convolveTwoPolygons(const Polygon &a, const Polygon &b)
{
  convolveTwoPointSequences(
      boost::polygon::begin_points(a), boost::polygon::end_points(a),
      boost::polygon::begin_points(b), boost::polygon::end_points(b));

  Polygon tmp_poly = a;
  addPolygonToPositions(
      boost::polygon::convolve(tmp_poly, *(boost::polygon::begin_points(b))));
  tmp_poly = b;
  addPolygonToPositions(
      boost::polygon::convolve(tmp_poly, *(boost::polygon::begin_points(a))));
}

bool hasSmallerAngle(float dir1X, float dir1Y, float dir2X, float dir2Y)
{
  float angle1 = std::atan2(dir1Y, dir1X);
  float angle2 = std::atan2(dir2Y, dir2X);

  return angle1 <= angle2;
}

template <typename Polygon>
void ConstraintUpdater::addPolygonToPositions(const Polygon &polygon)
{
  auto iteratorBegin = boost::polygon::begin_points(polygon);
  float referenceX = iteratorBegin->x();
  positions.push_back(referenceX);
  float referenceY = iteratorBegin->y();
  positions.push_back(height - referenceY);
  positions.push_back(referenceX);
  positions.push_back(height - referenceY);

  std::list<std::pair<float, float>> temp;
  for (auto iterator = ++iteratorBegin;
       iterator != boost::polygon::end_points(polygon); ++iterator)
  {
    float diffX = iterator->x() - referenceX;
    float diffY = iterator->y() - referenceY;
    auto inner = temp.begin();
    while (inner != temp.end() &&
           hasSmallerAngle(inner->first - referenceX,
                           inner->second - referenceY, diffX, diffY))
      ++inner;

    temp.insert(inner, 1, std::make_pair(iterator->x(), iterator->y()));
  }

  for (auto iterator = temp.cbegin(); iterator != temp.cend(); ++iterator)
  {
    positions.push_back(iterator->first);
    positions.push_back(height - iterator->second);
  }
}

void ConstraintUpdater::drawConstraintRegionFor(
    Eigen::Vector2i anchorPosition, Eigen::Vector2i labelSize,
    Eigen::Vector2i lastAnchorPosition, Eigen::Vector2i lastLabelPosition,
    Eigen::Vector2i lastLabelSize)
{
  int border = 2;
  polygon newLabel = createBoxPolygon(
      Eigen::Vector2i(0, 0), labelSize / 2 + Eigen::Vector2i(border, border));

  positions.clear();

  drawLabelShadowRegion(anchorPosition, lastLabelPosition, lastLabelSize,
                        newLabel);
  drawConnectorShadowRegion(anchorPosition, lastAnchorPosition,
                            lastLabelPosition, newLabel);

  drawer->drawElementVector(positions);
}

void ConstraintUpdater::clear()
{
  drawer->clear();
}

void ConstraintUpdater::useConnectorShadowRegion(bool enable)
{
  isConnectorShadowRegionEnabled = enable;
}

void ConstraintUpdater::drawLabelShadowRegion(Eigen::Vector2i anchorPosition,
                                              Eigen::Vector2i lastLabelPosition,
                                              Eigen::Vector2i lastLabelSize,
                                              const polygon &newLabel)
{
  polygon oldLabel = createBoxPolygon(lastLabelPosition, lastLabelSize / 2);

  polygon oldLabelExtruded(oldLabel);
  for (auto point : oldLabel.outer())
  {
    Eigen::Vector2i p = anchorPosition + 1000 * (point - anchorPosition);
    oldLabelExtruded.outer().push_back(p);
  }

  polygon oldLabelExtrudedConvexHull;
  boost::geometry::convex_hull(oldLabelExtruded, oldLabelExtrudedConvexHull);

  convolveTwoPolygons(oldLabelExtrudedConvexHull, newLabel);
}

void ConstraintUpdater::drawConnectorShadowRegion(
    Eigen::Vector2i anchorPosition, Eigen::Vector2i lastAnchorPosition,
    Eigen::Vector2i lastLabelPosition, const polygon &newLabel)
{
  if (!isConnectorShadowRegionEnabled)
    return;

  polygon connectorPolygon;
  Eigen::Vector2i throughLastAnchor =
      anchorPosition + 1000 * (lastAnchorPosition - anchorPosition);
  Eigen::Vector2i throughLastLabel =
      anchorPosition + 1000 * (lastLabelPosition - anchorPosition);

  connectorPolygon.outer().push_back(lastAnchorPosition);
  connectorPolygon.outer().push_back(throughLastAnchor);
  connectorPolygon.outer().push_back(throughLastLabel);
  connectorPolygon.outer().push_back(lastLabelPosition);

  convolveTwoPolygons(connectorPolygon, newLabel);
}

template <class T> void ConstraintUpdater::drawPolygon(std::vector<T> polygon)
{
  if (polygon.size() > 0)
  {
    auto point = polygon[0];
    positions.push_back(point.x());
    positions.push_back(height - point.y());
  }
  for (auto point : polygon)
  {
    positions.push_back(point.x());
    positions.push_back(height - point.y());
  }
}

<commit_msg>Output timing of calculations in ConstraintUpdater.<commit_after>#include "./constraint_updater.h"
#include <QLoggingCategory>
#include <Eigen/Geometry>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <vector>
#include <chrono>
#include <cmath>
#include <utility>
#include <list>
BOOST_GEOMETRY_REGISTER_POINT_2D(Eigen::Vector2i, int, cs::cartesian, x(), y())
#include "./boost_polygon_concepts.h"

QLoggingCategory cuChan("Placement.ConstraintUpdater");

ConstraintUpdater::ConstraintUpdater(std::shared_ptr<Graphics::Drawer> drawer,
                                     int width, int height)
  : drawer(drawer), width(width), height(height)
{
}

polygon createBoxPolygon(Eigen::Vector2i center, Eigen::Vector2i size)
{
  polygon p;
  p.outer().push_back(
      Eigen::Vector2i(center.x() - size.x(), center.y() - size.y()));
  p.outer().push_back(
      Eigen::Vector2i(center.x() + size.x(), center.y() - size.y()));
  p.outer().push_back(
      Eigen::Vector2i(center.x() + size.x(), center.y() + size.y()));
  p.outer().push_back(
      Eigen::Vector2i(center.x() - size.x(), center.y() + size.y()));

  return p;
}

template <typename edge>
void ConstraintUpdater::convolveTwoSegements(polygon &polygon, const edge &a,
                                             const edge &b)
{
  auto p = a.first;
  boost::polygon::convolve(p, b.second);
  polygon.outer().push_back(Eigen::Vector2i(p.x(), p.y()));

  p = a.first;
  boost::polygon::convolve(p, b.first);
  polygon.outer().push_back(Eigen::Vector2i(p.x(), p.y()));

  p = a.second;
  boost::polygon::convolve(p, b.first);
  polygon.outer().push_back(Eigen::Vector2i(p.x(), p.y()));

  p = a.second;
  boost::polygon::convolve(p, b.second);
  polygon.outer().push_back(Eigen::Vector2i(p.x(), p.y()));
}

template <typename itrT1, typename itrT2>
void ConstraintUpdater::convolveTwoPointSequences(itrT1 ab, itrT1 ae, itrT2 bb,
                                                  itrT2 be)
{
  if (ab == ae || bb == be)
    return;

  polygon poly;
  auto prev_a = *ab;
  ++ab;
  for (; ab != ae; ++ab)
  {
    auto prev_b = *bb;
    itrT2 tmpb = bb;
    ++tmpb;
    for (; tmpb != be; ++tmpb)
    {
      convolveTwoSegements(poly, std::make_pair(prev_b, *tmpb),
                           std::make_pair(prev_a, *ab));
      prev_b = *tmpb;
    }
    prev_a = *ab;
  }

  polygon convexHull;
  boost::geometry::convex_hull(poly, convexHull);
  drawPolygon(convexHull.outer());
}

template <typename Polygon>
void ConstraintUpdater::convolveTwoPolygons(const Polygon &a, const Polygon &b)
{
  convolveTwoPointSequences(
      boost::polygon::begin_points(a), boost::polygon::end_points(a),
      boost::polygon::begin_points(b), boost::polygon::end_points(b));

  Polygon tmp_poly = a;
  addPolygonToPositions(
      boost::polygon::convolve(tmp_poly, *(boost::polygon::begin_points(b))));
  tmp_poly = b;
  addPolygonToPositions(
      boost::polygon::convolve(tmp_poly, *(boost::polygon::begin_points(a))));
}

bool hasSmallerAngle(float dir1X, float dir1Y, float dir2X, float dir2Y)
{
  float angle1 = std::atan2(dir1Y, dir1X);
  float angle2 = std::atan2(dir2Y, dir2X);

  return angle1 <= angle2;
}

template <typename Polygon>
void ConstraintUpdater::addPolygonToPositions(const Polygon &polygon)
{
  auto iteratorBegin = boost::polygon::begin_points(polygon);
  float referenceX = iteratorBegin->x();
  positions.push_back(referenceX);
  float referenceY = iteratorBegin->y();
  positions.push_back(height - referenceY);
  positions.push_back(referenceX);
  positions.push_back(height - referenceY);

  std::list<std::pair<float, float>> temp;
  for (auto iterator = ++iteratorBegin;
       iterator != boost::polygon::end_points(polygon); ++iterator)
  {
    float diffX = iterator->x() - referenceX;
    float diffY = iterator->y() - referenceY;
    auto inner = temp.begin();
    while (inner != temp.end() &&
           hasSmallerAngle(inner->first - referenceX,
                           inner->second - referenceY, diffX, diffY))
      ++inner;

    temp.insert(inner, 1, std::make_pair(iterator->x(), iterator->y()));
  }

  for (auto iterator = temp.cbegin(); iterator != temp.cend(); ++iterator)
  {
    positions.push_back(iterator->first);
    positions.push_back(height - iterator->second);
  }
}

void ConstraintUpdater::drawConstraintRegionFor(
    Eigen::Vector2i anchorPosition, Eigen::Vector2i labelSize,
    Eigen::Vector2i lastAnchorPosition, Eigen::Vector2i lastLabelPosition,
    Eigen::Vector2i lastLabelSize)
{
  auto startTime = std::chrono::high_resolution_clock::now();

  int border = 2;
  polygon newLabel = createBoxPolygon(
      Eigen::Vector2i(0, 0), labelSize / 2 + Eigen::Vector2i(border, border));

  positions.clear();

  drawLabelShadowRegion(anchorPosition, lastLabelPosition, lastLabelSize,
                        newLabel);
  drawConnectorShadowRegion(anchorPosition, lastAnchorPosition,
                            lastLabelPosition, newLabel);

  auto endTime = std::chrono::high_resolution_clock::now();
  std::chrono::duration<float, std::milli> diff = endTime - startTime;

  qCDebug(cuChan) << "drawConstraintRegionFor without drawing took"
                  << diff.count() << "ms";

  drawer->drawElementVector(positions);
}

void ConstraintUpdater::clear()
{
  drawer->clear();
}

void ConstraintUpdater::useConnectorShadowRegion(bool enable)
{
  isConnectorShadowRegionEnabled = enable;
}

void ConstraintUpdater::drawLabelShadowRegion(Eigen::Vector2i anchorPosition,
                                              Eigen::Vector2i lastLabelPosition,
                                              Eigen::Vector2i lastLabelSize,
                                              const polygon &newLabel)
{
  polygon oldLabel = createBoxPolygon(lastLabelPosition, lastLabelSize / 2);

  polygon oldLabelExtruded(oldLabel);
  for (auto point : oldLabel.outer())
  {
    Eigen::Vector2i p = anchorPosition + 1000 * (point - anchorPosition);
    oldLabelExtruded.outer().push_back(p);
  }

  polygon oldLabelExtrudedConvexHull;
  boost::geometry::convex_hull(oldLabelExtruded, oldLabelExtrudedConvexHull);

  convolveTwoPolygons(oldLabelExtrudedConvexHull, newLabel);
}

void ConstraintUpdater::drawConnectorShadowRegion(
    Eigen::Vector2i anchorPosition, Eigen::Vector2i lastAnchorPosition,
    Eigen::Vector2i lastLabelPosition, const polygon &newLabel)
{
  if (!isConnectorShadowRegionEnabled)
    return;

  polygon connectorPolygon;
  Eigen::Vector2i throughLastAnchor =
      anchorPosition + 1000 * (lastAnchorPosition - anchorPosition);
  Eigen::Vector2i throughLastLabel =
      anchorPosition + 1000 * (lastLabelPosition - anchorPosition);

  connectorPolygon.outer().push_back(lastAnchorPosition);
  connectorPolygon.outer().push_back(throughLastAnchor);
  connectorPolygon.outer().push_back(throughLastLabel);
  connectorPolygon.outer().push_back(lastLabelPosition);

  convolveTwoPolygons(connectorPolygon, newLabel);
}

template <class T> void ConstraintUpdater::drawPolygon(std::vector<T> polygon)
{
  if (polygon.size() > 0)
  {
    auto point = polygon[0];
    positions.push_back(point.x());
    positions.push_back(height - point.y());
  }
  for (auto point : polygon)
  {
    positions.push_back(point.x());
    positions.push_back(height - point.y());
  }
}

<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/

#include "qtkitinformation.h"

#include "qtkitconfigwidget.h"
#include "qtversionmanager.h"

#include <utils/environment.h>

namespace QtSupport {
namespace Internal {
const char QT_INFORMATION[] = "QtSupport.QtInformation";
} // namespace Internal

QtKitInformation::QtKitInformation()
{
    setObjectName(QLatin1String("QtKitInformation"));
    connect(QtVersionManager::instance(), SIGNAL(qtVersionsChanged(QList<int>,QList<int>,QList<int>)),
            this, SIGNAL(validationNeeded()));
}

Core::Id QtKitInformation::dataId() const
{
    static Core::Id id = Core::Id(Internal::QT_INFORMATION);
    return id;
}

unsigned int QtKitInformation::priority() const
{
    return 26000;
}

QVariant QtKitInformation::defaultValue(ProjectExplorer::Kit *k) const
{
    Q_UNUSED(k);
    QtVersionManager *mgr = QtVersionManager::instance();

    // find "Qt in PATH":
    Utils::Environment env = Utils::Environment::systemEnvironment();
    Utils::FileName qmake = Utils::FileName::fromString(env.searchInPath(QLatin1String("qmake")));

    if (qmake.isEmpty())
        return -1;

    QList<BaseQtVersion *> versionList = mgr->versions();
    foreach (BaseQtVersion *v, versionList) {
        if (qmake == v->qmakeCommand())
            return v->uniqueId();
    }

    return -1;
}

QList<ProjectExplorer::Task> QtKitInformation::validate(ProjectExplorer::Kit *k) const
{
    int id = qtVersionId(k);
    if (id == -1)
        return QList<ProjectExplorer::Task>();
    BaseQtVersion *version = QtVersionManager::instance()->version(id);
    if (!version) {
        setQtVersionId(k, -1);
        return QList<ProjectExplorer::Task>();
    }
    return version->validateKit(k);
}

ProjectExplorer::KitConfigWidget *QtKitInformation::createConfigWidget(ProjectExplorer::Kit *k) const
{
    return new Internal::QtKitConfigWidget(k);
}

QString QtKitInformation::displayNamePostfix(const ProjectExplorer::Kit *k) const
{
    BaseQtVersion *version = qtVersion(k);
    return version ? version->displayName() : QString();
}

ProjectExplorer::KitInformation::ItemList
QtKitInformation::toUserOutput(ProjectExplorer::Kit *k) const
{
    BaseQtVersion *version = qtVersion(k);
    return ItemList() << qMakePair(tr("Qt version"), version ? version->displayName() : tr("None"));
}

void QtKitInformation::addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const
{
    BaseQtVersion *version = qtVersion(k);
    if (version)
        version->addToEnvironment(k, env);
}

int QtKitInformation::qtVersionId(const ProjectExplorer::Kit *k)
{
    if (!k)
        return -1;
    bool ok = false;
    int id = k->value(Core::Id(Internal::QT_INFORMATION), -1).toInt(&ok);
    if (!ok)
        id = -1;
    return id;
}

void QtKitInformation::setQtVersionId(ProjectExplorer::Kit *k, const int id)
{
    k->setValue(Core::Id(Internal::QT_INFORMATION), id);
}

BaseQtVersion *QtKitInformation::qtVersion(const ProjectExplorer::Kit *k)
{
    return QtVersionManager::instance()->version(qtVersionId(k));
}

void QtKitInformation::setQtVersion(ProjectExplorer::Kit *k, const BaseQtVersion *v)
{
    if (!v)
        setQtVersionId(k, -1);
    else
        setQtVersionId(k, v->uniqueId());
}

QtPlatformKitMatcher::QtPlatformKitMatcher(const QString &platform) :
    m_platform(platform)
{ }

bool QtPlatformKitMatcher::matches(const ProjectExplorer::Kit *k) const
{
    BaseQtVersion *version = QtKitInformation::qtVersion(k);
    return version && version->platformName() == m_platform;
}

bool QtVersionKitMatcher::matches(const ProjectExplorer::Kit *k) const
{
    BaseQtVersion *version = QtKitInformation::qtVersion(k);
    if (!version)
        return false;
    QtVersionNumber current = version->qtVersion();
    if (m_min.majorVersion > -1 && current < m_min)
        return false;
    if (m_max.majorVersion > -1 && current > m_max)
        return false;
    return version->availableFeatures().contains(m_features);
}

} // namespace QtSupport
<commit_msg>Handle autodetection sources as identifiers for Qt versions<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/

#include "qtkitinformation.h"

#include "qtkitconfigwidget.h"
#include "qtversionmanager.h"

#include <utils/environment.h>

namespace QtSupport {
namespace Internal {
const char QT_INFORMATION[] = "QtSupport.QtInformation";
} // namespace Internal

QtKitInformation::QtKitInformation()
{
    setObjectName(QLatin1String("QtKitInformation"));
    connect(QtVersionManager::instance(), SIGNAL(qtVersionsChanged(QList<int>,QList<int>,QList<int>)),
            this, SIGNAL(validationNeeded()));
}

Core::Id QtKitInformation::dataId() const
{
    static Core::Id id = Core::Id(Internal::QT_INFORMATION);
    return id;
}

unsigned int QtKitInformation::priority() const
{
    return 26000;
}

QVariant QtKitInformation::defaultValue(ProjectExplorer::Kit *k) const
{
    Q_UNUSED(k);
    QtVersionManager *mgr = QtVersionManager::instance();

    // find "Qt in PATH":
    Utils::Environment env = Utils::Environment::systemEnvironment();
    Utils::FileName qmake = Utils::FileName::fromString(env.searchInPath(QLatin1String("qmake")));

    if (qmake.isEmpty())
        return -1;

    QList<BaseQtVersion *> versionList = mgr->versions();
    foreach (BaseQtVersion *v, versionList) {
        if (qmake == v->qmakeCommand())
            return v->uniqueId();
    }

    return -1;
}

QList<ProjectExplorer::Task> QtKitInformation::validate(ProjectExplorer::Kit *k) const
{
    int id = qtVersionId(k);
    if (id == -1)
        return QList<ProjectExplorer::Task>();
    BaseQtVersion *version = QtVersionManager::instance()->version(id);
    if (!version) {
        setQtVersionId(k, -1);
        return QList<ProjectExplorer::Task>();
    }
    return version->validateKit(k);
}

ProjectExplorer::KitConfigWidget *QtKitInformation::createConfigWidget(ProjectExplorer::Kit *k) const
{
    return new Internal::QtKitConfigWidget(k);
}

QString QtKitInformation::displayNamePostfix(const ProjectExplorer::Kit *k) const
{
    BaseQtVersion *version = qtVersion(k);
    return version ? version->displayName() : QString();
}

ProjectExplorer::KitInformation::ItemList
QtKitInformation::toUserOutput(ProjectExplorer::Kit *k) const
{
    BaseQtVersion *version = qtVersion(k);
    return ItemList() << qMakePair(tr("Qt version"), version ? version->displayName() : tr("None"));
}

void QtKitInformation::addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const
{
    BaseQtVersion *version = qtVersion(k);
    if (version)
        version->addToEnvironment(k, env);
}

int QtKitInformation::qtVersionId(const ProjectExplorer::Kit *k)
{
    if (!k)
        return -1;

    int id = -1;
    QVariant data = k->value(Core::Id(Internal::QT_INFORMATION), -1);
    if (data.type() == QVariant::Int) {
        bool ok;
        id = data.toInt(&ok);
        if (!ok)
            id = -1;
    } else {
        QString source = data.toString();
        foreach (BaseQtVersion *v, QtVersionManager::instance()->versions()) {
            if (v->autodetectionSource() != source)
                continue;
            id = v->uniqueId();
            break;
        }
    }
    return id;
}

void QtKitInformation::setQtVersionId(ProjectExplorer::Kit *k, const int id)
{
    k->setValue(Core::Id(Internal::QT_INFORMATION), id);
}

BaseQtVersion *QtKitInformation::qtVersion(const ProjectExplorer::Kit *k)
{
    return QtVersionManager::instance()->version(qtVersionId(k));
}

void QtKitInformation::setQtVersion(ProjectExplorer::Kit *k, const BaseQtVersion *v)
{
    if (!v)
        setQtVersionId(k, -1);
    else
        setQtVersionId(k, v->uniqueId());
}

QtPlatformKitMatcher::QtPlatformKitMatcher(const QString &platform) :
    m_platform(platform)
{ }

bool QtPlatformKitMatcher::matches(const ProjectExplorer::Kit *k) const
{
    BaseQtVersion *version = QtKitInformation::qtVersion(k);
    return version && version->platformName() == m_platform;
}

bool QtVersionKitMatcher::matches(const ProjectExplorer::Kit *k) const
{
    BaseQtVersion *version = QtKitInformation::qtVersion(k);
    if (!version)
        return false;
    QtVersionNumber current = version->qtVersion();
    if (m_min.majorVersion > -1 && current < m_min)
        return false;
    if (m_max.majorVersion > -1 && current > m_max)
        return false;
    return version->availableFeatures().contains(m_features);
}

} // namespace QtSupport
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/

#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgDB/Registry>

#include <iostream>
#include <sstream>
#include <fstream>
#include <iterator>

#include <zlib.h>

///////////////////////////////////////////////////////////////////////////////////////////////////
//
//  ReaderWriterGZ
//
class ReaderWriterGZ : public osgDB::ReaderWriter
{
    public:

        enum ObjectType
        {
            OBJECT,
            ARCHIVE,
            IMAGE,
            HEIGHTFIELD,
            NODE
        };

        ReaderWriterGZ();

        ~ReaderWriterGZ();

        virtual const char* className() const { return "HTTP Protocol Model Reader"; }

        virtual ReadResult openArchive(const std::string& fileName,ArchiveStatus status, unsigned int , const Options* options) const
        {
            if (status!=READ) return ReadResult(ReadResult::FILE_NOT_HANDLED);
            else return readFile(ARCHIVE,fileName,options);
        }

        virtual ReadResult readObject(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return readFile(OBJECT,fileName,options);
        }

        virtual ReadResult readImage(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return readFile(IMAGE,fileName,options);
        }

        virtual ReadResult readHeightField(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return readFile(HEIGHTFIELD,fileName,options);
        }

        virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return readFile(NODE,fileName,options);
        }

        ReadResult readFile(ObjectType objectType, osgDB::ReaderWriter* rw, std::istream& fin, const osgDB::ReaderWriter::Options* options) const;

        ReadResult readFile(ObjectType objectType, const std::string& fullFileName, const osgDB::ReaderWriter::Options* options) const;

        virtual WriteResult writeObject(const osg::Object& obj, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return writeFile(OBJECT, &obj, fileName, options);
        }

        virtual WriteResult writeImage(const osg::Image& image, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return writeFile(IMAGE, &image, fileName, options);
        }

        virtual WriteResult writeHeightField(const osg::HeightField& hf, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return writeFile(HEIGHTFIELD, &hf, fileName, options);
        }

        virtual WriteResult writeNode(const osg::Node& node, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return writeFile(NODE, &node, fileName,options);
        }

        WriteResult writeFile(ObjectType objectType, const osg::Object* object, osgDB::ReaderWriter* rw, std::ostream& fin, const osgDB::ReaderWriter::Options* options) const;

        WriteResult writeFile(ObjectType objectType, const osg::Object* object, const std::string& fullFileName, const osgDB::ReaderWriter::Options* options) const;

        bool read(std::istream& fin, std::string& destination) const;
        bool write(std::ostream& fout, const std::string& source) const;

};

ReaderWriterGZ::ReaderWriterGZ()
{
    // osg::notify(osg::NOTICE)<<"ReaderWriterGZ::ReaderWriterGZ()"<<std::endl;

    supportsExtension("osgz","Compressed .osg file extension.");
    supportsExtension("ivez","Compressed .ive file extension.");
    supportsExtension("gz","Compressed file extension.");
}

ReaderWriterGZ::~ReaderWriterGZ()
{
    // osg::notify(osg::NOTICE)<<"ReaderWriterGZ::~ReaderWriterGZ()"<<std::endl;
}

osgDB::ReaderWriter::ReadResult ReaderWriterGZ::readFile(ObjectType objectType, osgDB::ReaderWriter* rw, std::istream& fin, const osgDB::ReaderWriter::Options *options) const
{
    switch(objectType)
    {
        case(OBJECT): return rw->readObject(fin,options);
        case(ARCHIVE): return rw->openArchive(fin,options);
        case(IMAGE): return rw->readImage(fin,options);
        case(HEIGHTFIELD): return rw->readHeightField(fin,options);
        case(NODE): return rw->readNode(fin,options);
        default: break;
    }
    return ReadResult::FILE_NOT_HANDLED;
}

osgDB::ReaderWriter::ReadResult ReaderWriterGZ::readFile(ObjectType objectType, const std::string& fullFileName, const osgDB::ReaderWriter::Options *options) const
{
    std::string ext = osgDB::getLowerCaseFileExtension(fullFileName);
    if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

    if (osgDB::containsServerAddress(fullFileName)) return ReadResult::FILE_NOT_HANDLED;

    osgDB::ReaderWriter* rw = 0;

    if (osgDB::equalCaseInsensitive(ext,"osgz"))
    {
        rw = osgDB::Registry::instance()->getReaderWriterForExtension("osg");
        osg::notify(osg::INFO)<<"osgz ReaderWriter "<<rw<<std::endl;
    }
    else if (osgDB::equalCaseInsensitive(ext,"ivez"))
    {
        rw = osgDB::Registry::instance()->getReaderWriterForExtension("ive");
        osg::notify(osg::INFO)<<"ivez ReaderWriter "<<rw<<std::endl;
    }
    else
    {
        std::string baseFileName = osgDB::getNameLessExtension(fullFileName);
        std::string baseExt = osgDB::getLowerCaseFileExtension(baseFileName);
        rw = osgDB::Registry::instance()->getReaderWriterForExtension(baseExt);
        osg::notify(osg::INFO)<<baseExt<<" ReaderWriter "<<rw<<std::endl;
    }

    std::string fileName = osgDB::findDataFile( fullFileName, options );
    if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;

    // code for setting up the database path so that internally referenced file are searched for on relative paths.
    osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
    local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));

    std::ifstream fin(fileName.c_str());
    if (!fin) return ReadResult::ERROR_IN_READING_FILE;

    std::string dest;
    read(fin, dest);

    std::stringstream strstream(dest);

    return readFile(objectType, rw, strstream, local_opt.get());
}

osgDB::ReaderWriter::WriteResult ReaderWriterGZ::writeFile(ObjectType objectType, const osg::Object* object, osgDB::ReaderWriter* rw, std::ostream& fout, const osgDB::ReaderWriter::Options *options) const
{
    switch(objectType)
    {
        case(OBJECT): return rw->writeObject(*object, fout, options);
        case(IMAGE): return rw->writeImage(*(dynamic_cast<const osg::Image*>(object)), fout, options);
        case(HEIGHTFIELD): return rw->writeHeightField(*(dynamic_cast<const osg::HeightField*>(object)), fout, options);
        case(NODE): return rw->writeNode(*(dynamic_cast<const osg::Node*>(object)), fout,options);
        default: break;
    }
    return WriteResult::FILE_NOT_HANDLED;
}

osgDB::ReaderWriter::WriteResult ReaderWriterGZ::writeFile(ObjectType objectType, const osg::Object* object, const std::string& fullFileName, const osgDB::ReaderWriter::Options *options) const
{
    std::string ext = osgDB::getLowerCaseFileExtension(fullFileName);
    if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;

    osgDB::ReaderWriter* rw = 0;

    if (osgDB::equalCaseInsensitive(ext,"osgz"))
    {
        rw = osgDB::Registry::instance()->getReaderWriterForExtension("osg");
        osg::notify(osg::NOTICE)<<"osgz ReaderWriter "<<rw<<std::endl;
    }
    else if (osgDB::equalCaseInsensitive(ext,"ivez"))
    {
        rw = osgDB::Registry::instance()->getReaderWriterForExtension("ive");
        osg::notify(osg::NOTICE)<<"ivez ReaderWriter "<<rw<<std::endl;
    }
    else
    {
        std::string baseFileName = osgDB::getNameLessExtension(fullFileName);
        std::string baseExt = osgDB::getLowerCaseFileExtension(baseFileName);
        rw = osgDB::Registry::instance()->getReaderWriterForExtension(baseExt);
        osg::notify(osg::NOTICE)<<baseExt<<" ReaderWriter "<<rw<<std::endl;
    }

    std::stringstream strstream;
    osgDB::ReaderWriter::WriteResult writeResult = writeFile(objectType, object, rw, strstream, options);

    std::ofstream fout(fullFileName.c_str());

    write(fout,strstream.str());

    return writeResult;
}

#define CHUNK 16384

bool ReaderWriterGZ::read(std::istream& fin, std::string& destination) const
{
    int ret;
    unsigned have;
    z_stream strm;
    unsigned char in[CHUNK];
    unsigned char out[CHUNK];

    /* allocate inflate state */
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    strm.avail_in = 0;
    strm.next_in = Z_NULL;
    ret = inflateInit2(&strm,
                       15 + 32 // autodected zlib or gzip header
                       );
    if (ret != Z_OK)
        return false;

    /* decompress until deflate stream ends or end of file */
    do {

        strm.avail_in = fin.readsome((char*)in, CHUNK);

        if (fin.fail())
        {
            (void)inflateEnd(&strm);
            return false;
        }
        if (strm.avail_in == 0)
            break;
        strm.next_in = in;

        /* run inflate() on input until output buffer not full */
        do {
            strm.avail_out = CHUNK;
            strm.next_out = out;
            ret = inflate(&strm, Z_NO_FLUSH);

            switch (ret) {
            case Z_NEED_DICT:
            case Z_DATA_ERROR:
            case Z_MEM_ERROR:
                (void)inflateEnd(&strm);
                return false;
            }
            have = CHUNK - strm.avail_out;

            destination.append((char*)out, have);

        } while (strm.avail_out == 0);

        /* done when inflate() says it's done */
    } while (ret != Z_STREAM_END);

    /* clean up and return */
    (void)inflateEnd(&strm);
    return ret == Z_STREAM_END ? true : false;
}

bool ReaderWriterGZ::write(std::ostream& fout, const std::string& source) const
{
    int ret, flush = Z_FINISH;
    unsigned have;
    z_stream strm;
    unsigned char out[CHUNK];

    int level = 6;
    int stategy = Z_DEFAULT_STRATEGY; // looks to be the best for .osg/.ive files
    //int stategy = Z_FILTERED;
    //int stategy = Z_HUFFMAN_ONLY;
    //int stategy = Z_RLE;

    /* allocate deflate state */
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    ret = deflateInit2(&strm,
                       level,
                       Z_DEFLATED,
                       15+16, // +16 to use gzip encoding
                       8, // default
                       stategy);
    if (ret != Z_OK)
    return false;

    strm.avail_in = source.size();
    strm.next_in = (Bytef*)(&(*source.begin()));

    /* run deflate() on input until output buffer not full, finish
       compression if all of source has been read in */
    do {
        strm.avail_out = CHUNK;
        strm.next_out = out;
        ret = deflate(&strm, flush);    /* no bad return value */

        if (ret == Z_STREAM_ERROR)
        {
            osg::notify(osg::NOTICE)<<"Z_STREAM_ERROR"<<std::endl;
            return false;
        }

        have = CHUNK - strm.avail_out;

        if (have>0) fout.write((const char*)out, have);

        if (fout.fail())
        {
            (void)deflateEnd(&strm);
            return false;
        }
    } while (strm.avail_out == 0);

    /* clean up and return */
    (void)deflateEnd(&strm);
    return true;
}

// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(GZ, ReaderWriterGZ)
<commit_msg>From Chuck Seberino, "have a fix for the reading code in trunk/src/osgPlugins/gz/ReaderWriterGZ.cpp.  It seems that the std::istream::readsome method on windows is a no-op (for files.  After much head scratching and research I was able to figure out what was going on.  I am submitting a fix to replace readsome with read() and gcount().  This change is for all platforms.  The previous implementation works fine under linux and OSX, so if you would rather keep things the way they are you can just #ifdef for non-WIN32.<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/

#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgDB/Registry>

#include <iostream>
#include <sstream>
#include <fstream>
#include <iterator>

#include <zlib.h>

///////////////////////////////////////////////////////////////////////////////////////////////////
//
//  ReaderWriterGZ
//
class ReaderWriterGZ : public osgDB::ReaderWriter
{
    public:

        enum ObjectType
        {
            OBJECT,
            ARCHIVE,
            IMAGE,
            HEIGHTFIELD,
            NODE
        };

        ReaderWriterGZ();

        ~ReaderWriterGZ();

        virtual const char* className() const { return "HTTP Protocol Model Reader"; }

        virtual ReadResult openArchive(const std::string& fileName,ArchiveStatus status, unsigned int , const Options* options) const
        {
            if (status!=READ) return ReadResult(ReadResult::FILE_NOT_HANDLED);
            else return readFile(ARCHIVE,fileName,options);
        }

        virtual ReadResult readObject(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return readFile(OBJECT,fileName,options);
        }

        virtual ReadResult readImage(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return readFile(IMAGE,fileName,options);
        }

        virtual ReadResult readHeightField(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return readFile(HEIGHTFIELD,fileName,options);
        }

        virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return readFile(NODE,fileName,options);
        }

        ReadResult readFile(ObjectType objectType, osgDB::ReaderWriter* rw, std::istream& fin, const osgDB::ReaderWriter::Options* options) const;

        ReadResult readFile(ObjectType objectType, const std::string& fullFileName, const osgDB::ReaderWriter::Options* options) const;

        virtual WriteResult writeObject(const osg::Object& obj, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return writeFile(OBJECT, &obj, fileName, options);
        }

        virtual WriteResult writeImage(const osg::Image& image, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return writeFile(IMAGE, &image, fileName, options);
        }

        virtual WriteResult writeHeightField(const osg::HeightField& hf, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return writeFile(HEIGHTFIELD, &hf, fileName, options);
        }

        virtual WriteResult writeNode(const osg::Node& node, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            return writeFile(NODE, &node, fileName,options);
        }

        WriteResult writeFile(ObjectType objectType, const osg::Object* object, osgDB::ReaderWriter* rw, std::ostream& fin, const osgDB::ReaderWriter::Options* options) const;

        WriteResult writeFile(ObjectType objectType, const osg::Object* object, const std::string& fullFileName, const osgDB::ReaderWriter::Options* options) const;

        bool read(std::istream& fin, std::string& destination) const;
        bool write(std::ostream& fout, const std::string& source) const;

};

ReaderWriterGZ::ReaderWriterGZ()
{
    // osg::notify(osg::NOTICE)<<"ReaderWriterGZ::ReaderWriterGZ()"<<std::endl;

    supportsExtension("osgz","Compressed .osg file extension.");
    supportsExtension("ivez","Compressed .ive file extension.");
    supportsExtension("gz","Compressed file extension.");
}

ReaderWriterGZ::~ReaderWriterGZ()
{
    // osg::notify(osg::NOTICE)<<"ReaderWriterGZ::~ReaderWriterGZ()"<<std::endl;
}

osgDB::ReaderWriter::ReadResult ReaderWriterGZ::readFile(ObjectType objectType, osgDB::ReaderWriter* rw, std::istream& fin, const osgDB::ReaderWriter::Options *options) const
{
    switch(objectType)
    {
        case(OBJECT): return rw->readObject(fin,options);
        case(ARCHIVE): return rw->openArchive(fin,options);
        case(IMAGE): return rw->readImage(fin,options);
        case(HEIGHTFIELD): return rw->readHeightField(fin,options);
        case(NODE): return rw->readNode(fin,options);
        default: break;
    }
    return ReadResult::FILE_NOT_HANDLED;
}

osgDB::ReaderWriter::ReadResult ReaderWriterGZ::readFile(ObjectType objectType, const std::string& fullFileName, const osgDB::ReaderWriter::Options *options) const
{
    std::string ext = osgDB::getLowerCaseFileExtension(fullFileName);
    if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

    if (osgDB::containsServerAddress(fullFileName)) return ReadResult::FILE_NOT_HANDLED;

    osgDB::ReaderWriter* rw = 0;

    if (osgDB::equalCaseInsensitive(ext,"osgz"))
    {
        rw = osgDB::Registry::instance()->getReaderWriterForExtension("osg");
        osg::notify(osg::INFO)<<"osgz ReaderWriter "<<rw<<std::endl;
    }
    else if (osgDB::equalCaseInsensitive(ext,"ivez"))
    {
        rw = osgDB::Registry::instance()->getReaderWriterForExtension("ive");
        osg::notify(osg::INFO)<<"ivez ReaderWriter "<<rw<<std::endl;
    }
    else
    {
        std::string baseFileName = osgDB::getNameLessExtension(fullFileName);
        std::string baseExt = osgDB::getLowerCaseFileExtension(baseFileName);
        rw = osgDB::Registry::instance()->getReaderWriterForExtension(baseExt);
        osg::notify(osg::INFO)<<baseExt<<" ReaderWriter "<<rw<<std::endl;
    }

    std::string fileName = osgDB::findDataFile( fullFileName, options );
    if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;

    // code for setting up the database path so that internally referenced file are searched for on relative paths.
    osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
    local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));

    std::ifstream fin(fileName.c_str(), std::ios::binary|std::ios::in);
    if (!fin) return ReadResult::ERROR_IN_READING_FILE;

    std::string dest;
    read(fin, dest);

    std::stringstream strstream(dest);

    return readFile(objectType, rw, strstream, local_opt.get());
}

osgDB::ReaderWriter::WriteResult ReaderWriterGZ::writeFile(ObjectType objectType, const osg::Object* object, osgDB::ReaderWriter* rw, std::ostream& fout, const osgDB::ReaderWriter::Options *options) const
{
    switch(objectType)
    {
        case(OBJECT): return rw->writeObject(*object, fout, options);
        case(IMAGE): return rw->writeImage(*(dynamic_cast<const osg::Image*>(object)), fout, options);
        case(HEIGHTFIELD): return rw->writeHeightField(*(dynamic_cast<const osg::HeightField*>(object)), fout, options);
        case(NODE): return rw->writeNode(*(dynamic_cast<const osg::Node*>(object)), fout,options);
        default: break;
    }
    return WriteResult::FILE_NOT_HANDLED;
}

osgDB::ReaderWriter::WriteResult ReaderWriterGZ::writeFile(ObjectType objectType, const osg::Object* object, const std::string& fullFileName, const osgDB::ReaderWriter::Options *options) const
{
    std::string ext = osgDB::getLowerCaseFileExtension(fullFileName);
    if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;

    osgDB::ReaderWriter* rw = 0;

    if (osgDB::equalCaseInsensitive(ext,"osgz"))
    {
        rw = osgDB::Registry::instance()->getReaderWriterForExtension("osg");
        osg::notify(osg::NOTICE)<<"osgz ReaderWriter "<<rw<<std::endl;
    }
    else if (osgDB::equalCaseInsensitive(ext,"ivez"))
    {
        rw = osgDB::Registry::instance()->getReaderWriterForExtension("ive");
        osg::notify(osg::NOTICE)<<"ivez ReaderWriter "<<rw<<std::endl;
    }
    else
    {
        std::string baseFileName = osgDB::getNameLessExtension(fullFileName);
        std::string baseExt = osgDB::getLowerCaseFileExtension(baseFileName);
        rw = osgDB::Registry::instance()->getReaderWriterForExtension(baseExt);
        osg::notify(osg::NOTICE)<<baseExt<<" ReaderWriter "<<rw<<std::endl;
    }

    std::stringstream strstream;
    osgDB::ReaderWriter::WriteResult writeResult = writeFile(objectType, object, rw, strstream, options);

    std::ofstream fout(fullFileName.c_str());

    write(fout,strstream.str());

    return writeResult;
}

#define CHUNK 16384

bool ReaderWriterGZ::read(std::istream& fin, std::string& destination) const
{
    int ret;
    unsigned have;
    z_stream strm;
    unsigned char in[CHUNK];
    unsigned char out[CHUNK];

    /* allocate inflate state */
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    strm.avail_in = 0;
    strm.next_in = Z_NULL;
    ret = inflateInit2(&strm,
                       15 + 32 // autodetected zlib or gzip header
                       );
    if (ret != Z_OK)
        return false;

    /* decompress until deflate stream ends or end of file */
    do {

        fin.read((char*)in, CHUNK);
        strm.avail_in = fin.gcount();

        if (fin.fail())
        {
            (void)inflateEnd(&strm);
            return false;
        }
        if (strm.avail_in == 0)
            break;
        strm.next_in = in;

        /* run inflate() on input until output buffer not full */
        do {
            strm.avail_out = CHUNK;
            strm.next_out = out;
            ret = inflate(&strm, Z_NO_FLUSH);

            switch (ret) {
            case Z_NEED_DICT:
            case Z_DATA_ERROR:
            case Z_MEM_ERROR:
                (void)inflateEnd(&strm);
                return false;
            }
            have = CHUNK - strm.avail_out;

            destination.append((char*)out, have);

        } while (strm.avail_out == 0);

        /* done when inflate() says it's done */
    } while (ret != Z_STREAM_END);

    /* clean up and return */
    (void)inflateEnd(&strm);
    return ret == Z_STREAM_END ? true : false;
}

bool ReaderWriterGZ::write(std::ostream& fout, const std::string& source) const
{
    int ret, flush = Z_FINISH;
    unsigned have;
    z_stream strm;
    unsigned char out[CHUNK];

    int level = 6;
    int stategy = Z_DEFAULT_STRATEGY; // looks to be the best for .osg/.ive files
    //int stategy = Z_FILTERED;
    //int stategy = Z_HUFFMAN_ONLY;
    //int stategy = Z_RLE;

    /* allocate deflate state */
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    ret = deflateInit2(&strm,
                       level,
                       Z_DEFLATED,
                       15+16, // +16 to use gzip encoding
                       8, // default
                       stategy);
    if (ret != Z_OK)
    return false;

    strm.avail_in = source.size();
    strm.next_in = (Bytef*)(&(*source.begin()));

    /* run deflate() on input until output buffer not full, finish
       compression if all of source has been read in */
    do {
        strm.avail_out = CHUNK;
        strm.next_out = out;
        ret = deflate(&strm, flush);    /* no bad return value */

        if (ret == Z_STREAM_ERROR)
        {
            osg::notify(osg::NOTICE)<<"Z_STREAM_ERROR"<<std::endl;
            return false;
        }

        have = CHUNK - strm.avail_out;

        if (have>0) fout.write((const char*)out, have);

        if (fout.fail())
        {
            (void)deflateEnd(&strm);
            return false;
        }
    } while (strm.avail_out == 0);

    /* clean up and return */
    (void)deflateEnd(&strm);
    return true;
}

// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(GZ, ReaderWriterGZ)
<|endoftext|>


<commit_before>/****************************************************************************
 **
 ** Copyright (C) Qxt Foundation. Some rights reserved.
 **
 ** This file is part of the QxtGui module of the Qxt library.
 **
 ** This library is free software; you can redistribute it and/or modify it
 ** under the terms of the Common Public License, version 1.0, as published
 ** by IBM, and/or under the terms of the GNU Lesser General Public License,
 ** version 2.1, as published by the Free Software Foundation.
 **
 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
 ** FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** You should have received a copy of the CPL and the LGPL along with this
 ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
 ** included with the source distribution for more information.
 ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
 **
 ** <http://libqxt.org>  <foundation@libqxt.org>
 **
 ****************************************************************************/

#include "qxtcrumbview.h"
#include "qxtcrumbview_p.h"
#include <QApplication>
#include <QPaintEvent>
#include <QListView>
#include <QToolButton>
#include <QBoxLayout>
#include <QModelIndex>
#include <QAbstractItemDelegate>
#include <QStyle>
#include <QStylePainter>
#include <QSize>
#include <QFont>
#include <QtAlgorithms>
#include <QtDebug>

// This class exists only to grant access to QListView's protected members
class QxtCrumbViewList : public QListView {
friend class QxtCrumbView;
public:
    QxtCrumbViewList(QWidget* parent) : QListView(parent) {}
};

class QxtCrumbViewDelegate : public QAbstractItemDelegate {
public:
    QxtCrumbViewDelegate(QAbstractItemDelegate* other, QObject* parent) : QAbstractItemDelegate(parent), delegate(other) {
        QObject::connect(other, SIGNAL(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint)),
                         this, SIGNAL(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint)));
        QObject::connect(other, SIGNAL(commitData(QWidget*)), this, SIGNAL(commitData(QWidget*)));
        QObject::connect(other, SIGNAL(sizeHintChanged(QModelIndex)), this, SIGNAL(sizeHintChanged(QModelIndex)));

    }
    QAbstractItemDelegate* delegate;

    void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
        delegate->paint(painter, option, index);

        if(!index.model()->hasChildren(index)) return;

        int arrow = 8;
        int pad = (option.rect.height() - arrow) / 2;
        QStyleOption arrowOption;
        arrowOption = option;
        arrowOption.rect = QRect(option.rect.right() - arrow, option.rect.top() + pad, arrow, arrow);
        QApplication::style()->drawPrimitive(QStyle::PE_IndicatorArrowRight, &arrowOption, painter);
    }

    QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const {
        return delegate->sizeHint(option, index) + QSize(8, 0);
    }

    QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) {
        return delegate->createEditor(parent, option, index);
    }

    void setEditorData(QWidget* editor, const QModelIndex& index) const {
        delegate->setEditorData(editor, index);
    }

    void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const {
        delegate->setModelData(editor, model, index);
    }

    void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const {
        delegate->updateEditorGeometry(editor, option, index);
    }

    bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) {
        return delegate->editorEvent(event, model, option, index);
    }
};

class QxtCrumbViewButton : public QAbstractButton {
public:
    QxtCrumbViewButton(const QModelIndex& idx, QxtCrumbView* parent) : QAbstractButton(parent), index(idx) {
        // initializers only
    }

    QModelIndex index;

    QSize sizeHint() const {
        QStyleOptionViewItem itemOption;
        itemOption.initFrom(this);
        int border = style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2;
        int arrow = 8;
        if(index.isValid())
            return static_cast<QxtCrumbView*>(parent())->itemDelegate()->sizeHint(itemOption, index) + QSize(border + arrow, border);
        else
            return QSize(border + arrow, border + arrow);
    }

protected:
    void enterEvent(QEvent* event) {
        Q_UNUSED(event);
        update();
    }

    void leaveEvent(QEvent* event) {
        Q_UNUSED(event);
        update();
    }

    void paintEvent(QPaintEvent* event) {
        Q_UNUSED(event);
        QStylePainter painter(this);
        QStyleOptionButton option;
        option.initFrom(this);
        if(rect().contains(mapFromGlobal(QCursor::pos()))) {
            painter.drawPrimitive(QStyle::PE_PanelButtonTool, option);
        }
        int border = painter.style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
        option.rect = option.rect.adjusted(border, border, -border, -border);
        QAbstractItemDelegate* delegate = static_cast<QxtCrumbView*>(parent())->itemDelegate();
        QStyleOptionViewItem itemOption;
        itemOption.initFrom(this);
        itemOption.rect = option.rect;
        delegate->paint(&painter, itemOption, index);
        int arrow = 8;
        int pad = (height() - (2 * border) - arrow) / 2;
        QStyleOption arrowOption;
        arrowOption.initFrom(this);
        arrowOption.rect = QRect(width() - border - arrow, pad, arrow, arrow);
        painter.drawPrimitive(QStyle::PE_IndicatorArrowRight, arrowOption);
    }
};

void QxtCrumbViewPrivate::addCrumb(const QModelIndex& index) {
    crumbs.append(index);
    QxtCrumbViewButton* button = new QxtCrumbViewButton(index, &qxt_p());
    button->setFocusPolicy(Qt::NoFocus);
    button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
    buttons.append(button);
    buttonLayout->insertWidget(buttons.count() - 1, button, 0);
    QObject::connect(button, SIGNAL(clicked()), this, SLOT(buttonPressed()));
}

void QxtCrumbViewPrivate::buttonPressed() {
    qxt_p().enterTree(static_cast<QxtCrumbViewButton*>(sender())->index);
}

QxtCrumbView::QxtCrumbView(QWidget* parent) : QAbstractItemView(parent) {
    QXT_INIT_PRIVATE(QxtCrumbView);
    setAutoFillBackground(false);
    setBackgroundRole(QPalette::Window);
    viewport()->setAutoFillBackground(false);
    viewport()->setBackgroundRole(QPalette::Window);
    setFrameStyle(QFrame::NoFrame);
    QVBoxLayout* layout = new QVBoxLayout(this);
    qxt_d().buttonLayout = new QHBoxLayout;
    qxt_d().buttonLayout->setSpacing(0);
    qxt_d().buttonLayout->addStretch(1);
    QToolButton* backButton = new QToolButton(this);
    backButton->setIcon(style()->standardPixmap(QStyle::SP_FileDialogBack));
    backButton->setAutoRaise(true);
    backButton->setFocusPolicy(Qt::NoFocus);
    qxt_d().buttonLayout->addWidget(backButton);
    layout->addLayout(qxt_d().buttonLayout, 0);
    qxt_d().view = new QxtCrumbViewList(this);
    layout->addWidget(qxt_d().view, 1);
    qxt_d().addCrumb(QModelIndex());

    QObject::connect(qxt_d().view, SIGNAL(activated(QModelIndex)), this, SLOT(enterTree(QModelIndex)));
    QObject::connect(backButton, SIGNAL(clicked()), this, SLOT(back()));
}

void QxtCrumbView::setModel(QAbstractItemModel* model) {
    qxt_d().view->setModel(model);
    QAbstractItemView::setModel(model);
    delete qxt_d().view->itemDelegate();
    qxt_d().view->setItemDelegate(new QxtCrumbViewDelegate(itemDelegate(), this));
}

void QxtCrumbView::reset() {
    QAbstractItemView::reset();
    qDeleteAll(qxt_d().buttons);
    qxt_d().crumbs.clear();
    qxt_d().buttons.clear();
    qxt_d().addCrumb(QModelIndex());
}

int QxtCrumbView::horizontalOffset() const {
    return qxt_d().view->horizontalOffset();
}

int QxtCrumbView::verticalOffset() const {
    return qxt_d().view->verticalOffset();
}

QModelIndex QxtCrumbView::indexAt(const QPoint& point) const {
    return qxt_d().view->indexAt(qxt_d().view->mapFromParent(point));
}

bool QxtCrumbView::isIndexHidden(const QModelIndex& index) const {
    return qxt_d().view->isIndexHidden(index);
}

QModelIndex QxtCrumbView::moveCursor(CursorAction action, Qt::KeyboardModifiers mods) {
    return qxt_d().view->moveCursor(action, mods);
}

void QxtCrumbView::scrollTo(const QModelIndex& index, ScrollHint hint) {
    if(index.parent() != qxt_d().view->rootIndex()) {
        // set the breadcrumbs and the view's root index correctly
    }
    qxt_d().view->scrollTo(index, hint);
}

void QxtCrumbView::setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags flags) {
    QPoint tl = qxt_d().view->mapFromParent(rect.topLeft());
    qxt_d().view->setSelection(QRect(tl, rect.size()), flags);
}

QRect QxtCrumbView::visualRect(const QModelIndex& index) const {
    QRect rect = qxt_d().view->visualRect(index);
    return QRect(qxt_d().view->mapToParent(rect.topLeft()), rect.size());
}

QRegion QxtCrumbView::visualRegionForSelection(const QItemSelection& selection) const {
    QRegion region = qxt_d().view->visualRegionForSelection(selection);
    return region.translated(qxt_d().view->pos());
}

void QxtCrumbView::enterTree(const QModelIndex& index) {
    if(!model() || !model()->hasChildren(index)) return;
    if(index == qxt_d().view->rootIndex()) {
        // do nothing but reload the view
    } else if(index.parent() != qxt_d().view->rootIndex()) {
        foreach(QxtCrumbViewButton* b, qxt_d().buttons) b->deleteLater();
        qxt_d().crumbs.clear();
        qxt_d().buttons.clear();
        qxt_d().addCrumb(QModelIndex());
        QList<QModelIndex> chain;
        QModelIndex pos = index;
        while(pos.isValid()) {
            chain.append(pos);
            pos = pos.parent();
        }
        while(!chain.isEmpty()) {
            qxt_d().addCrumb(chain.last());
            chain.removeLast();
        }
    } else {
        qxt_d().addCrumb(index);
    }
    qxt_d().view->setRootIndex(index);
}

void QxtCrumbView::back() {
    if(qxt_d().crumbs.count() <= 1) return;
    qxt_d().buttons.last()->deleteLater();
    qxt_d().buttons.removeLast();
    qxt_d().crumbs.removeLast();
    qxt_d().view->setRootIndex(qxt_d().crumbs.last());
}

void QxtCrumbView::setItemDelegate(QAbstractItemDelegate* delegate) {
    QAbstractItemView::setItemDelegate(delegate);
    delete qxt_d().view->itemDelegate();
    qxt_d().view->setItemDelegate(new QxtCrumbViewDelegate(itemDelegate(), this));
}

QListView* QxtCrumbView::listView() const {
    return qxt_d().view;
}
<commit_msg>QxtCrumbView: emit activate() when leaf node is accessed<commit_after>/****************************************************************************
 **
 ** Copyright (C) Qxt Foundation. Some rights reserved.
 **
 ** This file is part of the QxtGui module of the Qxt library.
 **
 ** This library is free software; you can redistribute it and/or modify it
 ** under the terms of the Common Public License, version 1.0, as published
 ** by IBM, and/or under the terms of the GNU Lesser General Public License,
 ** version 2.1, as published by the Free Software Foundation.
 **
 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
 ** FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** You should have received a copy of the CPL and the LGPL along with this
 ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
 ** included with the source distribution for more information.
 ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
 **
 ** <http://libqxt.org>  <foundation@libqxt.org>
 **
 ****************************************************************************/

#include "qxtcrumbview.h"
#include "qxtcrumbview_p.h"
#include <QApplication>
#include <QPaintEvent>
#include <QListView>
#include <QToolButton>
#include <QBoxLayout>
#include <QModelIndex>
#include <QAbstractItemDelegate>
#include <QStyle>
#include <QStylePainter>
#include <QSize>
#include <QFont>
#include <QtAlgorithms>
#include <QtDebug>

// This class exists only to grant access to QListView's protected members
class QxtCrumbViewList : public QListView {
friend class QxtCrumbView;
public:
    QxtCrumbViewList(QWidget* parent) : QListView(parent) {}
};

class QxtCrumbViewDelegate : public QAbstractItemDelegate {
public:
    QxtCrumbViewDelegate(QAbstractItemDelegate* other, QObject* parent) : QAbstractItemDelegate(parent), delegate(other) {
        QObject::connect(other, SIGNAL(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint)),
                         this, SIGNAL(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint)));
        QObject::connect(other, SIGNAL(commitData(QWidget*)), this, SIGNAL(commitData(QWidget*)));
        QObject::connect(other, SIGNAL(sizeHintChanged(QModelIndex)), this, SIGNAL(sizeHintChanged(QModelIndex)));

    }
    QAbstractItemDelegate* delegate;

    void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
        delegate->paint(painter, option, index);

        if(!index.model()->hasChildren(index)) return;

        int arrow = 8;
        int pad = (option.rect.height() - arrow) / 2;
        QStyleOption arrowOption;
        arrowOption = option;
        arrowOption.rect = QRect(option.rect.right() - arrow, option.rect.top() + pad, arrow, arrow);
        QApplication::style()->drawPrimitive(QStyle::PE_IndicatorArrowRight, &arrowOption, painter);
    }

    QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const {
        return delegate->sizeHint(option, index) + QSize(8, 0);
    }

    QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) {
        return delegate->createEditor(parent, option, index);
    }

    void setEditorData(QWidget* editor, const QModelIndex& index) const {
        delegate->setEditorData(editor, index);
    }

    void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const {
        delegate->setModelData(editor, model, index);
    }

    void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const {
        delegate->updateEditorGeometry(editor, option, index);
    }

    bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) {
        return delegate->editorEvent(event, model, option, index);
    }
};

class QxtCrumbViewButton : public QAbstractButton {
public:
    QxtCrumbViewButton(const QModelIndex& idx, QxtCrumbView* parent) : QAbstractButton(parent), index(idx) {
        // initializers only
    }

    QModelIndex index;

    QSize sizeHint() const {
        QStyleOptionViewItem itemOption;
        itemOption.initFrom(this);
        int border = style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2;
        int arrow = 8;
        if(index.isValid())
            return static_cast<QxtCrumbView*>(parent())->itemDelegate()->sizeHint(itemOption, index) + QSize(border + arrow, border);
        else
            return QSize(border + arrow, border + arrow);
    }

protected:
    void enterEvent(QEvent* event) {
        Q_UNUSED(event);
        update();
    }

    void leaveEvent(QEvent* event) {
        Q_UNUSED(event);
        update();
    }

    void paintEvent(QPaintEvent* event) {
        Q_UNUSED(event);
        QStylePainter painter(this);
        QStyleOptionButton option;
        option.initFrom(this);
        if(rect().contains(mapFromGlobal(QCursor::pos()))) {
            painter.drawPrimitive(QStyle::PE_PanelButtonTool, option);
        }
        int border = painter.style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
        option.rect = option.rect.adjusted(border, border, -border, -border);
        QAbstractItemDelegate* delegate = static_cast<QxtCrumbView*>(parent())->itemDelegate();
        QStyleOptionViewItem itemOption;
        itemOption.initFrom(this);
        itemOption.rect = option.rect;
        delegate->paint(&painter, itemOption, index);
        int arrow = 8;
        int pad = (height() - (2 * border) - arrow) / 2;
        QStyleOption arrowOption;
        arrowOption.initFrom(this);
        arrowOption.rect = QRect(width() - border - arrow, pad, arrow, arrow);
        painter.drawPrimitive(QStyle::PE_IndicatorArrowRight, arrowOption);
    }
};

void QxtCrumbViewPrivate::addCrumb(const QModelIndex& index) {
    crumbs.append(index);
    QxtCrumbViewButton* button = new QxtCrumbViewButton(index, &qxt_p());
    button->setFocusPolicy(Qt::NoFocus);
    button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
    buttons.append(button);
    buttonLayout->insertWidget(buttons.count() - 1, button, 0);
    QObject::connect(button, SIGNAL(clicked()), this, SLOT(buttonPressed()));
}

void QxtCrumbViewPrivate::buttonPressed() {
    qxt_p().enterTree(static_cast<QxtCrumbViewButton*>(sender())->index);
}

QxtCrumbView::QxtCrumbView(QWidget* parent) : QAbstractItemView(parent) {
    QXT_INIT_PRIVATE(QxtCrumbView);
    setAutoFillBackground(false);
    setBackgroundRole(QPalette::Window);
    viewport()->setAutoFillBackground(false);
    viewport()->setBackgroundRole(QPalette::Window);
    setFrameStyle(QFrame::NoFrame);
    QVBoxLayout* layout = new QVBoxLayout(this);
    qxt_d().buttonLayout = new QHBoxLayout;
    qxt_d().buttonLayout->setSpacing(0);
    qxt_d().buttonLayout->addStretch(1);
    QToolButton* backButton = new QToolButton(this);
    backButton->setIcon(style()->standardPixmap(QStyle::SP_FileDialogBack));
    backButton->setAutoRaise(true);
    backButton->setFocusPolicy(Qt::NoFocus);
    qxt_d().buttonLayout->addWidget(backButton);
    layout->addLayout(qxt_d().buttonLayout, 0);
    qxt_d().view = new QxtCrumbViewList(this);
    layout->addWidget(qxt_d().view, 1);
    qxt_d().addCrumb(QModelIndex());

    QObject::connect(qxt_d().view, SIGNAL(activated(QModelIndex)), this, SLOT(enterTree(QModelIndex)));
    QObject::connect(backButton, SIGNAL(clicked()), this, SLOT(back()));
}

void QxtCrumbView::setModel(QAbstractItemModel* model) {
    qxt_d().view->setModel(model);
    QAbstractItemView::setModel(model);
    delete qxt_d().view->itemDelegate();
    qxt_d().view->setItemDelegate(new QxtCrumbViewDelegate(itemDelegate(), this));
}

void QxtCrumbView::reset() {
    QAbstractItemView::reset();
    qDeleteAll(qxt_d().buttons);
    qxt_d().crumbs.clear();
    qxt_d().buttons.clear();
    qxt_d().addCrumb(QModelIndex());
}

int QxtCrumbView::horizontalOffset() const {
    return qxt_d().view->horizontalOffset();
}

int QxtCrumbView::verticalOffset() const {
    return qxt_d().view->verticalOffset();
}

QModelIndex QxtCrumbView::indexAt(const QPoint& point) const {
    return qxt_d().view->indexAt(qxt_d().view->mapFromParent(point));
}

bool QxtCrumbView::isIndexHidden(const QModelIndex& index) const {
    return qxt_d().view->isIndexHidden(index);
}

QModelIndex QxtCrumbView::moveCursor(CursorAction action, Qt::KeyboardModifiers mods) {
    return qxt_d().view->moveCursor(action, mods);
}

void QxtCrumbView::scrollTo(const QModelIndex& index, ScrollHint hint) {
    if(index.parent() != qxt_d().view->rootIndex()) {
        // set the breadcrumbs and the view's root index correctly
    }
    qxt_d().view->scrollTo(index, hint);
}

void QxtCrumbView::setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags flags) {
    QPoint tl = qxt_d().view->mapFromParent(rect.topLeft());
    qxt_d().view->setSelection(QRect(tl, rect.size()), flags);
}

QRect QxtCrumbView::visualRect(const QModelIndex& index) const {
    QRect rect = qxt_d().view->visualRect(index);
    return QRect(qxt_d().view->mapToParent(rect.topLeft()), rect.size());
}

QRegion QxtCrumbView::visualRegionForSelection(const QItemSelection& selection) const {
    QRegion region = qxt_d().view->visualRegionForSelection(selection);
    return region.translated(qxt_d().view->pos());
}

void QxtCrumbView::enterTree(const QModelIndex& index) {
    if(!model()) return;
    if(!model()->hasChildren(index)) {
        emit activated(index);
        return;
    }
    if(index == qxt_d().view->rootIndex()) {
        // do nothing but reload the view
    } else if(index.parent() != qxt_d().view->rootIndex()) {
        foreach(QxtCrumbViewButton* b, qxt_d().buttons) b->deleteLater();
        qxt_d().crumbs.clear();
        qxt_d().buttons.clear();
        qxt_d().addCrumb(QModelIndex());
        QList<QModelIndex> chain;
        QModelIndex pos = index;
        while(pos.isValid()) {
            chain.append(pos);
            pos = pos.parent();
        }
        while(!chain.isEmpty()) {
            qxt_d().addCrumb(chain.last());
            chain.removeLast();
        }
    } else {
        qxt_d().addCrumb(index);
    }
    qxt_d().view->setRootIndex(index);
}

void QxtCrumbView::back() {
    if(qxt_d().crumbs.count() <= 1) return;
    qxt_d().buttons.last()->deleteLater();
    qxt_d().buttons.removeLast();
    qxt_d().crumbs.removeLast();
    qxt_d().view->setRootIndex(qxt_d().crumbs.last());
}

void QxtCrumbView::setItemDelegate(QAbstractItemDelegate* delegate) {
    QAbstractItemView::setItemDelegate(delegate);
    delete qxt_d().view->itemDelegate();
    qxt_d().view->setItemDelegate(new QxtCrumbViewDelegate(itemDelegate(), this));
}

QListView* QxtCrumbView::listView() const {
    return qxt_d().view;
}
<|endoftext|>