eric7/UI/UserInterface.py

branch
eric7
changeset 8973
ad4848b7fd9b
parent 8972
54816b8f740f
child 8994
3bebd76dc6ea
equal deleted inserted replaced
8972:54816b8f740f 8973:ad4848b7fd9b
28 from PyQt6.QtWidgets import ( 28 from PyQt6.QtWidgets import (
29 QSizePolicy, QWidget, QWhatsThis, QToolBar, QDialog, QSplitter, 29 QSizePolicy, QWidget, QWhatsThis, QToolBar, QDialog, QSplitter,
30 QApplication, QMenu, QVBoxLayout, QDockWidget, QLabel 30 QApplication, QMenu, QVBoxLayout, QDockWidget, QLabel
31 ) 31 )
32 from PyQt6.Qsci import QSCINTILLA_VERSION_STR 32 from PyQt6.Qsci import QSCINTILLA_VERSION_STR
33 from PyQt6.QtNetwork import ( 33 from PyQt6.QtNetwork import QNetworkProxyFactory, QNetworkAccessManager
34 QNetworkProxyFactory, QNetworkAccessManager, QNetworkRequest, QNetworkReply
35 )
36 34
37 from .Info import Version, VersionOnly, BugAddress, Program, FeatureAddress 35 from .Info import Version, VersionOnly, BugAddress, Program, FeatureAddress
38 from . import Config 36 from . import Config
39 from .NotificationWidget import NotificationTypes 37 from .NotificationWidget import NotificationTypes
40 38
43 from EricWidgets.EricToolBarManager import EricToolBarManager 41 from EricWidgets.EricToolBarManager import EricToolBarManager
44 from EricWidgets import EricMessageBox, EricFileDialog, EricErrorMessage 42 from EricWidgets import EricMessageBox, EricFileDialog, EricErrorMessage
45 from EricWidgets.EricApplication import ericApp 43 from EricWidgets.EricApplication import ericApp
46 from EricWidgets.EricMainWindow import EricMainWindow 44 from EricWidgets.EricMainWindow import EricMainWindow
47 from EricWidgets.EricZoomWidget import EricZoomWidget 45 from EricWidgets.EricZoomWidget import EricZoomWidget
48 from EricWidgets.EricProgressDialog import EricProgressDialog
49 from EricWidgets.EricClickableLabel import EricClickableLabel 46 from EricWidgets.EricClickableLabel import EricClickableLabel
50 47
51 import Preferences 48 import Preferences
52 import Utilities 49 import Utilities
53 import Globals 50 import Globals
628 if self.microPythonWidget is not None: 625 if self.microPythonWidget is not None:
629 ericApp().registerObject("MicroPython", self.microPythonWidget) 626 ericApp().registerObject("MicroPython", self.microPythonWidget)
630 ericApp().registerObject("JediAssistant", self.jediAssistant) 627 ericApp().registerObject("JediAssistant", self.jediAssistant)
631 ericApp().registerObject("PluginRepositoryViewer", 628 ericApp().registerObject("PluginRepositoryViewer",
632 self.pluginRepositoryViewer) 629 self.pluginRepositoryViewer)
633
634 # list of web addresses serving the versions file
635 self.__httpAlternatives = Preferences.getUI("VersionsUrls7")
636 self.__inVersionCheck = False
637 self.__versionCheckProgress = None
638 630
639 # create the various JSON file interfaces 631 # create the various JSON file interfaces
640 self.__sessionFile = SessionFile(True) 632 self.__sessionFile = SessionFile(True)
641 self.__tasksFile = TasksFile(True) 633 self.__tasksFile = TasksFile(True)
642 634
6616 if fn: 6608 if fn:
6617 self.__setWindowCaption(editor=fn) 6609 self.__setWindowCaption(editor=fn)
6618 else: 6610 else:
6619 self.__setWindowCaption(editor="") 6611 self.__setWindowCaption(editor="")
6620 6612
6621 self.__httpAlternatives = Preferences.getUI("VersionsUrls7") 6613 self.performVersionCheck()
6622 self.performVersionCheck(False)
6623 6614
6624 from QScintilla.SpellChecker import SpellChecker 6615 from QScintilla.SpellChecker import SpellChecker
6625 SpellChecker.setDefaultLanguage( 6616 SpellChecker.setDefaultLanguage(
6626 Preferences.getEditor("SpellCheckingDefaultLanguage")) 6617 Preferences.getEditor("SpellCheckingDefaultLanguage"))
6627 6618
7555 7546
7556 @param online flag indicating the online state 7547 @param online flag indicating the online state
7557 @type bool 7548 @type bool
7558 """ 7549 """
7559 if online: 7550 if online:
7560 self.performVersionCheck(False) 7551 self.performVersionCheck()
7561 7552
7562 ############################################## 7553 ##############################################
7563 ## Below are methods to check for new versions 7554 ## Below are methods to check for new versions
7564 ############################################## 7555 ##############################################
7565 7556
7566 # TODO: change performVersionCheck to check against PyPI and do that 7557 def performVersionCheck(self):
7567 # only for the automatic check 7558 """
7568 @pyqtSlot() 7559 Public method to check for an update even if not installed via PyPI.
7569 def performVersionCheck(self, manual=True, alternative=0,
7570 showVersions=False):
7571 """
7572 Public method to check the internet for an eric update.
7573
7574 @param manual flag indicating an invocation via the menu (boolean)
7575 @param alternative index of server to download from (integer)
7576 @param showVersions flag indicating the show versions mode (boolean)
7577 """ 7560 """
7578 if self.isOnline(): 7561 if self.isOnline():
7579 if not manual: 7562 if VersionOnly.startswith(("rev_", "@@")):
7580 if VersionOnly.startswith("@@"): 7563 # cannot check against development or source installation
7581 return
7582 else:
7583 period = Preferences.getUI("PerformVersionCheck")
7584 if period == 0:
7585 return
7586 elif period in [2, 3, 4]:
7587 lastCheck = Preferences.getSettings().value(
7588 "Updates/LastCheckDate", QDate(1970, 1, 1))
7589 if lastCheck.isValid():
7590 now = QDate.currentDate()
7591 if (
7592 (period == 2 and
7593 lastCheck.day() == now.day()) or
7594 (period == 3 and lastCheck.daysTo(now) < 7) or
7595 (period == 4 and (lastCheck.daysTo(now) <
7596 lastCheck.daysInMonth()))
7597 ):
7598 # daily, weekly, monthly
7599 return
7600
7601 self.__inVersionCheck = True
7602 self.manualUpdatesCheck = manual
7603 self.showAvailableVersions = showVersions
7604 self.httpAlternative = alternative
7605 url = QUrl(self.__httpAlternatives[alternative])
7606 self.__versionCheckCanceled = False
7607 if manual:
7608 if self.__versionCheckProgress is None:
7609 self.__versionCheckProgress = EricProgressDialog(
7610 "", self.tr("&Cancel"),
7611 0, len(self.__httpAlternatives),
7612 self.tr("%v/%m"), self)
7613 self.__versionCheckProgress.setWindowTitle(
7614 self.tr("Version Check"))
7615 self.__versionCheckProgress.setMinimumDuration(0)
7616 self.__versionCheckProgress.canceled.connect(
7617 self.__versionsDownloadCanceled)
7618 self.__versionCheckProgress.setLabelText(
7619 self.tr("Trying host {0}").format(url.host()))
7620 self.__versionCheckProgress.setValue(alternative)
7621 request = QNetworkRequest(url)
7622 request.setAttribute(
7623 QNetworkRequest.Attribute.CacheLoadControlAttribute,
7624 QNetworkRequest.CacheLoadControl.AlwaysNetwork)
7625 reply = self.__networkManager.get(request)
7626 reply.finished.connect(lambda: self.__versionsDownloadDone(reply))
7627 self.__replies.append(reply)
7628 else:
7629 if manual:
7630 EricMessageBox.warning(
7631 self,
7632 self.tr("Error getting versions information"),
7633 self.tr("The versions information cannot not be"
7634 " downloaded because the Internet is"
7635 " <b>not reachable</b>. Please try again later.")
7636 )
7637
7638 @pyqtSlot()
7639 def __versionsDownloadDone(self, reply):
7640 """
7641 Private slot called, after the versions file has been downloaded
7642 from the internet.
7643
7644 @param reply reference to the network reply
7645 @type QNetworkReply
7646 """
7647 if self.__versionCheckCanceled:
7648 self.__inVersionCheck = False
7649 if self.__versionCheckProgress is not None:
7650 self.__versionCheckProgress.reset()
7651 self.__versionCheckProgress = None
7652 return
7653
7654 reply.deleteLater()
7655 if reply in self.__replies:
7656 self.__replies.remove(reply)
7657 if reply.error() == QNetworkReply.NetworkError.NoError:
7658 ioEncoding = Preferences.getSystem("IOEncoding")
7659 versions = str(reply.readAll(), ioEncoding, 'replace').splitlines()
7660 reply.close()
7661 if (
7662 reply.error() != QNetworkReply.NetworkError.NoError or
7663 len(versions) == 0 or
7664 versions[0].startswith("<")
7665 ):
7666 # network error or an error page
7667 self.httpAlternative += 1
7668 if self.httpAlternative >= len(self.__httpAlternatives):
7669 self.__inVersionCheck = False
7670 if self.__versionCheckProgress is not None:
7671 self.__versionCheckProgress.reset()
7672 self.__versionCheckProgress = None
7673 firstFailure = Preferences.getSettings().value(
7674 "Updates/FirstFailedCheckDate", QDate.currentDate())
7675 failedDuration = firstFailure.daysTo(QDate.currentDate())
7676 Preferences.getSettings().setValue(
7677 "Updates/FirstFailedCheckDate", firstFailure)
7678 if self.manualUpdatesCheck:
7679 EricMessageBox.warning(
7680 self,
7681 self.tr("Error getting versions information"),
7682 self.tr("""The versions information could not be"""
7683 """ downloaded."""
7684 """ Please go online and try again."""))
7685 elif failedDuration > 7:
7686 EricMessageBox.warning(
7687 self,
7688 self.tr("Error getting versions information"),
7689 self.tr("""The versions information could not be"""
7690 """ downloaded for the last 7 days."""
7691 """ Please go online and try again."""))
7692 return 7564 return
7693 else: 7565 else:
7694 self.performVersionCheck(self.manualUpdatesCheck, 7566 period = Preferences.getUI("PerformVersionCheck")
7695 self.httpAlternative, 7567 if period == 0:
7696 self.showAvailableVersions) 7568 return
7697 return 7569 elif period in [2, 3, 4]:
7698 7570 lastCheck = Preferences.getSettings().value(
7699 self.__inVersionCheck = False 7571 "Updates/LastCheckDate", QDate(1970, 1, 1))
7700 if self.__versionCheckProgress is not None: 7572 if lastCheck.isValid():
7701 self.__versionCheckProgress.reset() 7573 now = QDate.currentDate()
7702 self.__versionCheckProgress = None 7574 if (
7703 self.__updateVersionsUrls(versions) 7575 (period == 2 and
7704 if self.showAvailableVersions: 7576 lastCheck.day() == now.day()) or
7705 self.__showAvailableVersionInfos(versions) 7577 (period == 3 and lastCheck.daysTo(now) < 7) or
7706 else: 7578 (period == 4 and (lastCheck.daysTo(now) <
7707 Preferences.getSettings().remove("Updates/FirstFailedCheckDate") 7579 lastCheck.daysInMonth()))
7708 Preferences.getSettings().setValue( 7580 ):
7709 "Updates/LastCheckDate", QDate.currentDate()) 7581 # daily, weekly, monthly
7710 self.__versionCheckResult(versions) 7582 return
7711
7712 def __updateVersionsUrls(self, versions):
7713 """
7714 Private method to update the URLs from which to retrieve the versions
7715 file.
7716
7717 @param versions contents of the downloaded versions file (list of
7718 strings)
7719 """
7720 if len(versions) > 5 and versions[4] == "---":
7721 line = 5
7722 urls = []
7723 while line < len(versions):
7724 urls.append(versions[line])
7725 line += 1
7726 7583
7727 Preferences.setUI("VersionsUrls7", urls) 7584 availableVersions = (
7728 7585 self.pipInterface.getPackageVersions("eric-ide")
7729 def __versionCheckResult(self, versions): 7586 )
7730 """ 7587 updateAvailable = bool(v for v in availableVersions
7731 Private method to show the result of the version check action. 7588 if v > VersionOnly)
7732 7589 if updateAvailable:
7733 @param versions contents of the downloaded versions file (list of 7590 EricMessageBox.information(
7734 strings) 7591 self,
7735 """ 7592 self.tr("Upgrade available"),
7736 url = "" 7593 self.tr(
7737 try: 7594 """A newer version of the <b>eric-ide</b> package is"""
7738 if "snapshot-" in VersionOnly: 7595 """ available at <a href="{0}/eric-ide/">"""
7739 # check snapshot version like snapshot-20170810 7596 """PyPI</a>."""
7740 if "snapshot-" in versions[2]: 7597 ).format(self.pipInterface.getIndexUrlPypi())
7741 installedSnapshotDate = VersionOnly.rsplit("-", 1)[-1] 7598 )
7742 availableSnapshotDate = versions[2].rsplit("-", 1)[-1] 7599
7743 if availableSnapshotDate > installedSnapshotDate:
7744 res = EricMessageBox.yesNo(
7745 self,
7746 self.tr("Update available"),
7747 self.tr(
7748 """The update to <b>{0}</b> of eric is"""
7749 """ available at <b>{1}</b>. Would you like"""
7750 """ to get it?""")
7751 .format(versions[2], versions[3]),
7752 yesDefault=True)
7753 url = res and versions[3] or ''
7754 else:
7755 if self.manualUpdatesCheck:
7756 EricMessageBox.information(
7757 self,
7758 self.tr("Update Check"),
7759 self.tr(
7760 """You are using a snapshot release of"""
7761 """ eric. A more up-to-date stable release"""
7762 """ might be available."""))
7763 elif VersionOnly.startswith(("rev_", "@@")):
7764 # check installation from source
7765 if self.manualUpdatesCheck:
7766 EricMessageBox.information(
7767 self,
7768 self.tr("Update Check"),
7769 self.tr(
7770 """You installed eric directly from the source"""
7771 """ code. There is no possibility to check"""
7772 """ for the availability of an update."""))
7773 else:
7774 # check release version
7775 installedVersionTuple = self.__versionToTuple(VersionOnly)
7776 availableVersionTuple = self.__versionToTuple(versions[0])
7777 if availableVersionTuple > installedVersionTuple:
7778 res = EricMessageBox.yesNo(
7779 self,
7780 self.tr("Update available"),
7781 self.tr(
7782 """The update to <b>{0}</b> of eric is"""
7783 """ available at <b>{1}</b>. Would you like"""
7784 """ to get it?""")
7785 .format(versions[0], versions[1]),
7786 yesDefault=True)
7787 url = res and versions[1] or ''
7788 else:
7789 if self.manualUpdatesCheck:
7790 EricMessageBox.information(
7791 self,
7792 self.tr("eric is up to date"),
7793 self.tr(
7794 """You are using the latest version of"""
7795 """ eric"""))
7796 except (IndexError, TypeError):
7797 EricMessageBox.warning(
7798 self,
7799 self.tr("Error during updates check"),
7800 self.tr("""Could not perform updates check."""))
7801
7802 if url:
7803 QDesktopServices.openUrl(QUrl(url))
7804
7805 @pyqtSlot()
7806 def __versionsDownloadCanceled(self):
7807 """
7808 Private slot called to cancel the version check.
7809 """
7810 if self.__replies:
7811 self.__versionCheckCanceled = True
7812 self.__replies[-1].abort()
7813
7814 def __showAvailableVersionInfos(self, versions):
7815 """
7816 Private method to show the versions available for download.
7817
7818 @param versions contents of the downloaded versions file (list of
7819 strings)
7820 """
7821 versionText = self.tr(
7822 """<h3>Available versions</h3>"""
7823 """<table>""")
7824 line = 0
7825 while line < len(versions):
7826 if versions[line] == "---":
7827 break
7828
7829 versionText += (
7830 """<tr><td>{0}</td><td><a href="{1}">{2}</a></td></tr>"""
7831 ).format(
7832 versions[line], versions[line + 1],
7833 'sourceforge' in versions[line + 1] and
7834 "SourceForge" or versions[line + 1])
7835 line += 2
7836 versionText += self.tr("""</table>""")
7837
7838 self.__versionsDialog = EricMessageBox.EricMessageBox(
7839 EricMessageBox.NoIcon,
7840 Program,
7841 versionText,
7842 modal=False,
7843 buttons=EricMessageBox.Ok,
7844 parent=self
7845 )
7846 self.__versionsDialog.setIconPixmap(
7847 UI.PixmapCache.getPixmap("eric").scaled(64, 64))
7848 self.__versionsDialog.show()
7849
7850 def __sslErrors(self, reply, errors): 7600 def __sslErrors(self, reply, errors):
7851 """ 7601 """
7852 Private slot to handle SSL errors. 7602 Private slot to handle SSL errors.
7853 7603
7854 @param reply reference to the reply object (QNetworkReply) 7604 @param reply reference to the reply object (QNetworkReply)

eric ide

mercurial