diff -r 723f61499a79 -r bc0b38405b6a eric7/PipInterface/PipPackagesWidget.py --- a/eric7/PipInterface/PipPackagesWidget.py Thu Mar 24 19:29:13 2022 +0100 +++ b/eric7/PipInterface/PipPackagesWidget.py Fri Mar 25 19:06:20 2022 +0100 @@ -19,7 +19,7 @@ from PyQt6.QtNetwork import QNetworkReply, QNetworkRequest from PyQt6.QtWidgets import ( QWidget, QToolButton, QApplication, QHeaderView, QTreeWidgetItem, - QMenu, QDialog + QMenu, QDialog, QAbstractItemView ) from EricWidgets.EricApplication import ericApp @@ -205,6 +205,8 @@ UI.PixmapCache.getIcon("find")) self.searchButton.setIcon( UI.PixmapCache.getIcon("findNext")) + self.searchMoreButton.setIcon( + UI.PixmapCache.getIcon("plus")) self.installButton.setIcon( UI.PixmapCache.getIcon("plus")) self.installUserSiteButton.setIcon( @@ -263,6 +265,7 @@ self.statusLabel.hide() self.searchWidget.hide() + self.__lastSearchPage = 0 self.__queryName = [] self.__querySummary = [] @@ -475,6 +478,7 @@ self.__updateActionButtons() self.__updateSearchActionButtons() self.__updateSearchButton() + self.__updateSearchMoreButton(False) @pyqtSlot(str) def on_environmentsComboBox_currentTextChanged(self, name): @@ -795,6 +799,19 @@ self.__isPipAvailable() ) + def __updateSearchMoreButton(self, enable): + """ + Private method to update the state of the search more button. + + @param enable flag indicating the desired enable state + @type bool + """ + self.searchMoreButton.setEnabled( + enable and + bool(self.searchEditName.text()) and + self.__isPipAvailable() + ) + @pyqtSlot(bool) def on_searchToggleButton_toggled(self, checked): """ @@ -811,6 +828,7 @@ self.__updateSearchActionButtons() self.__updateSearchButton() + self.__updateSearchMoreButton(False) @pyqtSlot(str) def on_searchEditName_textChanged(self, txt): @@ -831,14 +849,21 @@ bool(self.searchEditName.text()) and self.__isPipAvailable() ): - self.__search() + self.__searchFirst() @pyqtSlot() def on_searchButton_clicked(self): """ Private slot handling a press of the search button. """ - self.__search() + self.__searchFirst() + + @pyqtSlot() + def on_searchMoreButton_clicked(self): + """ + Private slot handling a press of the search more button. + """ + self.__search(self.__lastSearchPage + 1) @pyqtSlot() def on_searchResultList_itemSelectionChanged(self): @@ -847,19 +872,33 @@ """ self.__updateSearchActionButtons() - def __search(self): + def __searchFirst(self): """ - Private method to perform the search by calling the PyPI search URL. + Private method to perform the search for packages. """ self.searchResultList.clear() self.searchInfoLabel.clear() + self.__updateSearchMoreButton(False) + + self.__search() + + def __search(self, page=1): + """ + Private method to perform the search by calling the PyPI search URL. + + @param page search page to retrieve (defaults to 1) + @type int (optional) + """ + self.__lastSearchPage = page + self.searchButton.setEnabled(False) searchTerm = self.searchEditName.text().strip() searchTerm = bytes(QUrl.toPercentEncoding(searchTerm)).decode() urlQuery = QUrlQuery() urlQuery.addQueryItem("q", searchTerm) + urlQuery.addQueryItem("page", str(page)) url = QUrl(self.__pip.getIndexUrlSearch()) url.setQuery(urlQuery) @@ -902,18 +941,39 @@ results = PypiSearchResultsParser(data).getResults() if results: + # PyPI returns max. 20 entries per page if len(results) < 20: - msg = self.tr("%n package(s) found.", "", len(results)) + msg = self.tr("%n package(s) found.", "", + (self.__lastSearchPage - 1) * 20 + len(results)) + self.__updateSearchMoreButton(False) else: - msg = self.tr("Showing first 20 packages found.") + msg = self.tr("Showing first {0} packages found.").format( + self.__lastSearchPage * 20) + self.__updateSearchMoreButton(True) self.searchInfoLabel.setText(msg) + lastItem = self.searchResultList.topLevelItem( + self.searchResultList.topLevelItemCount() - 1) else: - EricMessageBox.warning( - self, - self.tr("Search PyPI"), - self.tr("""<p>There were no results for <b>{0}</b>.</p>""")) - self.searchInfoLabel.setText( - self.tr("""<p>There were no results for <b>{0}</b>.</p>""")) + self.__updateSearchMoreButton(False) + if self.__lastSearchPage == 1: + EricMessageBox.warning( + self, + self.tr("Search PyPI"), + self.tr("""<p>There were no results for <b>{0}</b>.</p>""") + .format(searchTerm) + ) + self.searchInfoLabel.setText( + self.tr("""<p>There were no results for <b>{0}</b>.</p>""") + .format(searchTerm) + ) + else: + EricMessageBox.warning( + self, + self.tr("Search PyPI"), + self.tr("""<p>There were no more results for""" + """ <b>{0}</b>.</p>""").format(searchTerm) + ) + lastItem = None wrapper = textwrap.TextWrapper(width=80) for result in results: @@ -933,6 +993,11 @@ ]) itm.setData(0, self.SearchVersionRole, result['version']) + if lastItem: + self.searchResultList.scrollToItem( + lastItem, + QAbstractItemView.ScrollHint.PositionAtTop) + header = self.searchResultList.header() header.setStretchLastSection(False) header.resizeSections(QHeaderView.ResizeMode.ResizeToContents)