#include "headercompletionpopup.h" #include #include #include #include HeaderCompletionPopup::HeaderCompletionPopup(QWidget* parent):QWidget(parent) { setWindowFlags(Qt::Popup); mListView = new CodeCompletionListView(this); mModel=new HeaderCompletionListModel(&mCompletionList); mListView->setModel(mModel); setLayout(new QVBoxLayout()); layout()->addWidget(mListView); layout()->setMargin(0); mSearchLocal = false; mCurrentFile = ""; mPhrase = ""; mIgnoreCase = false; } HeaderCompletionPopup::~HeaderCompletionPopup() { delete mModel; } void HeaderCompletionPopup::prepareSearch(const QString &phrase, const QString &fileName) { QCursor oldCursor = cursor(); setCursor(Qt::WaitCursor); mCurrentFile = fileName; mPhrase = phrase; getCompletionFor(phrase); setCursor(oldCursor); } bool HeaderCompletionPopup::search(const QString &phrase, bool autoHideOnSingleResult) { mPhrase = phrase; if (mPhrase.isEmpty()) { hide(); return false; } if(!isEnabled()) return false; QCursor oldCursor = cursor(); setCursor(Qt::WaitCursor); int i = mPhrase.lastIndexOf('\\'); if (i<0) { i = mPhrase.lastIndexOf('/'); } QString symbol = mPhrase; if (i>=0) { symbol = mPhrase.mid(i+1); } // filter fFullCompletionList to fCompletionList filterList(symbol); mModel->notifyUpdated(); setCursor(oldCursor); if (!mCompletionList.isEmpty()) { mListView->setCurrentIndex(mModel->index(0,0)); if (mCompletionList.count() == 1) { // if only one suggestion and auto hide , don't show the frame if (autoHideOnSingleResult) return true; // if only one suggestion, and is exactly the symbol to search, hide the frame (the search is over) if (symbol == mCompletionList.front()) return true; } } else { hide(); } return false; } void HeaderCompletionPopup::setKeypressedCallback(const KeyPressedCallback &newKeypressedCallback) { mListView->setKeypressedCallback(newKeypressedCallback); } void HeaderCompletionPopup::setSuggestionColor(const QColor &color) { mModel->setColor(color); } QString HeaderCompletionPopup::selectedFilename() { if (!isEnabled()) return ""; int index = mListView->currentIndex().row(); if (index>=0 && index0) { return mCompletionList.front(); } return ""; } void HeaderCompletionPopup::filterList(const QString &member) { mCompletionList.clear(); if (member.isEmpty()) { foreach (const QString& s,mFullCompletionList) { mCompletionList.append(s); } } else { foreach (const QString& s,mFullCompletionList) { if (mIgnoreCase && s.startsWith(member, Qt::CaseInsensitive)) { mCompletionList.append(s); } else if (s.startsWith(member, Qt::CaseSensitive)){ mCompletionList.append(s); } } } std::sort(mCompletionList.begin(),mCompletionList.end()); } void HeaderCompletionPopup::getCompletionFor(const QString &phrase) { int idx = phrase.lastIndexOf('\\'); if (idx<0) { idx = phrase.lastIndexOf('/'); } mFullCompletionList.clear(); if (idx < 0) { // dont have basedir if (mSearchLocal) { QFileInfo fileInfo(mCurrentFile); addFilesInPath(fileInfo.absolutePath()); }; for (const QString& path: mParser->includePaths()) { addFilesInPath(path); } for (const QString& path: mParser->projectIncludePaths()) { addFilesInPath(path); } } else { QString current = phrase.mid(0,idx); if (mSearchLocal) { QFileInfo fileInfo(mCurrentFile); addFilesInSubDir(fileInfo.absolutePath(),current); } for (const QString& path: mParser->includePaths()) { addFilesInSubDir(path,current); } for (const QString& path: mParser->projectIncludePaths()) { addFilesInSubDir(path,current); } } } void HeaderCompletionPopup::addFilesInPath(const QString &path) { QDir dir(path); if (!dir.exists()) return; foreach (const QFileInfo& fileInfo, dir.entryInfoList()) { if (fileInfo.fileName().startsWith(".")) continue; QString suffix = fileInfo.suffix().toLower(); if (suffix == "h" || suffix == "hpp" || suffix == "") { addFile(fileInfo.fileName()); } } } void HeaderCompletionPopup::addFile(const QString &fileName) { if (fileName.isEmpty()) return; if (fileName.startsWith('.')) return; mFullCompletionList.insert(fileName); } void HeaderCompletionPopup::addFilesInSubDir(const QString &baseDirPath, const QString &subDirName) { QDir baseDir(baseDirPath); QString subDirPath = baseDir.filePath(subDirName); addFilesInPath(subDirPath); } bool HeaderCompletionPopup::searchLocal() const { return mSearchLocal; } void HeaderCompletionPopup::setSearchLocal(bool newSearchLocal) { mSearchLocal = newSearchLocal; } bool HeaderCompletionPopup::ignoreCase() const { return mIgnoreCase; } void HeaderCompletionPopup::setIgnoreCase(bool newIgnoreCase) { mIgnoreCase = newIgnoreCase; } const QString &HeaderCompletionPopup::phrase() const { return mPhrase; } void HeaderCompletionPopup::setParser(const PCppParser &newParser) { mParser = newParser; } void HeaderCompletionPopup::showEvent(QShowEvent *) { mListView->setFocus(); } void HeaderCompletionPopup::hideEvent(QHideEvent *) { mCompletionList.clear(); mFullCompletionList.clear(); } bool HeaderCompletionPopup::event(QEvent *event) { bool result = QWidget::event(event); switch (event->type()) { case QEvent::FontChange: mListView->setFont(font()); break; } return result; } HeaderCompletionListModel::HeaderCompletionListModel(const QStringList *files, QObject *parent): QAbstractListModel(parent), mFiles(files) { } int HeaderCompletionListModel::rowCount(const QModelIndex &) const { return mFiles->count(); } QVariant HeaderCompletionListModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (index.row()>=mFiles->count()) return QVariant(); switch(role) { case Qt::DisplayRole: { return mFiles->at(index.row()); } case Qt::ForegroundRole: return mColor; break; } return QVariant(); } void HeaderCompletionListModel::notifyUpdated() { beginResetModel(); endResetModel(); } void HeaderCompletionListModel::setColor(const QColor &newColor) { mColor = newColor; }