/************************************************************************** ** ** 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 #include #include #include #include #include #include using namespace Find::Internal; SearchResultTreeModel::SearchResultTreeModel(QObject *parent) : QAbstractItemModel(parent) , m_lastAddedResultFile(0) , m_showReplaceUI(false) { m_rootItem = new SearchResultTreeItem; m_textEditorFont = QFont("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(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(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(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(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(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(item); result = data(row, role); } else if (item->itemType() == SearchResultTreeItem::ResultFile) { const SearchResultFile *file = static_cast(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(index.internalPointer()); SearchResultTextRow *row = static_cast(item); Qt::CheckState checkState = static_cast(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 = "row"; break; case ItemDataRoles::FileNameRole: { if (row->parent()->itemType() == SearchResultTreeItem::ResultFile) { const SearchResultFile *file = static_cast(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::appendResultLine(int index, int lineNumber, const QString &rowText, int searchTermStart, int searchTermLength) { if (!m_lastAddedResultFile) return; QModelIndex lastFile(createIndex(m_lastAddedResultFile->rowOfItem(), 0, m_lastAddedResultFile)); beginInsertRows(lastFile, m_lastAddedResultFile->childrenCount(), m_lastAddedResultFile->childrenCount()); m_lastAddedResultFile->appendResultLine(index, lineNumber, rowText, searchTermStart, 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. */ int SearchResultTreeModel::addResultLine(int index, const QString &fileName, int lineNumber, const QString &rowText, int searchTermStart, int searchTermLength) { int insertionIndex = -1; if (!m_lastAddedResultFile || (m_lastAddedResultFile->fileName() != fileName)) insertionIndex = addResultFile(fileName); appendResultLine(index, lineNumber, rowText, searchTermStart, searchTermLength); return insertionIndex; } 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(); }