From: PeterLValve Date: Tue, 18 Mar 2014 22:24:24 +0000 (-0700) Subject: UI: Fix issue #20: Search in the editor really slow X-Git-Url: https://git.cworth.org/git?p=vogl;a=commitdiff_plain;h=406ad78f7c0f904c1f7c00dddd51c8e98e83ccfa UI: Fix issue #20: Search in the editor really slow * Instead of selecting all the rows which match the search string, the tree view now highlights those rows which match and are visible. * If the user presses [enter], the first matching row (if one exists) will be scrolled into view and selected. * Continually pressing enter will cycle through each match, in the same way that clicking the "Next" button works. * If there are no matching items when the user presses [enter], the background to the search textbox will turn red. It will restore to its previous color when the user next edits the text. --- diff --git a/src/vogleditor/vogleditor.cpp b/src/vogleditor/vogleditor.cpp index a7c199c..ea33ffa 100644 --- a/src/vogleditor/vogleditor.cpp +++ b/src/vogleditor/vogleditor.cpp @@ -132,6 +132,9 @@ VoglEditor::VoglEditor(QWidget *parent) : m_statusLabel->setBaseSize(150, 12); ui->statusBar->addWidget(m_statusLabel, 1); + // cache the original background color of the search text box + m_searchTextboxBackgroundColor = ui->searchTextBox->palette().base().color(); + // setup framebuffer tab QGridLayout* framebufferTab_layout = new QGridLayout; m_framebufferExplorer = new vogleditor_QFramebufferExplorer(ui->framebufferTab); @@ -348,7 +351,6 @@ void VoglEditor::close_trace_file() m_openFilename.clear(); m_backtraceToJsonMap.clear(); m_backtraceDoc.clear(); - m_searchApicallResults.clear(); reset_tracefile_ui(); @@ -1632,71 +1634,23 @@ void VoglEditor::selectApicallModelIndex(QModelIndex index, bool scrollTo, bool { ui->treeView->setCurrentIndex(index); } - - if (m_searchApicallResults.size() > 0 && !ui->searchTextBox->text().isEmpty()) - { - QItemSelectionModel* pSelection = ui->treeView->selectionModel(); - for (int i = 0; i < m_searchApicallResults.size(); i++) - { - pSelection->select(m_searchApicallResults[i], QItemSelectionModel::Select | QItemSelectionModel::Rows); - } - ui->treeView->setSelectionModel(pSelection); - } } void VoglEditor::on_searchTextBox_textChanged(const QString &searchText) { - QModelIndex curSearchIndex = ui->treeView->currentIndex(); - if (curSearchIndex.isValid() == false) - { - return; - } - - // store original background color of the search text box so that it can be turned to red and later restored. - static const QColor sOriginalTextBoxBackground = ui->searchTextBox->palette().base().color(); - - // clear previous items - QItemSelectionModel* pSelection = ui->treeView->selectionModel(); - if (pSelection != NULL) - { - for (int i = 0; i < m_searchApicallResults.size(); i++) - { - pSelection->select(m_searchApicallResults[i], QItemSelectionModel::Clear | QItemSelectionModel::Rows); - } - ui->treeView->setSelectionModel(pSelection); - } + QPalette palette(ui->searchTextBox->palette()); + palette.setColor(QPalette::Base, m_searchTextboxBackgroundColor); + ui->searchTextBox->setPalette(palette); - // find new matches - m_searchApicallResults.clear(); if (m_pApicallTreeModel != NULL) { - m_searchApicallResults = m_pApicallTreeModel->find_search_matches(searchText); + m_pApicallTreeModel->set_highlight_search_string(searchText); } - // if there are matches, restore the textbox background to its original color - if (m_searchApicallResults.size() > 0) - { - QPalette palette(ui->searchTextBox->palette()); - palette.setColor(QPalette::Base, sOriginalTextBoxBackground); - ui->searchTextBox->setPalette(palette); - } - - // select new items - if (!searchText.isEmpty()) - { - if (m_searchApicallResults.size() > 0) - { - // scroll to the first result, but don't select it - selectApicallModelIndex(m_searchApicallResults[0], true, false); - } - else - { - // no items were found, so set the textbox background to red - QPalette palette(ui->searchTextBox->palette()); - palette.setColor(QPalette::Base, Qt::red); - ui->searchTextBox->setPalette(palette); - } - } + // need to briefly give the treeview focus so that it properly redraws and highlights the matching rows + // then return focus to the search textbox so that typed keys are not lost + ui->treeView->setFocus(); + ui->searchTextBox->setFocus(); } void VoglEditor::on_searchNextButton_clicked() @@ -1704,7 +1658,11 @@ void VoglEditor::on_searchNextButton_clicked() if (m_pApicallTreeModel != NULL) { QModelIndex index = m_pApicallTreeModel->find_next_search_result(m_pCurrentCallTreeItem, ui->searchTextBox->text()); - selectApicallModelIndex(index, true, true); + if (index.isValid()) + { + selectApicallModelIndex(index, true, true); + ui->treeView->setFocus(); + } } } @@ -1713,7 +1671,11 @@ void VoglEditor::on_searchPrevButton_clicked() if (m_pApicallTreeModel != NULL) { QModelIndex index = m_pApicallTreeModel->find_prev_search_result(m_pCurrentCallTreeItem, ui->searchTextBox->text()); - selectApicallModelIndex(index, true, true); + if (index.isValid()) + { + selectApicallModelIndex(index, true, true); + ui->treeView->setFocus(); + } } } @@ -1722,8 +1684,11 @@ void VoglEditor::on_prevSnapshotButton_clicked() if (m_pApicallTreeModel != NULL) { vogleditor_apiCallTreeItem* pPrevItemWithSnapshot = m_pApicallTreeModel->find_prev_snapshot(m_pCurrentCallTreeItem); - selectApicallModelIndex(m_pApicallTreeModel->indexOf(pPrevItemWithSnapshot), true, true); - ui->treeView->setFocus(); + if (pPrevItemWithSnapshot != NULL) + { + selectApicallModelIndex(m_pApicallTreeModel->indexOf(pPrevItemWithSnapshot), true, true); + ui->treeView->setFocus(); + } } } @@ -1732,8 +1697,11 @@ void VoglEditor::on_nextSnapshotButton_clicked() if (m_pApicallTreeModel != NULL) { vogleditor_apiCallTreeItem* pNextItemWithSnapshot = m_pApicallTreeModel->find_next_snapshot(m_pCurrentCallTreeItem); - selectApicallModelIndex(m_pApicallTreeModel->indexOf(pNextItemWithSnapshot), true, true); - ui->treeView->setFocus(); + if (pNextItemWithSnapshot != NULL) + { + selectApicallModelIndex(m_pApicallTreeModel->indexOf(pNextItemWithSnapshot), true, true); + ui->treeView->setFocus(); + } } } @@ -1742,8 +1710,11 @@ void VoglEditor::on_prevDrawcallButton_clicked() if (m_pApicallTreeModel != NULL) { vogleditor_apiCallTreeItem* pPrevItem = m_pApicallTreeModel->find_prev_drawcall(m_pCurrentCallTreeItem); - selectApicallModelIndex(m_pApicallTreeModel->indexOf(pPrevItem), true, true); - ui->treeView->setFocus(); + if (pPrevItem != NULL) + { + selectApicallModelIndex(m_pApicallTreeModel->indexOf(pPrevItem), true, true); + ui->treeView->setFocus(); + } } } @@ -1752,12 +1723,14 @@ void VoglEditor::on_nextDrawcallButton_clicked() if (m_pApicallTreeModel != NULL) { vogleditor_apiCallTreeItem* pNextItem = m_pApicallTreeModel->find_next_drawcall(m_pCurrentCallTreeItem); - selectApicallModelIndex(m_pApicallTreeModel->indexOf(pNextItem), true, true); - ui->treeView->setFocus(); + if (pNextItem != NULL) + { + selectApicallModelIndex(m_pApicallTreeModel->indexOf(pNextItem), true, true); + ui->treeView->setFocus(); + } } } - void VoglEditor::on_program_edited(vogl_program_state* pNewProgramState) { VOGL_NOTE_UNUSED(pNewProgramState); @@ -1841,3 +1814,23 @@ void VoglEditor::on_actionOpen_Session_triggered() setCursor(origCursor); } + +void VoglEditor::on_searchTextBox_returnPressed() +{ + if (m_pApicallTreeModel != NULL) + { + QModelIndex index = m_pApicallTreeModel->find_next_search_result(m_pCurrentCallTreeItem, ui->searchTextBox->text()); + if (index.isValid()) + { + // a valid item was found, scroll to it and select it + selectApicallModelIndex(index, true, true); + } + else + { + // no items were found, so set the textbox background to red (it will get cleared to the original color if the user edits the search text) + QPalette palette(ui->searchTextBox->palette()); + palette.setColor(QPalette::Base, Qt::red); + ui->searchTextBox->setPalette(palette); + } + } +} diff --git a/src/vogleditor/vogleditor.h b/src/vogleditor/vogleditor.h index ad007e2..30ffd58 100644 --- a/src/vogleditor/vogleditor.h +++ b/src/vogleditor/vogleditor.h @@ -110,6 +110,8 @@ private slots: void on_actionOpen_Session_triggered(); + void on_searchTextBox_returnPressed(); + private: Ui::VoglEditor* ui; @@ -166,8 +168,7 @@ private: vogleditor_apiCallTimelineModel* m_pTimelineModel; vogleditor_QApiCallTreeModel* m_pApicallTreeModel; - - QModelIndexList m_searchApicallResults; + QColor m_searchTextboxBackgroundColor; }; #endif // VOGLEDITOR_H diff --git a/src/vogleditor/vogleditor_qapicalltreemodel.cpp b/src/vogleditor/vogleditor_qapicalltreemodel.cpp index e34cc5b..e661f1c 100644 --- a/src/vogleditor/vogleditor_qapicalltreemodel.cpp +++ b/src/vogleditor/vogleditor_qapicalltreemodel.cpp @@ -312,9 +312,23 @@ QVariant vogleditor_QApiCallTreeModel::data(const QModelIndex &index, int role) if (!index.isValid()) return QVariant(); - vogleditor_apiCallTreeItem *item = static_cast(index.internalPointer()); + vogleditor_apiCallTreeItem* pItem = static_cast(index.internalPointer()); - return item->columnData(index.column(), role); + // highlight the API call cell if it has a substring which matches the searchString + if (role == Qt::BackgroundRole && index.column() == VOGL_ACTC_APICALL) + { + if (!m_searchString.isEmpty()) + { + QVariant data = pItem->columnData(VOGL_ACTC_APICALL, Qt::DisplayRole); + QString string = data.toString(); + if (string.contains(m_searchString, Qt::CaseInsensitive)) + { + return QColor(Qt::yellow); + } + } + } + + return pItem->columnData(index.column(), role); } Qt::ItemFlags vogleditor_QApiCallTreeModel::flags(const QModelIndex &index) const @@ -334,44 +348,35 @@ QVariant vogleditor_QApiCallTreeModel::headerData(int section, Qt::Orientation o return QVariant(); } -QModelIndexList vogleditor_QApiCallTreeModel::find_search_matches(const QString searchText) +void vogleditor_QApiCallTreeModel::set_highlight_search_string(const QString searchString) +{ + m_searchString = searchString; +} + +QModelIndex vogleditor_QApiCallTreeModel::find_prev_search_result(vogleditor_apiCallTreeItem* start, const QString searchText) { QLinkedListIterator iter(m_itemList); - QModelIndexList matches; - // iterate through all items and find matching text - while (iter.hasNext()) + if (start != NULL) { - vogleditor_apiCallTreeItem* pItem = iter.peekNext(); - QVariant data = pItem->columnData(VOGL_ACTC_APICALL, Qt::DisplayRole); - QString string = data.toString(); - if (string.contains(searchText, Qt::CaseInsensitive)) + if (iter.findNext(start) == false) { - matches.push_back(indexOf(pItem)); + // the object wasn't found in the list, so return a default (invalid) item + return QModelIndex(); } - iter.next(); + // need to back up past the current item + iter.previous(); } - - return matches; -} - -QModelIndex vogleditor_QApiCallTreeModel::find_prev_search_result(vogleditor_apiCallTreeItem* start, const QString searchText) -{ - QLinkedListIterator iter(m_itemList); - - if (iter.findNext(start) == false) + else { - // the object wasn't found in the list, so just return the same item - return indexOf(start); + // set the iterator to the back so that searching starts from the end of the list + iter.toBack(); } - // need to back up past the current item - iter.previous(); - // now the iterator is pointing to the desired start object in the list, // continually check the prev item and find one with a snapshot - vogleditor_apiCallTreeItem* pFound = start; + vogleditor_apiCallTreeItem* pFound = NULL; while (iter.hasPrevious()) { vogleditor_apiCallTreeItem* pItem = iter.peekPrevious(); @@ -391,18 +396,20 @@ QModelIndex vogleditor_QApiCallTreeModel::find_prev_search_result(vogleditor_api QModelIndex vogleditor_QApiCallTreeModel::find_next_search_result(vogleditor_apiCallTreeItem* start, const QString searchText) { - QLinkedListIterator iter(m_itemList); - if (iter.findNext(start) == false) + if (start != NULL) { - // the object wasn't found in the list, so just return the same item - return indexOf(start); + if (iter.findNext(start) == false) + { + // the object wasn't found in the list, so return a default (invalid) item + return QModelIndex(); + } } // now the iterator is pointing to the desired start object in the list, // continually check the next item and find one with a snapshot - vogleditor_apiCallTreeItem* pFound = start; + vogleditor_apiCallTreeItem* pFound = NULL; while (iter.hasNext()) { vogleditor_apiCallTreeItem* pItem = iter.peekNext(); @@ -424,18 +431,26 @@ vogleditor_apiCallTreeItem* vogleditor_QApiCallTreeModel::find_prev_snapshot(vog { QLinkedListIterator iter(m_itemList); - if (iter.findNext(start) == false) + if (start != NULL) { - // the object wasn't found in the list, so just return the same item - return start; - } + if (iter.findNext(start) == false) + { + // the object wasn't found in the list + return NULL; + } - // need to back up past the current item - iter.previous(); + // need to back up past the current item + iter.previous(); + } + else + { + // set the iterator to the back so that searching starts from the end of the list + iter.toBack(); + } // now the iterator is pointing to the desired start object in the list, // continually check the prev item and find one with a snapshot - vogleditor_apiCallTreeItem* pFound = start; + vogleditor_apiCallTreeItem* pFound = NULL; while (iter.hasPrevious()) { if (iter.peekPrevious()->has_snapshot()) @@ -459,14 +474,14 @@ vogleditor_apiCallTreeItem* vogleditor_QApiCallTreeModel::find_next_snapshot(vog { if (iter.findNext(start) == false) { - // the object wasn't found in the list, so just return the same item - return start; + // the object wasn't found in the list + return NULL; } } // now the iterator is pointing to the desired start object in the list, // continually check the next item and find one with a snapshot - vogleditor_apiCallTreeItem* pFound = start; + vogleditor_apiCallTreeItem* pFound = NULL; while (iter.hasNext()) { if (iter.peekNext()->has_snapshot()) @@ -486,18 +501,26 @@ vogleditor_apiCallTreeItem *vogleditor_QApiCallTreeModel::find_prev_drawcall(vog { QLinkedListIterator iter(m_itemList); - if (iter.findNext(start) == false) + if (start != NULL) { - // the object wasn't found in the list, so just return the same item - return start; - } + if (iter.findNext(start) == false) + { + // the object wasn't found in the list + return NULL; + } - // need to back up past the current item - iter.previous(); + // need to back up past the current item + iter.previous(); + } + else + { + // set the iterator to the back so that searching starts from the end of the list + iter.toBack(); + } // now the iterator is pointing to the desired start object in the list, // continually check the prev item and find one with a snapshot - vogleditor_apiCallTreeItem* pFound = start; + vogleditor_apiCallTreeItem* pFound = NULL; while (iter.hasPrevious()) { vogleditor_apiCallTreeItem* pItem = iter.peekPrevious(); @@ -524,13 +547,13 @@ vogleditor_apiCallTreeItem *vogleditor_QApiCallTreeModel::find_next_drawcall(vog if (iter.findNext(start) == false) { - // the object wasn't found in the list, so just return the same item - return start; + // the object wasn't found in the list + return NULL; } // now the iterator is pointing to the desired start object in the list, // continually check the next item and find one with a snapshot - vogleditor_apiCallTreeItem* pFound = start; + vogleditor_apiCallTreeItem* pFound = NULL; while (iter.hasNext()) { vogleditor_apiCallTreeItem* pItem = iter.peekNext(); diff --git a/src/vogleditor/vogleditor_qapicalltreemodel.h b/src/vogleditor/vogleditor_qapicalltreemodel.h index 91305c8..dab3da9 100644 --- a/src/vogleditor/vogleditor_qapicalltreemodel.h +++ b/src/vogleditor/vogleditor_qapicalltreemodel.h @@ -61,7 +61,7 @@ public: return m_rootItem; } - QModelIndexList find_search_matches(const QString searchText); + void set_highlight_search_string(const QString searchString); QModelIndex find_prev_search_result(vogleditor_apiCallTreeItem* start, const QString searchText); QModelIndex find_next_search_result(vogleditor_apiCallTreeItem* start, const QString searchText); @@ -82,6 +82,7 @@ private: vogleditor_apiCallTreeItem* m_rootItem; vogl_ctypes m_trace_ctypes; QLinkedList m_itemList; + QString m_searchString; void setupModelData(vogl_trace_file_reader* pTrace_reader, vogleditor_apiCallTreeItem* parent);