diff --git a/doc/source/installer.rst b/doc/source/installer.rst index a4979c33..a39ce58e 100644 --- a/doc/source/installer.rst +++ b/doc/source/installer.rst @@ -334,6 +334,8 @@ On the ``Launching options`` section, the following options are available: * ``Launch Console``: this option starts a console window with the command ``python`` pointing towards your selected Python environment. +* ``Launch VSCode``: this option starts a ``Visual Studio Code``. If ``Visual Studio Code`` is + not installed, then the ``Ansys Python Manager`` provides instructions to install it. * ``Launch JupyterLab``: this option starts a ``JupyterLab`` session. If ``JupyterLab`` is not installed, then the ``Ansys Python Manager`` installs it for you. * ``Launch Jupyter Notebook``: this option starts a ``Jupyter Notebook`` session. If diff --git a/setup.nsi b/setup.nsi index 0fb72130..add5b638 100644 --- a/setup.nsi +++ b/setup.nsi @@ -22,9 +22,19 @@ OutFile "dist\${OUTFILE_NAME}" !insertmacro MULTIUSER_PAGE_INSTALLMODE !insertmacro MUI_PAGE_LICENSE "${LICENSE_FILE}" !insertmacro MUI_PAGE_INSTFILES -!insertmacro MUI_LANGUAGE English !include "uninstall.nsi" +Function CreateDesktopShortCut + CreateShortCut "$desktop\Ansys Python Manager.lnk" "$INSTDIR\Ansys Python Manager.exe" +FunctionEnd + +!define MUI_FINISHPAGE_RUN "$INSTDIR\Ansys Python Manager.exe" +!define MUI_FINISHPAGE_SHOWREADME +!define MUI_FINISHPAGE_SHOWREADME_TEXT "Create Desktop Shortcut" +!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED +!define MUI_FINISHPAGE_SHOWREADME_FUNCTION "CreateDesktopShortCut" +!insertmacro MUI_PAGE_FINISH + Function .onInit !insertmacro MULTIUSER_INIT FunctionEnd @@ -58,12 +68,6 @@ Section "Ansys Python Manager" SEC01 WriteUninstaller "$INSTDIR\uninstall.exe" - ; start after install - Exec "$INSTDIR\Ansys Python Manager.exe" - - ; After installation succeeded, wait and close - Sleep 5000 - Quit SectionEnd ; Define the uninstaller section @@ -74,6 +78,7 @@ Section "Uninstall" SEC02 DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" Delete "$SMPROGRAMS\Ansys Python Manager\Ansys Python Manager.lnk" RMDir "$SMPROGRAMS\Ansys Python Manager" + Delete "$desktop\Ansys Python Manager.lnk" SectionEnd Icon "dist\ansys_python_manager\_internal\assets\pyansys_icon.ico" @@ -90,3 +95,4 @@ FunctionEnd ; Call the MUI2 OneClick plugin !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_LANGUAGE English diff --git a/src/ansys/tools/installer/configure.py b/src/ansys/tools/installer/configure.py index d6404b58..1f614cc1 100644 --- a/src/ansys/tools/installer/configure.py +++ b/src/ansys/tools/installer/configure.py @@ -35,10 +35,10 @@ class Configure(QtWidgets.QWidget): - """Manage Virtual Environment w.r.t Python versions tab.""" + """Configure tab.""" def __init__(self, parent): - """Initialize this tab.""" + """Initialize this class.""" try: super().__init__() self._parent = parent diff --git a/src/ansys/tools/installer/installed_table.py b/src/ansys/tools/installer/installed_table.py index 1565cd65..799e36cb 100644 --- a/src/ansys/tools/installer/installed_table.py +++ b/src/ansys/tools/installer/installed_table.py @@ -46,6 +46,7 @@ run_linux_command, run_linux_command_conda, ) +from ansys.tools.installer.vscode import VSCode ALLOWED_FOCUS_EVENTS = [QtCore.QEvent.Type.WindowActivate, QtCore.QEvent.Type.Show] LOG = logging.getLogger(__name__) @@ -251,6 +252,10 @@ def __init__(self, parent=None): self.button_launch_cmd.clicked.connect(self.launch_cmd) hbox.addWidget(self.button_launch_cmd) + self.button_launch_cmd = QtWidgets.QPushButton("Launch VSCode") + self.button_launch_cmd.clicked.connect(self.launch_vscode) + hbox.addWidget(self.button_launch_cmd) + self.button_launch_lab = QtWidgets.QPushButton("Launch Jupyterlab") self.button_launch_lab.clicked.connect(self.launch_jupyterlab) hbox.addWidget(self.button_launch_lab) @@ -365,6 +370,10 @@ def launch_jupyterlab(self): self._update_pck_mnger() self.launch_cmd(f"python -m jupyter lab || {error_msg}") + def launch_vscode(self): + """Launch VSCode.""" + vscode = VSCode(self) + def launch_jupyter_notebook(self): """Launch Jupyter Notebook.""" # handle errors diff --git a/src/ansys/tools/installer/vscode.py b/src/ansys/tools/installer/vscode.py new file mode 100644 index 00000000..91693ea3 --- /dev/null +++ b/src/ansys/tools/installer/vscode.py @@ -0,0 +1,188 @@ +# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""VS code launch window.""" +import os + +from PySide6 import QtCore, QtGui, QtWidgets + +from ansys.tools.installer.constants import ANSYS_FAVICON, USER_PATH + + +class VSCode(QtWidgets.QWidget): + """VS code launch window.""" + + def __init__(self, parent): + """Initialize this class.""" + try: + super().__init__() + self._parent = parent + if self.is_vscode_installed(): + self._parent.vscode_window = QtWidgets.QWidget() + self._parent.vscode_window.move( + self._parent.vscode_window.frameGeometry().center() + ) + vscode_window_label = QtWidgets.QLabel() + vscode_window_label.setText("Configuration") + vscode_window_label.setTextFormat(QtCore.Qt.TextFormat.RichText) + vscode_window_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignJustify) + vscode_window_label.setWordWrap(True) + + vscode_layout = QtWidgets.QVBoxLayout() + + # Group 1: Configure default Virtual Environment creation path + vscode_window_path_config = QtWidgets.QGroupBox( + "VS Code open directory:" + ) + vscode_window_path_config_layout = QtWidgets.QVBoxLayout() + vscode_window_path_config_layout.setContentsMargins(10, 20, 10, 20) + vscode_window_path_config.setLayout(vscode_window_path_config_layout) + + # ---> Add box + self.vscode_window_path_config_edit = QtWidgets.QLineEdit() + self.vscode_window_path_config_edit.setText(USER_PATH) + vscode_window_path_config_layout.addWidget( + self.vscode_window_path_config_edit + ) + + self.vscode_warning_text = QtWidgets.QLabel() + self.vscode_warning_text.setAlignment( + QtCore.Qt.AlignmentFlag.AlignJustify + ) + self.vscode_warning_text.setWordWrap(True) + vscode_window_path_config_layout.addWidget(self.vscode_warning_text) + + # Finally, add all the previous widgets to the global layout + vscode_layout.addWidget(vscode_window_path_config) + + vscode_window_button_open = QtWidgets.QPushButton("Open") + vscode_window_button_open.clicked.connect( + lambda x: self._pop_up("Do you want to open?", self._open_vscode) + ) + vscode_window_button_close = QtWidgets.QPushButton("Close") + vscode_window_button_close.clicked.connect( + lambda x: self._pop_up("Do you want to close?", self._close_all) + ) + + vscode_window_layout_1 = QtWidgets.QHBoxLayout() + vscode_window_layout_1.addWidget(vscode_window_label) + vscode_window_layout_2 = QtWidgets.QHBoxLayout() + vscode_window_layout_2.addWidget(vscode_window_button_open) + vscode_window_layout_2.addWidget(vscode_window_button_close) + + vscode_window_layout = QtWidgets.QVBoxLayout() + vscode_window_layout.addLayout(vscode_window_layout_1) + vscode_window_layout.addLayout(vscode_layout) + vscode_window_layout.addLayout(vscode_window_layout_2) + self._parent.vscode_window.setLayout(vscode_window_layout) + + self._parent.vscode_window.setWindowTitle("Configuration") + self._parent.vscode_window.setWindowIcon(QtGui.QIcon(ANSYS_FAVICON)) + self._parent.vscode_window.resize(500, 40) + self._parent.vscode_window.show() + else: + msg = QtWidgets.QMessageBox() + msg.setTextFormat(QtCore.Qt.TextFormat.RichText) + msg.warning( + self, + "VS Code Launch Error", + f"Failed to launch vscode. Try reinstalling code by following this link", + ) + + except Exception as e: + self._parent.show_error(str(e)) + + def _open_vscode(self): + """Open VS code from path.""" + # handle errors + path = self.vscode_window_path_config_edit.text().strip() + if os.path.exists(path): + error_msg = "echo Failed to launch vscode. Try reinstalling code by following this link https://code.visualstudio.com/download" + self._parent.launch_cmd(f"code {path} && exit 0 || {error_msg}") + + self.user_confirmation_form.close() + self._parent.vscode_window.close() + else: + self.vscode_warning_text.setText( + f"""{path} does not exist. Provide a valid path.""" + ) + self.vscode_warning_text.setStyleSheet( + """ + color: rgb(255, 0, 0); + """ + ) + self.user_confirmation_form.close() + + def _close_all(self): + """Close all the pop-up window.""" + self.user_confirmation_form.close() + self._parent.vscode_window.close() + + def _pop_up(self, message, call_back): + """Launch the confirmation pop-up window.""" + self.user_confirmation_form = QtWidgets.QWidget() + self.user_confirmation_form.move( + self.user_confirmation_form.frameGeometry().center() + ) + user_confirmation_label = QtWidgets.QLabel() + user_confirmation_label.setText(message) + user_confirmation_label.setOpenExternalLinks(True) + user_confirmation_label.setTextFormat(QtCore.Qt.TextFormat.RichText) + user_confirmation_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignJustify) + user_confirmation_label.setWordWrap(True) + + user_confirmation_layout_horizontal = QtWidgets.QHBoxLayout() + user_confirmation_yes_button = QtWidgets.QPushButton("Yes") + user_confirmation_yes_button.clicked.connect(call_back) + user_confirmation_no_button = QtWidgets.QPushButton("No") + user_confirmation_no_button.clicked.connect(self.user_confirmation_form.close) + user_confirmation_layout = QtWidgets.QVBoxLayout() + user_confirmation_layout.addWidget(user_confirmation_label) + user_confirmation_layout_horizontal.addWidget(user_confirmation_yes_button) + user_confirmation_layout_horizontal.addWidget(user_confirmation_no_button) + user_confirmation_layout.addLayout(user_confirmation_layout_horizontal) + self.user_confirmation_form.setLayout(user_confirmation_layout) + self.user_confirmation_form.setWindowTitle("Confirmation") + icon = QtGui.QIcon(ANSYS_FAVICON) + self.user_confirmation_form.setWindowIcon(icon) + self.user_confirmation_form.resize(400, 40) + self.user_confirmation_form.setWindowFlag( + QtCore.Qt.WindowCloseButtonHint, False + ) + self.user_confirmation_form.show() + + def is_vscode_installed(self): + """Check if VSCode is installed or not. + + Returns + ------- + bool + Whether VSCode is installed or not. + """ + try: + return_val = os.system("code --version") + if return_val == 0: + return True + else: + return False + except: + return False