eric7/PipInterface/PipPackagesWidget.py

branch
eric7
changeset 9000
bc0b38405b6a
parent 8999
723f61499a79
child 9001
a00cd6b55728
equal deleted inserted replaced
8999:723f61499a79 9000:bc0b38405b6a
17 from PyQt6.QtCore import pyqtSlot, Qt, QUrl, QUrlQuery 17 from PyQt6.QtCore import pyqtSlot, Qt, QUrl, QUrlQuery
18 from PyQt6.QtGui import QIcon 18 from PyQt6.QtGui import QIcon
19 from PyQt6.QtNetwork import QNetworkReply, QNetworkRequest 19 from PyQt6.QtNetwork import QNetworkReply, QNetworkRequest
20 from PyQt6.QtWidgets import ( 20 from PyQt6.QtWidgets import (
21 QWidget, QToolButton, QApplication, QHeaderView, QTreeWidgetItem, 21 QWidget, QToolButton, QApplication, QHeaderView, QTreeWidgetItem,
22 QMenu, QDialog 22 QMenu, QDialog, QAbstractItemView
23 ) 23 )
24 24
25 from EricWidgets.EricApplication import ericApp 25 from EricWidgets.EricApplication import ericApp
26 from EricWidgets import EricMessageBox 26 from EricWidgets import EricMessageBox
27 from EricGui.EricOverrideCursor import EricOverrideCursor 27 from EricGui.EricOverrideCursor import EricOverrideCursor
203 UI.PixmapCache.getIcon("info")) 203 UI.PixmapCache.getIcon("info"))
204 self.searchToggleButton.setIcon( 204 self.searchToggleButton.setIcon(
205 UI.PixmapCache.getIcon("find")) 205 UI.PixmapCache.getIcon("find"))
206 self.searchButton.setIcon( 206 self.searchButton.setIcon(
207 UI.PixmapCache.getIcon("findNext")) 207 UI.PixmapCache.getIcon("findNext"))
208 self.searchMoreButton.setIcon(
209 UI.PixmapCache.getIcon("plus"))
208 self.installButton.setIcon( 210 self.installButton.setIcon(
209 UI.PixmapCache.getIcon("plus")) 211 UI.PixmapCache.getIcon("plus"))
210 self.installUserSiteButton.setIcon( 212 self.installUserSiteButton.setIcon(
211 UI.PixmapCache.getIcon("addUser")) 213 UI.PixmapCache.getIcon("addUser"))
212 self.showDetailsButton.setIcon( 214 self.showDetailsButton.setIcon(
261 self.__updateActionButtons() 263 self.__updateActionButtons()
262 self.__updateDepActionButtons() 264 self.__updateDepActionButtons()
263 265
264 self.statusLabel.hide() 266 self.statusLabel.hide()
265 self.searchWidget.hide() 267 self.searchWidget.hide()
268 self.__lastSearchPage = 0
266 269
267 self.__queryName = [] 270 self.__queryName = []
268 self.__querySummary = [] 271 self.__querySummary = []
269 272
270 self.__replies = [] 273 self.__replies = []
473 self.statusLabel.hide() 476 self.statusLabel.hide()
474 477
475 self.__updateActionButtons() 478 self.__updateActionButtons()
476 self.__updateSearchActionButtons() 479 self.__updateSearchActionButtons()
477 self.__updateSearchButton() 480 self.__updateSearchButton()
481 self.__updateSearchMoreButton(False)
478 482
479 @pyqtSlot(str) 483 @pyqtSlot(str)
480 def on_environmentsComboBox_currentTextChanged(self, name): 484 def on_environmentsComboBox_currentTextChanged(self, name):
481 """ 485 """
482 Private slot handling the selection of a Python environment. 486 Private slot handling the selection of a Python environment.
793 self.searchButton.setEnabled( 797 self.searchButton.setEnabled(
794 bool(self.searchEditName.text()) and 798 bool(self.searchEditName.text()) and
795 self.__isPipAvailable() 799 self.__isPipAvailable()
796 ) 800 )
797 801
802 def __updateSearchMoreButton(self, enable):
803 """
804 Private method to update the state of the search more button.
805
806 @param enable flag indicating the desired enable state
807 @type bool
808 """
809 self.searchMoreButton.setEnabled(
810 enable and
811 bool(self.searchEditName.text()) and
812 self.__isPipAvailable()
813 )
814
798 @pyqtSlot(bool) 815 @pyqtSlot(bool)
799 def on_searchToggleButton_toggled(self, checked): 816 def on_searchToggleButton_toggled(self, checked):
800 """ 817 """
801 Private slot to togle the search widget. 818 Private slot to togle the search widget.
802 819
809 self.searchEditName.setFocus(Qt.FocusReason.OtherFocusReason) 826 self.searchEditName.setFocus(Qt.FocusReason.OtherFocusReason)
810 self.searchEditName.selectAll() 827 self.searchEditName.selectAll()
811 828
812 self.__updateSearchActionButtons() 829 self.__updateSearchActionButtons()
813 self.__updateSearchButton() 830 self.__updateSearchButton()
831 self.__updateSearchMoreButton(False)
814 832
815 @pyqtSlot(str) 833 @pyqtSlot(str)
816 def on_searchEditName_textChanged(self, txt): 834 def on_searchEditName_textChanged(self, txt):
817 """ 835 """
818 Private slot handling a change of the search term. 836 Private slot handling a change of the search term.
829 """ 847 """
830 if ( 848 if (
831 bool(self.searchEditName.text()) and 849 bool(self.searchEditName.text()) and
832 self.__isPipAvailable() 850 self.__isPipAvailable()
833 ): 851 ):
834 self.__search() 852 self.__searchFirst()
835 853
836 @pyqtSlot() 854 @pyqtSlot()
837 def on_searchButton_clicked(self): 855 def on_searchButton_clicked(self):
838 """ 856 """
839 Private slot handling a press of the search button. 857 Private slot handling a press of the search button.
840 """ 858 """
841 self.__search() 859 self.__searchFirst()
860
861 @pyqtSlot()
862 def on_searchMoreButton_clicked(self):
863 """
864 Private slot handling a press of the search more button.
865 """
866 self.__search(self.__lastSearchPage + 1)
842 867
843 @pyqtSlot() 868 @pyqtSlot()
844 def on_searchResultList_itemSelectionChanged(self): 869 def on_searchResultList_itemSelectionChanged(self):
845 """ 870 """
846 Private slot handling changes of the search result selection. 871 Private slot handling changes of the search result selection.
847 """ 872 """
848 self.__updateSearchActionButtons() 873 self.__updateSearchActionButtons()
849 874
850 def __search(self): 875 def __searchFirst(self):
851 """ 876 """
852 Private method to perform the search by calling the PyPI search URL. 877 Private method to perform the search for packages.
853 """ 878 """
854 self.searchResultList.clear() 879 self.searchResultList.clear()
855 self.searchInfoLabel.clear() 880 self.searchInfoLabel.clear()
881
882 self.__updateSearchMoreButton(False)
883
884 self.__search()
885
886 def __search(self, page=1):
887 """
888 Private method to perform the search by calling the PyPI search URL.
889
890 @param page search page to retrieve (defaults to 1)
891 @type int (optional)
892 """
893 self.__lastSearchPage = page
856 894
857 self.searchButton.setEnabled(False) 895 self.searchButton.setEnabled(False)
858 896
859 searchTerm = self.searchEditName.text().strip() 897 searchTerm = self.searchEditName.text().strip()
860 searchTerm = bytes(QUrl.toPercentEncoding(searchTerm)).decode() 898 searchTerm = bytes(QUrl.toPercentEncoding(searchTerm)).decode()
861 urlQuery = QUrlQuery() 899 urlQuery = QUrlQuery()
862 urlQuery.addQueryItem("q", searchTerm) 900 urlQuery.addQueryItem("q", searchTerm)
901 urlQuery.addQueryItem("page", str(page))
863 url = QUrl(self.__pip.getIndexUrlSearch()) 902 url = QUrl(self.__pip.getIndexUrlSearch())
864 url.setQuery(urlQuery) 903 url.setQuery(urlQuery)
865 904
866 request = QNetworkRequest(QUrl(url)) 905 request = QNetworkRequest(QUrl(url))
867 request.setAttribute( 906 request.setAttribute(
900 data = bytes(reply.readAll()).decode() 939 data = bytes(reply.readAll()).decode()
901 reply.deleteLater() 940 reply.deleteLater()
902 941
903 results = PypiSearchResultsParser(data).getResults() 942 results = PypiSearchResultsParser(data).getResults()
904 if results: 943 if results:
944 # PyPI returns max. 20 entries per page
905 if len(results) < 20: 945 if len(results) < 20:
906 msg = self.tr("%n package(s) found.", "", len(results)) 946 msg = self.tr("%n package(s) found.", "",
947 (self.__lastSearchPage - 1) * 20 + len(results))
948 self.__updateSearchMoreButton(False)
907 else: 949 else:
908 msg = self.tr("Showing first 20 packages found.") 950 msg = self.tr("Showing first {0} packages found.").format(
951 self.__lastSearchPage * 20)
952 self.__updateSearchMoreButton(True)
909 self.searchInfoLabel.setText(msg) 953 self.searchInfoLabel.setText(msg)
954 lastItem = self.searchResultList.topLevelItem(
955 self.searchResultList.topLevelItemCount() - 1)
910 else: 956 else:
911 EricMessageBox.warning( 957 self.__updateSearchMoreButton(False)
912 self, 958 if self.__lastSearchPage == 1:
913 self.tr("Search PyPI"), 959 EricMessageBox.warning(
914 self.tr("""<p>There were no results for <b>{0}</b>.</p>""")) 960 self,
915 self.searchInfoLabel.setText( 961 self.tr("Search PyPI"),
916 self.tr("""<p>There were no results for <b>{0}</b>.</p>""")) 962 self.tr("""<p>There were no results for <b>{0}</b>.</p>""")
963 .format(searchTerm)
964 )
965 self.searchInfoLabel.setText(
966 self.tr("""<p>There were no results for <b>{0}</b>.</p>""")
967 .format(searchTerm)
968 )
969 else:
970 EricMessageBox.warning(
971 self,
972 self.tr("Search PyPI"),
973 self.tr("""<p>There were no more results for"""
974 """ <b>{0}</b>.</p>""").format(searchTerm)
975 )
976 lastItem = None
917 977
918 wrapper = textwrap.TextWrapper(width=80) 978 wrapper = textwrap.TextWrapper(width=80)
919 for result in results: 979 for result in results:
920 try: 980 try:
921 description = "\n".join([ 981 description = "\n".join([
930 result['version'], 990 result['version'],
931 result["released"].strip(), 991 result["released"].strip(),
932 description, 992 description,
933 ]) 993 ])
934 itm.setData(0, self.SearchVersionRole, result['version']) 994 itm.setData(0, self.SearchVersionRole, result['version'])
995
996 if lastItem:
997 self.searchResultList.scrollToItem(
998 lastItem,
999 QAbstractItemView.ScrollHint.PositionAtTop)
935 1000
936 header = self.searchResultList.header() 1001 header = self.searchResultList.header()
937 header.setStretchLastSection(False) 1002 header.setStretchLastSection(False)
938 header.resizeSections(QHeaderView.ResizeMode.ResizeToContents) 1003 header.resizeSections(QHeaderView.ResizeMode.ResizeToContents)
939 headerSize = 0 1004 headerSize = 0

eric ide

mercurial