1# -*- coding: utf-8 -*-
2
3# Copyright (c) 2020 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4#
5
6"""
7Module implementing a dialog to show information about the installation.
8"""
9
10import json
11import os
12
13from PyQt5.QtCore import pyqtSlot
14from PyQt5.QtWidgets import QDialog, QDialogButtonBox
15
16from E5Gui import E5MessageBox
17
18from .Ui_InstallInfoDialog import Ui_InstallInfoDialog
19
20import Globals
21import UI.PixmapCache
22
23
24class InstallInfoDialog(QDialog, Ui_InstallInfoDialog):
25    """
26    Class implementing a dialog to show information about the installation.
27    """
28    def __init__(self, parent=None):
29        """
30        Constructor
31
32        @param parent reference to the parent widget
33        @type QWidget
34        """
35        super().__init__(parent)
36        self.setupUi(self)
37
38        self.__deleteButton = self.buttonBox.addButton(
39            self.tr("Delete Info"), QDialogButtonBox.ButtonRole.ActionRole)
40        self.__deleteButton.clicked.connect(self.on_deleteButton_clicked)
41        self.__updateButton = self.buttonBox.addButton(
42            self.tr("Upgrade Instructions"),
43            QDialogButtonBox.ButtonRole.ActionRole)
44        self.__updateButton.clicked.connect(self.on_updateButton_clicked)
45
46        self.__edited = False
47        self.__loaded = True
48
49        self.editButton.setIcon(UI.PixmapCache.getIcon("infoEdit"))
50        self.saveButton.setIcon(UI.PixmapCache.getIcon("fileSave"))
51
52        infoFileName = Globals.getInstallInfoFilePath()
53
54        self.__deleteButton.setEnabled(os.path.exists(infoFileName))
55
56        try:
57            with open(infoFileName, "r") as infoFile:
58                self.__info = json.load(infoFile)
59
60            if Globals.isWindowsPlatform():
61                self.sudoLabel1.setText(self.tr("Installed as Administrator:"))
62            else:
63                self.sudoLabel1.setText(self.tr("Installed with sudo:"))
64            self.sudoLabel2.setText(
65                self.tr("Yes") if self.__info["sudo"] else self.tr("No"))
66            self.userLabel.setText(self.__info["user"])
67            self.installedFromEdit.setText(self.__info["install_cwd"])
68            self.interpreteEdit.setText(self.__info["exe"])
69            self.commandEdit.setText(self.__info["argv"])
70            self.installPathEdit.setText(self.__info["eric"])
71            self.virtenvLabel.setText(
72                self.tr("Yes") if self.__info["virtualenv"] else self.tr("No"))
73            self.remarksEdit.setPlainText(self.__info["remarks"])
74            if self.__info["pip"]:
75                self.pipLabel.setText(self.tr(
76                    "'eric-ide' was installed from PyPI using the pip"
77                    " command."))
78            else:
79                self.pipLabel.hide()
80            if self.__info["guessed"]:
81                self.guessLabel.setText(self.tr(
82                    "The information shown in this dialog was guessed at"
83                    " the first start of eric."))
84            else:
85                self.guessLabel.hide()
86            if self.__info["edited"]:
87                self.userProvidedLabel.setText(self.tr(
88                    "The installation information was provided by the user."
89                ))
90            else:
91                self.userProvidedLabel.hide()
92            if self.__info["installed_on"]:
93                self.installDateTimeLabel.setText(
94                    self.__info["installed_on"] if self.__info["installed_on"]
95                    else self.tr("unknown"))
96
97            self.__updateButton.setEnabled(bool(self.__info["exe"]))
98        except OSError as err:
99            E5MessageBox.critical(
100                self,
101                self.tr("Load Install Information"),
102                self.tr("<p>The file containing the install information could"
103                        " not be read.</p><p>Reason: {0}</p>""")
104                .format(str(err))
105            )
106            self.__loaded = False
107            self.__info = {}
108
109            self.__updateButton.setEnabled(False)
110
111    def wasLoaded(self):
112        """
113        Public method to check, if the install data was loaded.
114
115        @return flag indicating the data was loaded
116        @rtype bool
117        """
118        return self.__loaded
119
120    @pyqtSlot(bool)
121    def on_editButton_toggled(self, checked):
122        """
123        Private slot to switch the dialog into edit mode.
124
125        @param checked flag giving the button check state
126        @type bool
127        """
128        self.installedFromEdit.setReadOnly(not checked)
129        self.interpreteEdit.setReadOnly(not checked)
130        self.commandEdit.setReadOnly(not checked)
131        self.installPathEdit.setReadOnly(not checked)
132        self.remarksEdit.setReadOnly(not checked)
133
134        if checked:
135            self.__edited = True
136
137    @pyqtSlot()
138    def on_saveButton_clicked(self):
139        """
140        Private slot handling the save button press.
141        """
142        if self.__edited:
143            self.__saveData()
144
145    @pyqtSlot()
146    def reject(self):
147        """
148        Public slot handling the closing of the dialog.
149        """
150        if self.__edited:
151            yes = E5MessageBox.yesNo(
152                self,
153                self.tr("Install Information"),
154                self.tr("""The install information was edited. Unsaved"""
155                        """ changes will be lost. Save first?"""),
156                yesDefault=True)
157            if yes:
158                self.__saveData()
159
160        super().reject()
161
162    def __saveData(self):
163        """
164        Private method to save the data.
165        """
166        if self.installedFromEdit.text() != self.__info["install_cwd"]:
167            self.__info["install_cwd"] = self.installedFromEdit.text()
168            self.__info["install_cwd_edited"] = True
169        if self.interpreteEdit.text() != self.__info["exe"]:
170            self.__info["exe"] = self.interpreteEdit.text()
171            self.__info["exe_edited"] = True
172        if self.commandEdit.text() != self.__info["argv"]:
173            self.__info["argv"] = self.commandEdit.text()
174            self.__info["argv_edited"] = True
175        if self.installPathEdit.text() != self.__info["eric"]:
176            self.__info["eric"] = self.installPathEdit.text()
177            self.__info["eric_edited"] = True
178        self.__info["remarks"] = self.remarksEdit.toPlainText()
179        self.__info["edited"] = True
180
181        infoFileName = Globals.getInstallInfoFilePath()
182        try:
183            with open(infoFileName, "w") as infoFile:
184                json.dump(self.__info, infoFile, indent=2)
185            self.__edited = False
186            self.editButton.setChecked(False)
187        except OSError as err:
188            E5MessageBox.critical(
189                self,
190                self.tr("Save Install Information"),
191                self.tr("<p>The file containing the install information could"
192                        " not be written.</p><p>Reason: {0}</p>""")
193                .format(str(err))
194            )
195
196    @pyqtSlot()
197    def on_deleteButton_clicked(self):
198        """
199        Private slot deleting the install information file.
200        """
201        res = E5MessageBox.yesNo(
202            self,
203            self.tr("Delete Installation Information"),
204            self.tr("""Do you really want to delete the installation"""
205                    """ information? It will be recreated at the next"""
206                    """ start."""))
207        if not res:
208            return
209
210        infoFileName = Globals.getInstallInfoFilePath()
211        os.remove(infoFileName)
212
213        # local data will be deleted automatically
214        self.__edited = False
215
216        self.close()
217
218    @pyqtSlot()
219    def on_updateButton_clicked(self):
220        """
221        Private slot to show some upgrade instructions.
222        """
223        updateTextList = []
224        cmdPrefix = ""
225
226        if self.__info["sudo"]:
227            if Globals.isWindowsPlatform():
228                updateTextList.append(
229                    self.tr("Perform the following step(s) with Administrator"
230                            " privileges.\n"))
231            else:
232                cmdPrefix = "sudo "
233
234        if self.__info["pip"]:
235            updateTextList.append(
236                "{0}{1} -m pip install --upgrade eric-ide".format(
237                    cmdPrefix, self.__info["exe"],
238                )
239            )
240        else:
241            if (
242                "install_cwd" in self.__info and
243                bool(self.__info["install_cwd"])
244            ):
245                updateTextList.append(
246                    "cd {0}".format(self.__info["install_cwd"])
247                )
248            updateTextList.append(
249                "{0}{1} {2}".format(
250                    cmdPrefix, self.__info["exe"], self.__info["argv"],
251                )
252            )
253
254        from E5Gui.E5PlainTextDialog import E5PlainTextDialog
255        dlg = E5PlainTextDialog(
256            title=self.tr("Upgrade Instructions"),
257            text="\n".join(updateTextList))
258        dlg.exec()
259