mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
416 lines
13 KiB
Python
416 lines
13 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Show dialog for choosing central pype repository."""
|
|
import os
|
|
import sys
|
|
import re
|
|
|
|
from Qt import QtCore, QtGui, QtWidgets # noqa
|
|
from Qt.QtGui import QValidator # noqa
|
|
from Qt.QtCore import QTimer # noqa
|
|
|
|
from .install_thread import InstallThread
|
|
from .tools import (
|
|
validate_mongo_connection,
|
|
get_openpype_path_from_db
|
|
)
|
|
from .user_settings import OpenPypeSecureRegistry
|
|
from .version import __version__
|
|
|
|
|
|
def load_stylesheet():
|
|
stylesheet_path = os.path.join(
|
|
os.path.dirname(__file__),
|
|
"stylesheet.css"
|
|
)
|
|
with open(stylesheet_path, "r") as file_stream:
|
|
stylesheet = file_stream.read()
|
|
|
|
return stylesheet
|
|
|
|
|
|
class ButtonWithOptions(QtWidgets.QFrame):
|
|
option_clicked = QtCore.Signal(str)
|
|
|
|
def __init__(self, options, default=None, parent=None):
|
|
super(ButtonWithOptions, self).__init__(parent)
|
|
|
|
self.setObjectName("ButtonWithOptions")
|
|
|
|
if default:
|
|
if default not in options:
|
|
default = None
|
|
|
|
if default is None:
|
|
default = options[0]
|
|
|
|
main_btn = QtWidgets.QPushButton(default, self)
|
|
main_btn.setFlat(True)
|
|
|
|
options_btn = QtWidgets.QToolButton(self)
|
|
options_btn.setArrowType(QtCore.Qt.DownArrow)
|
|
options_btn.setIconSize(QtCore.QSize(12, 12))
|
|
|
|
options_menu = QtWidgets.QMenu(self)
|
|
for option in options:
|
|
action = QtWidgets.QAction(option, options_menu)
|
|
action.setData(option)
|
|
options_menu.addAction(action)
|
|
|
|
main_layout = QtWidgets.QHBoxLayout(self)
|
|
main_layout.setContentsMargins(0, 0, 0, 0)
|
|
main_layout.setSpacing(1)
|
|
|
|
main_layout.addWidget(main_btn, 1, QtCore.Qt.AlignVCenter)
|
|
main_layout.addWidget(options_btn, 0, QtCore.Qt.AlignVCenter)
|
|
|
|
main_btn.clicked.connect(self._on_main_button)
|
|
options_btn.clicked.connect(self._on_options_click)
|
|
options_menu.triggered.connect(self._on_trigger)
|
|
|
|
self.main_btn = main_btn
|
|
self.options_btn = options_btn
|
|
self.options_menu = options_menu
|
|
|
|
self._default_value = default
|
|
|
|
def resizeEvent(self, event):
|
|
super(ButtonWithOptions, self).resizeEvent(event)
|
|
self.options_btn.setFixedHeight(self.main_btn.height())
|
|
|
|
def _on_options_click(self):
|
|
point = self.mapToGlobal(self.rect().bottomLeft())
|
|
self.options_menu.popup(point)
|
|
|
|
def _on_trigger(self, action):
|
|
self.option_clicked.emit(action.data())
|
|
|
|
def _on_main_button(self):
|
|
self.option_clicked.emit(self._default_value)
|
|
|
|
|
|
class MongoUrlInput(QtWidgets.QLineEdit):
|
|
"""Widget to input mongodb URL."""
|
|
|
|
def set_valid(self):
|
|
"""Set valid state on mongo url input."""
|
|
self.setProperty("state", "valid")
|
|
self.style().polish(self)
|
|
|
|
def set_warning(self):
|
|
"""Set invalid state on mongo url input."""
|
|
self.setProperty("state", "warning")
|
|
self.style().polish(self)
|
|
|
|
def set_invalid(self):
|
|
"""Set invalid state on mongo url input."""
|
|
self.setProperty("state", "invalid")
|
|
self.style().polish(self)
|
|
|
|
|
|
class InstallDialog(QtWidgets.QDialog):
|
|
"""Main Igniter dialog window."""
|
|
|
|
mongo_url_regex = re.compile(r"(mongodb|mongodb+srv)://.+")
|
|
|
|
_width = 300
|
|
_height = 200
|
|
def __init__(self, parent=None):
|
|
super(InstallDialog, self).__init__(parent)
|
|
|
|
self.setWindowTitle(
|
|
f"OpenPype Igniter {__version__} - OpenPype installation"
|
|
)
|
|
self.setWindowFlags(
|
|
QtCore.Qt.WindowCloseButtonHint
|
|
| QtCore.Qt.WindowMinimizeButtonHint
|
|
)
|
|
|
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
roboto_font_path = os.path.join(current_dir, "RobotoMono-Regular.ttf")
|
|
icon_path = os.path.join(current_dir, "openpype_icon.png")
|
|
|
|
# Install roboto font
|
|
QtGui.QFontDatabase.addApplicationFont(roboto_font_path)
|
|
|
|
# Load logo
|
|
pixmap_openpype_logo = QtGui.QPixmap(icon_path)
|
|
# Set logo as icon of window
|
|
self.setWindowIcon(QtGui.QIcon(pixmap_openpype_logo))
|
|
|
|
secure_registry = OpenPypeSecureRegistry("mongodb")
|
|
mongo_url = ""
|
|
try:
|
|
mongo_url = (
|
|
os.getenv("OPENPYPE_MONGO", "")
|
|
or secure_registry.get_item("openPypeMongo")
|
|
)
|
|
except ValueError:
|
|
pass
|
|
|
|
self.mongo_url = mongo_url
|
|
self._pixmap_openpype_logo = pixmap_openpype_logo
|
|
|
|
self._secure_registry = secure_registry
|
|
self._controls_disabled = False
|
|
self._install_thread = None
|
|
|
|
# style for normal console text
|
|
self.default_console_style = QtGui.QTextCharFormat()
|
|
# self.default_console_style.setFontPointSize(0.1)
|
|
self.default_console_style.setForeground(
|
|
QtGui.QColor.fromRgb(72, 200, 150))
|
|
|
|
# style for error console text
|
|
self.error_console_style = QtGui.QTextCharFormat()
|
|
# self.error_console_style.setFontPointSize(0.1)
|
|
self.error_console_style.setForeground(
|
|
QtGui.QColor.fromRgb(184, 54, 19))
|
|
|
|
self.setMinimumSize(QtCore.QSize(self._width, self._height))
|
|
self._init_ui()
|
|
|
|
# Set stylesheet
|
|
self.setStyleSheet(load_stylesheet())
|
|
|
|
# Trigger mongo validation
|
|
self.validate_url()
|
|
|
|
def _init_ui(self):
|
|
# basic visual style - dark background, light text
|
|
|
|
# Main info
|
|
# --------------------------------------------------------------------
|
|
main_label = QtWidgets.QLabel("Welcome to <b>OpenPype</b>", self)
|
|
main_label.setWordWrap(True)
|
|
main_label.setObjectName("MainLabel")
|
|
|
|
# Mongo box | OK button
|
|
# --------------------------------------------------------------------
|
|
mongo_label = QtWidgets.QLabel("Enter your Mongo URL:")
|
|
mongo_label.setWordWrap(True)
|
|
|
|
mongo_input = MongoUrlInput(self)
|
|
mongo_input.setPlaceholderText(
|
|
"Mongo URL < mongodb://192.168.1.1:27017 >"
|
|
)
|
|
if self.mongo_url:
|
|
mongo_input.setText(self.mongo_url)
|
|
|
|
# Bottom button bar
|
|
# --------------------------------------------------------------------
|
|
bottom_widget = QtWidgets.QWidget(self)
|
|
|
|
btns_widget = QtWidgets.QWidget(bottom_widget)
|
|
|
|
openpype_logo_label = QtWidgets.QLabel("openpype logo", bottom_widget)
|
|
openpype_logo_label.setPixmap(self._pixmap_openpype_logo)
|
|
openpype_logo_label.setContentsMargins(5, 5, 5, 5)
|
|
|
|
run_button = ButtonWithOptions(
|
|
["Run", "Run from code"],
|
|
"Run",
|
|
btns_widget
|
|
)
|
|
run_button.setMinimumSize(64, 24)
|
|
run_button.setToolTip("Run OpenPype")
|
|
|
|
# install button - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
exit_button = QtWidgets.QPushButton("Exit", btns_widget)
|
|
exit_button.setObjectName("ExitBtn")
|
|
exit_button.setFlat(True)
|
|
exit_button.setMinimumSize(64, 24)
|
|
exit_button.setToolTip("Exit")
|
|
|
|
btns_layout = QtWidgets.QHBoxLayout(btns_widget)
|
|
btns_layout.setContentsMargins(0, 0, 0, 0)
|
|
btns_layout.addWidget(run_button, 0)
|
|
btns_layout.addWidget(exit_button, 0)
|
|
|
|
bottom_layout = QtWidgets.QHBoxLayout(bottom_widget)
|
|
bottom_layout.setContentsMargins(0, 0, 0, 0)
|
|
bottom_layout.setAlignment(QtCore.Qt.AlignHCenter)
|
|
bottom_layout.addWidget(openpype_logo_label, 0)
|
|
bottom_layout.addStretch(1)
|
|
bottom_layout.addWidget(btns_widget, 0)
|
|
|
|
# Console label
|
|
# --------------------------------------------------------------------
|
|
status_label = QtWidgets.QLabel("Console:", self)
|
|
status_label.setContentsMargins(0, 10, 0, 10)
|
|
status_label.setStyleSheet("color: rgb(61, 115, 97);")
|
|
|
|
# Console
|
|
# --------------------------------------------------------------------
|
|
status_box = QtWidgets.QPlainTextEdit(self)
|
|
status_box.setReadOnly(True)
|
|
status_box.setCurrentCharFormat(self.default_console_style)
|
|
status_box.setObjectName("Console")
|
|
|
|
# Progress bar
|
|
# --------------------------------------------------------------------
|
|
progress_bar = QtWidgets.QProgressBar(self)
|
|
progress_bar.setValue(0)
|
|
progress_bar.setAlignment(QtCore.Qt.AlignCenter)
|
|
progress_bar.setTextVisible(False)
|
|
|
|
# add all to main
|
|
main = QtWidgets.QVBoxLayout(self)
|
|
main.addWidget(main_label, 0)
|
|
main.addWidget(mongo_label, 0)
|
|
main.addWidget(mongo_input, 0)
|
|
|
|
main.addWidget(status_label, 0)
|
|
main.addWidget(status_box, 1)
|
|
|
|
main.addWidget(progress_bar, 0)
|
|
main.addWidget(bottom_widget, 0)
|
|
|
|
run_button.option_clicked.connect(self._on_run_btn_click)
|
|
exit_button.clicked.connect(self._on_exit_clicked)
|
|
mongo_input.textChanged.connect(self._on_mongo_url_change)
|
|
|
|
self.main_label = main_label
|
|
self.mongo_label = mongo_label
|
|
|
|
self._mongo_input = mongo_input
|
|
|
|
self._status_label = status_label
|
|
self._status_box = status_box
|
|
|
|
self._run_button = run_button
|
|
self._exit_button = exit_button
|
|
self._progress_bar = progress_bar
|
|
|
|
def _on_run_btn_click(self, option):
|
|
if not self.validate_url():
|
|
return
|
|
|
|
if option == "Run":
|
|
self._run_openpype()
|
|
elif option == "Run from code":
|
|
self._run_openpype_from_code()
|
|
else:
|
|
raise AssertionError("BUG: Unknown variant \"{}\"".format(option))
|
|
|
|
def _run_openpype_from_code(self):
|
|
valid, reason = validate_mongo_connection(self.mongo_url)
|
|
if not valid:
|
|
self._mongo_input.set_invalid()
|
|
self.update_console(f"!!! {reason}", True)
|
|
return
|
|
|
|
self._secure_registry.set_item("openPypeMongo", self.mongo_url)
|
|
|
|
self.done(2)
|
|
|
|
def _run_openpype(self):
|
|
"""Start install process.
|
|
|
|
This will once again validate entered path and mongo if ok, start
|
|
working thread that will do actual job.
|
|
"""
|
|
# Check if install thread is not already running
|
|
if self._install_thread and self._install_thread.isRunning():
|
|
return
|
|
|
|
valid, reason = validate_mongo_connection(self.mongo_url)
|
|
if not valid:
|
|
self._mongo_input.set_invalid()
|
|
self.update_console(f"!!! {reason}", True)
|
|
return
|
|
|
|
self._mongo_input.set_valid()
|
|
|
|
self._disable_buttons()
|
|
|
|
install_thread = InstallThread(self)
|
|
install_thread.message.connect(self.update_console)
|
|
install_thread.progress.connect(self._update_progress)
|
|
install_thread.finished.connect(self._installation_finished)
|
|
install_thread.set_mongo(self.mongo_url)
|
|
|
|
self._install_thread = install_thread
|
|
|
|
install_thread.start()
|
|
|
|
def _installation_finished(self, status):
|
|
if status >= 0:
|
|
self.done(3)
|
|
else:
|
|
self._enable_buttons()
|
|
|
|
def _update_progress(self, progress: int):
|
|
self._progress_bar.setValue(progress)
|
|
|
|
def _on_exit_clicked(self):
|
|
self.reject()
|
|
|
|
def _on_mongo_url_change(self, new_value):
|
|
# Strip the value
|
|
new_value = new_value.strip()
|
|
# Store new mongo url to variable
|
|
self.mongo_url = new_value
|
|
# Change style of input
|
|
if not new_value:
|
|
self._mongo_input.set_warning()
|
|
elif self.mongo_url_regex.match(new_value):
|
|
self._mongo_input.set_valid()
|
|
else:
|
|
self._mongo_input.set_invalid()
|
|
|
|
def validate_url(self):
|
|
"""Validate if entered url is ok.
|
|
|
|
Returns:
|
|
True if url is valid monogo string.
|
|
|
|
"""
|
|
if self.mongo_url == "":
|
|
return False
|
|
|
|
is_valid, reason_str = validate_mongo_connection(self.mongo_url)
|
|
if not is_valid:
|
|
self._mongo_input.set_invalid()
|
|
self.update_console(f"!!! {reason_str}", True)
|
|
return False
|
|
else:
|
|
self._mongo_input.set_valid()
|
|
return True
|
|
|
|
def update_console(self, msg: str, error: bool = False) -> None:
|
|
"""Display message in console.
|
|
|
|
Args:
|
|
msg (str): message.
|
|
error (bool): if True, print it red.
|
|
"""
|
|
if not error:
|
|
self._status_box.setCurrentCharFormat(self.default_console_style)
|
|
else:
|
|
self._status_box.setCurrentCharFormat(self.error_console_style)
|
|
self._status_box.appendPlainText(msg)
|
|
|
|
def _disable_buttons(self):
|
|
"""Disable buttons so user interaction doesn't interfere."""
|
|
self._exit_button.setEnabled(False)
|
|
self._run_button.setEnabled(False)
|
|
self._controls_disabled = True
|
|
|
|
def _enable_buttons(self):
|
|
"""Enable buttons after operation is complete."""
|
|
self._exit_button.setEnabled(True)
|
|
self._run_button.setEnabled(True)
|
|
self._controls_disabled = False
|
|
|
|
def closeEvent(self, event): # noqa
|
|
"""Prevent closing if window when controls are disabled."""
|
|
if self._controls_disabled:
|
|
return event.ignore()
|
|
return super(InstallDialog, self).closeEvent(event)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
app = QtWidgets.QApplication(sys.argv)
|
|
d = InstallDialog()
|
|
d.show()
|
|
sys.exit(app.exec_())
|