diff --git a/pype/muster/__init__.py b/pype/muster/__init__.py new file mode 100644 index 0000000000..9429cbe561 --- /dev/null +++ b/pype/muster/__init__.py @@ -0,0 +1,5 @@ +from .muster import MusterModule + + +def tray_init(tray_widget, main_widget): + return MusterModule(main_widget, tray_widget) diff --git a/pype/muster/muster.py b/pype/muster/muster.py new file mode 100644 index 0000000000..6af8352542 --- /dev/null +++ b/pype/muster/muster.py @@ -0,0 +1,90 @@ +import appdirs +from pypeapp import style +from Qt import QtWidgets +import os +import json +from .widget_login import MusterLogin + + +class MusterModule: + """ + Module handling Muster Render credentials. This will display dialog + asking for user credentials for Muster if not already specified. + """ + cred_folder_path = os.path.normpath( + appdirs.user_data_dir('pype-app', 'pype', 'muster') + ) + cred_filename = 'muster_cred.json' + + def __init__(self, main_parent=None, parent=None): + self.cred_path = os.path.join( + self.cred_folder_path, self.cred_filename + ) + self.main_parent = main_parent + self.parent = parent + self.widget_login = MusterLogin(main_parent, self) + + def start_up(self): + """ + Show login dialog if credentials not found. + """ + # This should be start of module in tray + cred = self.load_credentials() + if not cred: + self.show_login() + else: + # nothing to do + pass + + # Definition of Tray menu + def tray_menu(self, parent): + """ + Add **change credentials** option to tray menu. + """ + # Menu for Tray App + self.menu = QtWidgets.QMenu('Muster', parent) + self.menu.setProperty('submenu', 'on') + self.menu.setStyleSheet(style.load_stylesheet()) + + # Actions + self.aShowLogin = QtWidgets.QAction( + "Change login", self.menu + ) + + self.menu.addAction(self.aShowLogin) + self.aShowLogin.triggered.connect(self.show_settings) + + return self.menu + + def load_credentials(self): + """ + Get credentials from JSON file + """ + credentials = {} + try: + file = open(self.cred_path, 'r') + credentials = json.load(file) + except Exception: + file = open(self.cred_path, 'w') + file.close() + + return credentials + + def save_credentials(self, username, password): + """ + Save credentials to JSON file + """ + data = { + 'username': username, + 'password': password + } + + file = open(self.cred_path, 'w') + file.write(json.dumps(data)) + file.close() + + def show_login(self): + """ + Show dialog to enter credentials + """ + self.widget_login.show() diff --git a/pype/muster/widget_login.py b/pype/muster/widget_login.py new file mode 100644 index 0000000000..8967089791 --- /dev/null +++ b/pype/muster/widget_login.py @@ -0,0 +1,137 @@ +import os +from Qt import QtCore, QtGui, QtWidgets +from pypeapp import style + + +class MusterLogin(QtWidgets.QWidget): + + SIZE_W = 300 + SIZE_H = 130 + + loginSignal = QtCore.Signal(object, object, object) + + def __init__(self, main_parent=None, parent=None): + + super(MusterLogin, self).__init__() + + self.parent_widget = parent + self.main_parent = main_parent + self.clockapi = parent.clockapi + + # Icon + if hasattr(parent, 'icon'): + self.setWindowIcon(parent.icon) + elif hasattr(parent, 'parent') and hasattr(parent.parent, 'icon'): + self.setWindowIcon(parent.parent.icon) + else: + pype_setup = os.getenv('PYPE_ROOT') + items = [pype_setup, "app", "resources", "icon.png"] + fname = os.path.sep.join(items) + icon = QtGui.QIcon(fname) + self.setWindowIcon(icon) + + self.setWindowFlags( + QtCore.Qt.WindowCloseButtonHint | + QtCore.Qt.WindowMinimizeButtonHint + ) + + self._translate = QtCore.QCoreApplication.translate + + # Font + self.font = QtGui.QFont() + self.font.setFamily("DejaVu Sans Condensed") + self.font.setPointSize(9) + self.font.setBold(True) + self.font.setWeight(50) + self.font.setKerning(True) + + # Size setting + self.resize(self.SIZE_W, self.SIZE_H) + self.setMinimumSize(QtCore.QSize(self.SIZE_W, self.SIZE_H)) + self.setMaximumSize(QtCore.QSize(self.SIZE_W+100, self.SIZE_H+100)) + self.setStyleSheet(style.load_stylesheet()) + + self.setLayout(self._main()) + self.setWindowTitle('Muster login') + + def _main(self): + self.main = QtWidgets.QVBoxLayout() + self.main.setObjectName("main") + + self.form = QtWidgets.QFormLayout() + self.form.setContentsMargins(10, 15, 10, 5) + self.form.setObjectName("form") + + self.label_username = QtWidgets.QLabel("Username:") + self.label_username.setFont(self.font) + self.label_username.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) + self.label_username.setTextFormat(QtCore.Qt.RichText) + + self.input_username = QtWidgets.QLineEdit() + self.input_username.setEnabled(True) + self.input_username.setFrame(True) + self.input_username.setPlaceholderText( + self._translate("main", "e.g. John Smith") + ) + + self.label_password = QtWidgets.QLabel("Password:") + self.label_password.setFont(self.font) + self.label_password.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) + self.label_password.setTextFormat(QtCore.Qt.RichText) + + self.input_password = QtWidgets.QLineEdit() + self.input_password.setEchoMode(QtGui.QLineEdit.Password) + self.input_password.setEnabled(True) + self.input_password.setFrame(True) + self.input_password.setPlaceholderText( + self._translate("main", "e.g. ********") + ) + + self.error_label = QtWidgets.QLabel("") + self.error_label.setFont(self.font) + self.error_label.setTextFormat(QtCore.Qt.RichText) + self.error_label.setObjectName("error_label") + self.error_label.setWordWrap(True) + self.error_label.hide() + + self.form.addRow(self.label_username, self.input_username) + self.form.addRow(self.label_password, self.input_password) + self.form.addRow(self.error_label) + + self.btn_group = QtWidgets.QHBoxLayout() + self.btn_group.addStretch(1) + self.btn_group.setObjectName("btn_group") + + self.btn_ok = QtWidgets.QPushButton("Ok") + self.btn_ok.clicked.connect(self.click_ok) + + self.btn_cancel = QtWidgets.QPushButton("Cancel") + self.btn_cancel.clicked.connect(self.close) + + self.btn_group.addWidget(self.btn_ok) + self.btn_group.addWidget(self.btn_cancel) + + self.main.addLayout(self.form) + self.main.addLayout(self.btn_group) + + return self.main + + def setError(self, msg): + self.error_label.setText(msg) + self.error_label.show() + + def invalid_input(self, entity): + entity.setStyleSheet("border: 1px solid red;") + + def click_ok(self): + # all what should happen - validations and saving into appsdir + username = self.input_username.text() + password = self.input_password.text() + # TODO: more robust validation. Password can be empty in muster? + if not username: + self.setError("Username cannot be empty") + self.invalid_input(self.input_username) + self.save_credentials(username, password) + + def save_credentials(self, username, password): + self.parent_widget.save_credentials(username, password)