From 07db3bf724044c1f93702ce58d5b91abbd44a1a3 Mon Sep 17 00:00:00 2001
From: gfdgd_xi <3025613752@qq.com>
Date: Sat, 23 Dec 2023 12:24:20 +0800
Subject: [PATCH] Have finished log report maker

---
 DefaultSetting.py                   | 132 ++++++++++++++++++++++++++--
 Makefile                            |   1 +
 Resources/LogTemplate/template.html |  10 ++-
 mainwindow.py                       |  49 +++++++----
 wine/installwine                    |   2 +-
 5 files changed, 168 insertions(+), 26 deletions(-)

diff --git a/DefaultSetting.py b/DefaultSetting.py
index 4ee759d..b58f1b4 100644
--- a/DefaultSetting.py
+++ b/DefaultSetting.py
@@ -1,6 +1,7 @@
 #!/usr/bin/env python3
 # 读取设置单独用一个 py 文件
 import os
+import sys
 import json
 import base64
 import shutil
@@ -8,7 +9,10 @@ import getpass
 import datetime
 import traceback
 import subprocess
+import configparser
 import PyQt5.QtGui as QtGui
+import PyQt5.QtCore as QtCore
+import PyQt5.QtWidgets as QtWidgets
 
 # 获取用户主目录
 def get_home():
@@ -43,6 +47,7 @@ defultProgramList = {
 }
 
 programPath = os.path.split(os.path.realpath(__file__))[0]  # 返回 string
+iconPath = "{}/deepin-wine-runner.svg".format(programPath)
 try:
     setting = json.loads(readtxt(get_home() + "/.config/deepin-wine-runner/WineSetting.json"))
     information = json.loads(readtxt(f"{programPath}/information.json"))
@@ -92,7 +97,10 @@ def FileToBase64(filePath):
         src += base64Byte.decode("utf-8")
     return src
 
-class SaveLog():
+def SaveLogWindow():
+    pass
+
+class SaveLogReport():
     userName = getpass.getuser()
     time = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
     kernelVersion = subprocess.getoutput("uname -a")
@@ -103,9 +111,8 @@ class SaveLog():
     lshw = subprocess.getoutput("lshw")
     cpu = subprocess.getoutput("cat /proc/cpuinfo | grep 'model name' | head -n 1 | awk -F: '{print $2}'")
     gpu = subprocess.getoutput("lspci | grep -i 'VGA\|3D\|2D'")
-    
 
-    def __init__(self, chooseWineName, chooseWineCommand, runCommand, binPath, logOut, description, imgPath=[]) -> None:
+    def __init__(self, chooseWineName, chooseWineCommand, runCommand, binPath, logOut, description="无", imgPath=[]) -> None:
         self.chooseWineName = chooseWineName
         self.chooseWineCommand = chooseWineCommand
         self.runCommand = runCommand
@@ -138,12 +145,104 @@ class SaveLog():
         except:
             traceback.print_exc()
             self.memoryInfo = traceback.format_exc()
+        # 读取系统信息
+        try:
+            with open("/etc/os-release", "r") as file:
+                text = "[Default]\n" + file.read()
+            conf = configparser.ConfigParser()
+            conf.read_string(text)
+            self.systemVersion = conf.get("Default", "PRETTY_NAME")
+        except:
+            traceback.print_exc()
+            self.systemVersion = subprocess.getoutput("lsb_release -a")
+
+    def SetWindow(self):
+        def AddImageToListClicked():
+            choose = QtWidgets.QFileDialog.getOpenFileNames(messagebox, "选择图像", get_home(), "图片文件(*.png *.jpg *.bmp *.gif *.svg);;所有文件(*.*)")
+            print(choose)
+            for i in choose[0]:
+                if i in imageList:
+                    continue
+                imageList.append(i)
+            nmodel = QtGui.QStandardItemModel(messagebox)
+            for i in imageList:
+                item = QtGui.QStandardItem(i)
+                nmodel.appendRow(item)
+            imageListView.setModel(nmodel)
+
+        def DeleteImageToListClicked():
+            index = imageListView.currentIndex().row()
+            if index < 0:
+                QtWidgets.QMessageBox.information(messagebox, "提示", "您未选择任何项")
+                return
+            del imageList[index]
+            nmodel = QtGui.QStandardItemModel(messagebox)
+            for i in imageList:
+                item = QtGui.QStandardItem(i)
+                nmodel.appendRow(item)
+            imageListView.setModel(nmodel)
+            # 选择第一项
+            imageListView.setCurrentIndex(nmodel.index(0, 0))
+
+        def OkClicked():
+            self.description = description.toPlainText()
+            self.imgPath = imageList
+            path = QtWidgets.QFileDialog.getSaveFileName(messagebox, "保存日志报告", get_home(), "7z 文件(*.7z);;所有文件(*.*)")
+            print(path)
+            if path[0] != "":
+                try:
+                    self.To7z(path[0])
+                except:
+                    traceback.print_exc()
+                    QtWidgets.QMessageBox.critical(messagebox, "错误", traceback.format_exc())
+                    return
+                messagebox.close()
+                QtWidgets.QMessageBox.information(messagebox, "提示", "生成完成!")
+
+        def CancelClicked():
+            messagebox.close()
+
+        # 权重
+        size = QtWidgets.QSizePolicy()
+        size.setHorizontalPolicy(0)
+        imageList = []
+        messagebox = QtWidgets.QDialog()
+        layout = QtWidgets.QGridLayout()
+        description = QtWidgets.QTextEdit()
+        imageListView = QtWidgets.QListView()
+        addImageToList = QtWidgets.QPushButton("+")
+        deleteImageToList = QtWidgets.QPushButton("-")
+        controlLayout = QtWidgets.QHBoxLayout()
+        ok = QtWidgets.QPushButton("保存")
+        cancel = QtWidgets.QPushButton("取消")
+        description.setPlaceholderText("可以填写故障的现象、复现步骤以及其他有关的信息,同时也可以填写联系方式")
+        addImageToList.clicked.connect(AddImageToListClicked)
+        deleteImageToList.clicked.connect(DeleteImageToListClicked)
+        ok.clicked.connect(OkClicked)
+        cancel.clicked.connect(CancelClicked)
+        addImageToList.setSizePolicy(size)
+        deleteImageToList.setSizePolicy(size)
+        ok.setSizePolicy(size)
+        cancel.setSizePolicy(size)
+        layout.addWidget(QtWidgets.QLabel("<h2>描述(建议填写)</h2>"), 0, 0)
+        layout.addWidget(description, 1, 0, 1, 3)
+        layout.addWidget(QtWidgets.QLabel("<hr>"), 2, 0, 1, 4)
+        layout.addWidget(QtWidgets.QLabel("<h2>截图(建议选择)</h2>"), 3, 0)
+        layout.addWidget(imageListView, 4, 0, 4, 3)
+        layout.addWidget(addImageToList, 5, 3)
+        layout.addWidget(deleteImageToList, 6, 3)
+        layout.addLayout(controlLayout, 8, 2, 1, 2)
+        controlLayout.addWidget(cancel)
+        controlLayout.addWidget(ok)
+        messagebox.setLayout(layout)
+        messagebox.exec_()
 
     def To7z(self, savePath):
         os.system("rm -rfv /tmp/wine-runner-log")
         os.system("mkdir -v /tmp/wine-runner-log")
         self.ToHtml("/tmp/wine-runner-log/index.html", toZip=True)
-        shutil.copy(self.binIconPath, f"/tmp/wine-runner-log/{os.path.basename(self.binIconPath)}")
+        if os.path.exists(self.binIconPath):
+            shutil.copy(self.binIconPath, f"/tmp/wine-runner-log/{os.path.basename(self.binIconPath)}")
         lists = ["wine-runner-log-icon.png", "index.html"]
         for i in self.imgPath:
             name = os.path.basename(i)
@@ -167,17 +266,35 @@ class SaveLog():
         imgPath = ""
         lsmod = ""
         lshw = ""
+        charReplaceMap = {
+            "<": "&lt;",
+            ">": "&gt;",
+            "&": "&amp;",
+            '"': "&quot;"
+        }
         for i in self.description.splitlines():
+            for k in charReplaceMap:
+                i = i.replace(k, charReplaceMap[k])
             description += f'<span class="line code">{i}</span>\n'
         for i in self.logOut.splitlines():
+            for k in charReplaceMap:
+                i = i.replace(k, charReplaceMap[k])
             logOut += f'<span class="line code">{i}</span>\n'
         for i in self.cpuInfo.splitlines():
+            for k in charReplaceMap:
+                i = i.replace(k, charReplaceMap[k])
             cpuInfo += f'<span class="line code">{i}</span>\n'
         for i in self.memoryInfo.splitlines():
+            for k in charReplaceMap:
+                i = i.replace(k, charReplaceMap[k])
             memoryInfo += f'<span class="line code">{i}</span>\n'
         for i in self.lsmod.splitlines():
+            for k in charReplaceMap:
+                i = i.replace(k, charReplaceMap[k])
             lsmod += f'<span class="line code">{i}</span>\n'
         for i in self.lshw.splitlines():
+            for k in charReplaceMap:
+                i = i.replace(k, charReplaceMap[k])
             lshw += f'<span class="line code">{i}</span>\n'
         text = readtxt(f"{programPath}/Resources/LogTemplate/template.html")
         if toZip:
@@ -223,14 +340,11 @@ class SaveLog():
             "%Lsmod%": lsmod,
             "%Lshw%": lshw,
             "%CPU%": self.cpu,
-            "%GPU%": self.gpu
+            "%GPU%": self.gpu,
+            "%SystemVersion%": self.systemVersion
         }
         for i in replaceMap.keys():
             text = text.replace(i, replaceMap[i])
         with open(savePath, "w") as file:
             file.write(text)
 
-
-
-
-SaveLog("a", "b", "c", "/opt/apps/deepin-wine-runner/geek.exe", "e", "f", ["/tmp/wine-runner-log/wine-runner-log-icon.png"]).To7z("/tmp/a.7z")
\ No newline at end of file
diff --git a/Makefile b/Makefile
index f1b9415..da82562 100755
--- a/Makefile
+++ b/Makefile
@@ -62,6 +62,7 @@ package:
 	cp -rv RegShot deb/opt/apps/deepin-wine-runner
 	cp -rv BeCyIconGrabber.exe deb/opt/apps/deepin-wine-runner
 	cp -rv AutoShell deb/opt/apps/deepin-wine-runner
+	cp -rv Resources deb/opt/apps/deepin-wine-runner
 	cp -rv deepin-wine-packager-with-script.py deb/opt/apps/deepin-wine-runner
 	cp -rv deepin-wine-packager.py deb/opt/apps/deepin-wine-runner
 	cp -rv deepin-wine-runner-update-bug deb/opt/apps/deepin-wine-runner
diff --git a/Resources/LogTemplate/template.html b/Resources/LogTemplate/template.html
index ff7a0d9..c1ecec3 100644
--- a/Resources/LogTemplate/template.html
+++ b/Resources/LogTemplate/template.html
@@ -98,9 +98,13 @@
 %Lshw%
 </pre></code>
     <hr />
-    <p align="center">©2020~Now gfdgd xi</p>
+    <p align="center" id="copyright">©2020~Now <a target="_blank" class="unLine" href="https://gitee.com/gfdgd-xi">gfdgd xi</a></p>
 </body>
 <style>
+    .unLine {
+        text-decoration: none;
+        color: black;
+    }
     @counter-style lno {
         system: extends decimal;
         pad: 4 " ";
@@ -142,5 +146,9 @@
     }
 </style>
 <script>
+window.onload = function load(){
+    date = new Date();
+    document.getElementById("copyright").innerHTML = "©2020~" + date.getFullYear() + ' <a class="unLine" target="_blank" href="https://gitee.com/gfdgd-xi">gfdgd xi</a>';
+}
 
 </script>
\ No newline at end of file
diff --git a/mainwindow.py b/mainwindow.py
index 16c8e84..aecb4e3 100755
--- a/mainwindow.py
+++ b/mainwindow.py
@@ -279,6 +279,7 @@ class Runexebutton_threading(QtCore.QThread):
         super().__init__()
 
     def run(self):
+        global lastRunCommand
         if e1.currentText() == "":
             wineBottonPath = setting["DefultBotton"]
         else:
@@ -330,20 +331,26 @@ class Runexebutton_threading(QtCore.QThread):
         if setting["TerminalOpen"]:
             res = ""
             if e2.currentText()[-4:] == ".msi" and os.path.exists(e2.currentText()):
-                OpenTerminal("env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " msiexec /i '" + e2.currentText() + "' " + setting["WineOption"])
+                runCommand = "env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " msiexec /i '" + e2.currentText() + "' " + setting["WineOption"]
+                OpenTerminal(runCommand)
             elif e2.currentText()[-4:] == ".bat" and os.path.exists(e2.currentText()):
-                OpenTerminal("env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " wineconsole '" + e2.currentText() + "' " + setting["WineOption"])
+                runCommand = "env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " wineconsole '" + e2.currentText() + "' " + setting["WineOption"]
+                OpenTerminal(runCommand)
             else:
-                OpenTerminal("env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + exePath + "' " + setting["WineOption"])
+                runCommand = "env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + exePath + "' " + setting["WineOption"]
+                OpenTerminal(runCommand)
             #res = subprocess.Popen([f"'{programPath}/launch.sh' deepin-terminal -C \"WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + e2.currentText() + "' " + setting["WineOption"] + "\" --keep-open" + wineUsingOption], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
         else:
             if e2.currentText()[-4:] == ".msi" and os.path.exists(e2.currentText()):
-                res = subprocess.Popen(["WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " msiexec /i '" + e2.currentText() + "' " + setting["WineOption"]], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+                runCommand = "WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " msiexec /i '" + e2.currentText() + "' " + setting["WineOption"]
+                res = subprocess.Popen([runCommand], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
             elif e2.currentText()[-4:] == ".bat" and os.path.exists(e2.currentText()):
-                res = subprocess.Popen(["WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " wineconsole '" + e2.currentText() + "' " + setting["WineOption"]], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+                runCommand = "WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " wineconsole '" + e2.currentText() + "' " + setting["WineOption"]
+                res = subprocess.Popen([runCommand], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
             else:
+                runCommand = "WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + exePath + "' " + setting["WineOption"]
                 print(["WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + exePath + "' " + setting["WineOption"]])
-                res = subprocess.Popen(["WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + exePath + "' " + setting["WineOption"]], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+                res = subprocess.Popen([runCommand], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
         # 实时读取程序返回
         #
         if not setting["TerminalOpen"]:
@@ -354,6 +361,8 @@ class Runexebutton_threading(QtCore.QThread):
                     text = ""
                 self.signal.emit(text)
                 print(text, end="")
+        lastRunCommand = runCommand
+        print(runCommand)
         if len(findExeHistory) == 0 or findExeHistory[-1] != wineBottonPath:
             findExeHistory.append(wineBottonPath)  # 将记录写进数组
             write_txt(get_home() + "/.config/deepin-wine-runner/FindExeHistory.json", str(json.dumps(ListToDictionary(findExeHistory))))  # 将历史记录的数组转换为字典并写入
@@ -750,6 +759,7 @@ class RunWineProgramThread(QtCore.QThread):
         self.Disbled = Disbled
 
     def run(self):
+        global lastRunCommand
         if e1.currentText() == "":
             wineBottonPath = setting["DefultBotton"]
         else:
@@ -774,10 +784,14 @@ class RunWineProgramThread(QtCore.QThread):
                 os.remove(f"{programPath}/dlls-arm.7z")
         if setting["TerminalOpen"]:
             res = ""
-            OpenTerminal(f"env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + self.wineProgram + "' " + setting["WineOption"] + " " + wineUsingOption)
+            runCommand = f"env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + self.wineProgram + "' " + setting["WineOption"] + " " + wineUsingOption
+            OpenTerminal(runCommand)
             #res = subprocess.Popen([f"'{programPath}/launch.sh' deepin-terminal -C \"WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + self.wineProgram + "' " + setting["WineOption"] + " " + wineUsingOption + "\" --keep-open"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
         else:
-            res = subprocess.Popen(["WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + self.wineProgram + "' " + setting["WineOption"]], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+            runCommand = "WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + self.wineProgram + "' " + setting["WineOption"]
+            res = subprocess.Popen([runCommand], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        print(runCommand)
+        lastRunCommand = runCommand
         # 实时读取程序返回
         if not setting["TerminalOpen"]:
             while res.poll() is None:
@@ -2580,6 +2594,7 @@ information = json.loads(readtxt(f"{programPath}/information.json"))
 version = information["Version"]
 goodRunSystem = QtCore.QCoreApplication.translate("U", "常见 Linux 发行版")
 thankText = ""
+lastRunCommand = "暂未运行命令"
 tips = QtCore.QCoreApplication.translate("U", '''<h4>提示:</h4>
 1、使用终端运行该程序,可以看到 wine 以及程序本身的提示和报错;
 2、wine 32 位和 64 位的容器互不兼容;
@@ -2800,11 +2815,12 @@ background-color: black;
 color: white;
 """)
 returnText.setText(QtCore.QCoreApplication.translate("U", """在此可以看到wine安装应用时的终端输出内容
-========================================
+=============================================
 如果解决了你的问题,请不要吝啬你的star哟!
 地址:
 https://gitee.com/gfdgd-xi/deep-wine-runner
-https://github.com/gfdgd-xi/deep-wine-runner"""))
+https://github.com/gfdgd-xi/deep-wine-runner
+https://sourceforge.net/projects/deep-wine-runner"""))
 mainLayout.setRowStretch(0, 2)
 mainLayout.setRowStretch(1, 1)
 mainLayout.setColumnStretch(0, 2)
@@ -3148,18 +3164,21 @@ log = menu.addMenu(QtCore.QCoreApplication.translate("U", "日志(&L)"))
 getDllInfo = QtWidgets.QAction(QtCore.QCoreApplication.translate("U", "查询 Dll"))
 checkLogText = QtWidgets.QAction(QtCore.QCoreApplication.translate("U", "日志分析"))
 saveLogText = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(16), QtCore.QCoreApplication.translate("U", "另存为日志"))
+saveLogReport = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(16), QtCore.QCoreApplication.translate("U", "输出详细日志报告"))
 transLogText = QtWidgets.QAction(QtCore.QCoreApplication.translate("U", "翻译日志(翻译后日志分析功能会故障)"))
 uploadLogText = QtWidgets.QAction(QtCore.QCoreApplication.translate("U", "上传日志"))
 getDllInfo.triggered.connect(DllWindow.ShowWindow)
 checkLogText.triggered.connect(LogChecking.ShowWindow)
 saveLogText.triggered.connect(SaveLog)
+saveLogReport.triggered.connect(lambda: SaveLogReport(o1.currentText(), wine[o1.currentText()], lastRunCommand, e2.currentText(), returnText.toPlainText()).SetWindow())
 transLogText.triggered.connect(TransLog)
 uploadLogText.triggered.connect(UploadLog)
 log.addAction(getDllInfo)
-log.addAction(checkLogText)
+#log.addAction(checkLogText)
 log.addAction(saveLogText)
-log.addAction(transLogText)
-log.addAction(uploadLogText)
+log.addAction(saveLogReport)
+#log.addAction(transLogText)
+#log.addAction(uploadLogText)
 
 actionList = []
 def AddLib(install: QtWidgets.QAction, uninstall, menu, info):
@@ -3281,7 +3300,7 @@ gfdgdxiio = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), Q
 gitee = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), QtCore.QCoreApplication.translate("U", "Gitee"))
 github = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), QtCore.QCoreApplication.translate("U", "Github"))
 gitlab = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), QtCore.QCoreApplication.translate("U", "Gitlab"))
-jihu = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), QtCore.QCoreApplication.translate("U", "极狐"))
+jihu = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), QtCore.QCoreApplication.translate("U", "Sourceforge"))
 h1.addAction(gfdgdxiio)
 h1.addAction(gitee)
 h1.addAction(github)
@@ -3315,7 +3334,7 @@ gfdgdxiio.triggered.connect(lambda: webbrowser.open_new_tab("https://gfdgd-xi.gi
 gitee.triggered.connect(lambda: webbrowser.open_new_tab("https://gitee.com/gfdgd-xi/deep-wine-runner"))
 github.triggered.connect(lambda: webbrowser.open_new_tab("https://github.com/gfdgd-xi/deep-wine-runner"))
 gitlab.triggered.connect(lambda: webbrowser.open_new_tab("https://gitlab.com/gfdgd-xi/deep-wine-runner"))
-jihu.triggered.connect(lambda: webbrowser.open_new_tab("https://jihulab.com//gfdgd-xi/deep-wine-runner"))
+jihu.triggered.connect(lambda: webbrowser.open_new_tab("https://sourceforge.net/projects/deep-wine-runner/"))
 runStatusWebSize.triggered.connect(lambda: webbrowser.open_new_tab("https://gfdgd-xi.github.io/wine-runner-info"))
 h2.triggered.connect(helps)
 h3.triggered.connect(UpdateThings)
diff --git a/wine/installwine b/wine/installwine
index 341923f..1b4eb74 100755
--- a/wine/installwine
+++ b/wine/installwine
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 # 本来是用C++写的,但在非deepin/UOS编译/运行就是下载不了https文件,只能用python重写
 #########################################################################
-# 作者:gfdgd xi、为什么您不喜欢熊出没和阿布
+# 作者:gfdgd xi
 # 版本:2.4.0
 # 感谢:感谢 deepin-wine 团队,提供了 deepin-wine 给大家使用,让我能做这个程序
 # 基于 Python3 的 PyQt5 构建