예제 #1
0
    def viewSource(self):
        self.textEdit = QTextEdit()
        self.textEdit.setAttribute(Qt.WA_DeleteOnClose)
        self.textEdit.adjustSize()
        self.textEdit.move(self.geometry().center() -
                           self.textEdit.rect().center())
        self.textEdit.show()

        self.view.page().toHtml(self.textEdit.setPlainText)
예제 #2
0
class TextInput(QWidget):
    # used when input text

    inputChanged = Signal()
    okPressed = Signal()
    cancelPressed = Signal()

    def __init__(self, parent=None):
        super(TextInput, self).__init__(parent)

        self.setWindowFlags(Qt.Dialog | Qt.FramelessWindowHint)

        self.mainLayout = QVBoxLayout()
        self.textArea = QTextEdit(self)

        self.buttonArea = QWidget(self)
        self.buttonLayout = QHBoxLayout()
        self.cancelButton = QPushButton('Cancel', self)
        self.okButton = QPushButton('Ok', self)
        self.buttonLayout.addWidget(self.cancelButton)
        self.buttonLayout.addWidget(self.okButton)
        self.buttonArea.setLayout(self.buttonLayout)

        self.mainLayout.addWidget(self.textArea)
        self.mainLayout.addWidget(self.buttonArea)
        self.setLayout(self.mainLayout)

        self.textArea.textChanged.connect(self.textChanged_)
        self.okButton.clicked.connect(self.okButtonClicked)
        self.cancelButton.clicked.connect(self.cancelPressed)

    def getText(self):
        return self.textArea.toPlainText()

    def getFocus(self):
        self.setFocus()
        self.textArea.setFocus()

    def clearText(self):
        self.textArea.clear()

    # slots
    def textChanged_(self):
        self.inputChanged.emit()

    def cancelButtonClicked(self):
        self.cancelPressed.emit()

    def okButtonClicked(self):
        self.okPressed.emit()
예제 #3
0
    def __init__(self, *args, **kwargs):
        super(TextFieldWidget, self).__init__(*args, **kwargs)

        widget = QTextEdit(parent=self)
        # widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        widget.textChanged.connect(self._on_emit_value_changed)
        self.set_widget(widget)
예제 #4
0
파일: code.py 프로젝트: tpDcc/tpDcc-libs-qt
    def _line_number_highlight(self):
        extra_selection = QTextEdit.ExtraSelection()
        selections = [extra_selection]
        if not self.isReadOnly():
            selection = QTextEdit.ExtraSelection()
            if dcc.is_maya():
                line_color = QColor(Qt.black)
            else:
                line_color = QColor(Qt.lightGray)
            selection.format.setBackground(line_color)
            selection.format.setProperty(QTextFormat.FullWidthSelection, True)
            selection.cursor = self.textCursor()
            selection.cursor.clearSelection()
            selections.append(selection)

        self.setExtraSelections(selections)
예제 #5
0
class Editor(QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        self.current_dir = os.getcwd()
        self.current_file = None
        
        self.init_ui()
    
    def init_ui(self):
        self.text_edit = QTextEdit(self)
        self.setCentralWidget(self.text_edit)
        
        font = QFont("Menlo", 12)
        # TODO: Create a layout and change the line spacing
        #spacing = QFontMetrics(font).lineSpacing()
        self.text_edit.setFont(font)
        self.highlighter = Highlighter(self.text_edit.document(), DEFAULT_RULES, DEFAULT_STYLE)
        #print("Highlighter doc: {}".format(self.text_edit.document()))
        
        menu_bar = self.menuBar()
        m_file = menu_bar.addMenu("File")
        
        i_open = QAction("Open", self)
        i_open.setShortcut('Ctrl+O')
        i_open.triggered.connect(self.on_open)
        
        m_file.addAction(i_open)
        
        self.setGeometry(300, 300, 350, 300)
        self.setWindowTitle("tea")
    
    def on_open(self):
        file_path, other = QFileDialog.getOpenFileName(self, "Open File", self.current_dir)
        #print([a for a in dir(QFileDialog) if not a.startswith("_")])
        print("File name: {}, Other: {}".format(file_path, other))
        if file_path:
            dirname = os.path.basename(os.path.dirname(file_path))
            filename = os.path.basename(file_path)
            self.setWindowTitle("{} - {}".format(filename, dirname))
            with open(file_path) as f:
                text = f.read()
                #formatted = markup_python(text)
                #formatted = "<font color=red size=24>{}</font>".format(text)
                self.text_edit.setText(text)
    def ui(self):
        super(InfoMessage, self).ui()

        self.setMaximumHeight(150)

        info_icon = resources.icon('info')
        self._expandable_frame = expandables.ExpandableFrame(icon=info_icon,
                                                             parent=self)
        self._expandable_frame.setFrameStyle(QFrame.StyledPanel
                                             | QFrame.Raised)

        expandable_layout = layouts.HorizontalLayout(margins=(2, 2, 2, 2))

        texts_layout = layouts.HorizontalLayout(spacing=0,
                                                margins=(0, 0, 0, 0))
        self._description_text = QPlainTextEdit(parent=self)
        self._description_text.setReadOnly(True)
        self._description_text.setSizePolicy(QSizePolicy.Preferred,
                                             QSizePolicy.Maximum)
        self._description_text.setFocusPolicy(Qt.NoFocus)
        self._description_text.setFrameShape(QFrame.NoFrame)
        self._instructions_widget = QWidget()
        instructions_layout = layouts.VerticalLayout(spacing=2,
                                                     margins=(0, 0, 0, 0))
        self._instructions_widget.setLayout(instructions_layout)
        self._instructions_text = QTextEdit(parent=self)
        self._instructions_text.setReadOnly(True)
        self._instructions_text.setSizePolicy(QSizePolicy.Preferred,
                                              QSizePolicy.Maximum)
        self._instructions_text.setFocusPolicy(Qt.NoFocus)
        self._instructions_text.setFrameShape(QFrame.NoFrame)
        self._instructions_widget.setVisible(False)
        # self._instructions_text.insertHtml("<ul><li>text 1</li><li>text 2</li><li>text 3</li></ul> <br />")
        instructions_layout.addWidget(dividers.Divider('Instructions'))
        instructions_layout.addWidget(self._instructions_text)
        texts_layout.addWidget(self._description_text)
        texts_layout.addWidget(self._instructions_widget)

        content_layout = layouts.VerticalLayout()
        content_layout.addLayout(texts_layout)
        expandable_layout.addLayout(content_layout)

        self._expandable_frame.addLayout(expandable_layout)

        self.main_layout.addWidget(self._expandable_frame)
예제 #7
0
 def __init__(self, font, textColor, parent=None):
     super(TextEditDialog, self).__init__(parent)
     self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.FramelessWindowHint)
     self.resize(QtCore.QSize(400, 300))
     self.layout = QVBoxLayout(self)
     self.layout.setContentsMargins(2, 2, 2, 2)
     self.te = QTextEdit()
     self._font = font
     self._font = QtGui.QFont(font)
     self.te.setFont(self._font)
     self.te.setTextColor(textColor)
     self.layout.addWidget(self.te)
     self.buttons = QDialogButtonBox(
         QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self)
     self.buttons.accepted.connect(self.onAccept)
     self.buttons.rejected.connect(self.onReject)
     self.layout.addWidget(self.buttons)
     self._result = None
     self.te.textChanged.connect(
         lambda color=textColor: self.te.setTextColor(color))
예제 #8
0
 def init_ui(self):
     self.text_edit = QTextEdit(self)
     self.setCentralWidget(self.text_edit)
     
     font = QFont("Menlo", 12)
     # TODO: Create a layout and change the line spacing
     #spacing = QFontMetrics(font).lineSpacing()
     self.text_edit.setFont(font)
     self.highlighter = Highlighter(self.text_edit.document(), DEFAULT_RULES, DEFAULT_STYLE)
     #print("Highlighter doc: {}".format(self.text_edit.document()))
     
     menu_bar = self.menuBar()
     m_file = menu_bar.addMenu("File")
     
     i_open = QAction("Open", self)
     i_open.setShortcut('Ctrl+O')
     i_open.triggered.connect(self.on_open)
     
     m_file.addAction(i_open)
     
     self.setGeometry(300, 300, 350, 300)
     self.setWindowTitle("tea")
예제 #9
0
    def __init__(self, parent=None):
        super(TextInput, self).__init__(parent)

        self.setWindowFlags(Qt.Dialog | Qt.FramelessWindowHint)

        self.mainLayout = QVBoxLayout()
        self.textArea = QTextEdit(self)

        self.buttonArea = QWidget(self)
        self.buttonLayout = QHBoxLayout()
        self.cancelButton = QPushButton('Cancel', self)
        self.okButton = QPushButton('Ok', self)
        self.buttonLayout.addWidget(self.cancelButton)
        self.buttonLayout.addWidget(self.okButton)
        self.buttonArea.setLayout(self.buttonLayout)

        self.mainLayout.addWidget(self.textArea)
        self.mainLayout.addWidget(self.buttonArea)
        self.setLayout(self.mainLayout)

        self.textArea.textChanged.connect(self.textChanged_)
        self.okButton.clicked.connect(self.okButtonClicked)
        self.cancelButton.clicked.connect(self.cancelPressed)
예제 #10
0
    def __init__(self, id_, items, parent=None):
        super().__init__(parent)

        itemLabel = QLabel(self.tr("Item: "))
        descriptionLabel = QLabel(self.tr("Description: "))
        imageFileLabel = QLabel(self.tr("Image file: "))

        self.createButtons()

        self.itemText = QLabel()
        self.descriptionEditor = QTextEdit()

        self.imageFileEditor = QComboBox()
        self.imageFileEditor.setModel(items.relationModel(1))
        self.imageFileEditor.setModelColumn(
            items.relationModel(1).fieldIndex("file"))

        self.mapper = QDataWidgetMapper(self)
        self.mapper.setModel(items)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.setItemDelegate(QSqlRelationalDelegate(self.mapper))
        self.mapper.addMapping(self.imageFileEditor, 1)
        self.mapper.addMapping(self.itemText, 2, b"text")
        self.mapper.addMapping(self.descriptionEditor, 3)
        self.mapper.setCurrentIndex(id_)

        self.descriptionEditor.textChanged.connect(self.enableButtons)
        self.imageFileEditor.currentIndexChanged.connect(self.enableButtons)

        formLayout = QFormLayout()
        formLayout.addRow(itemLabel, self.itemText)
        formLayout.addRow(imageFileLabel, self.imageFileEditor)
        formLayout.addRow(descriptionLabel, self.descriptionEditor)

        layout = QVBoxLayout()
        layout.addLayout(formLayout)
        layout.addWidget(self.buttonBox)
        self.setLayout(layout)

        self.itemId = id_
        self.displayedImage = self.imageFileEditor.currentText()

        self.setWindowFlags(Qt.Window)
        self.enableButtons(False)
        self.setWindowTitle(self.itemText.text())
예제 #11
0
파일: code.py 프로젝트: tpDcc/tpDcc-libs-qt
 def show_info_popup(self, info=None):
     self._info = QTextEdit()
     self._info.setEnabled(False)
     self._info.setWindowFlags(Qt.Popup)
     self._info.show()
예제 #12
0
파일: code.py 프로젝트: tpDcc/tpDcc-libs-qt
class PythonCompleter(QCompleter, object):
    def __init__(self):
        super(PythonCompleter, self).__init__()

        self._info = None
        self._file_path = None
        self._model_strings = list()
        self._reset_list = True
        self._string_model = QStringListModel(self._model_strings, self)

        self._refresh_completer = True
        self._sub_activated = False
        self._last_imports = None
        self._last_lines = None
        self._last_path = None
        self._current_defined_imports = None
        self._last_path_and_part = None
        self._current_sub_functions = None
        self._last_column = 0

        self.setCompletionMode(self.PopupCompletion)
        self.setCaseSensitivity(Qt.CaseInsensitive)
        self.setModel(self._string_model)
        self.setWrapAround(False)

        self.activated.connect(self._on_insert_completion)

    def setWidget(self, widget):
        super(PythonCompleter, self).setWidget(widget)
        self.setParent(widget)

    def keyPressEvent(self):
        return

    def show_info_popup(self, info=None):
        self._info = QTextEdit()
        self._info.setEnabled(False)
        self._info.setWindowFlags(Qt.Popup)
        self._info.show()

    def get_imports(self, paths=None):
        imports = self._get_available_modules(paths=paths)
        imports.sort()

        return imports

    def get_sub_imports(self, path):
        """
        Returns namespace in a module
        :param path: str
        :return: str
        """

        defined = code.get_defined(path)
        defined.sort()

        return defined

    def clear_completer_list(self):
        self._string_model.setStringList([])

    def text_under_cursor(self):
        cursor = self.widget().textCursor()
        cursor.select(cursor.LineUnderCursor)

        return cursor.selectedText()

    def set_filepath(self, file_path):
        if not file_path:
            return

        self._file_path = file_path

    def handle_text(self, text):
        """
        Parses a single line of text
        :param text: str
        :return: bool
        """

        if not text:
            return False

        cursor = self.widget().textCursor()
        column = cursor.columnNumber() - 1
        if column < self._last_column:
            self._last_column = column
            return False
        self._last_column = column

        if column == 1:
            return False
        text = str(text)
        passed = self.handle_from_import(text, column)
        if passed:
            return True
        passed = self.handle_sub_import(text, column)
        if passed:
            return True
        passed = self.handle_import_load(text, cursor)
        if passed:
            return True

        return False

    def handle_import(self, text):
        m = re.search(r'(from|import)(?:\s+?)(\w*)', text)
        if m:
            # TODO: Find available modules in Python path
            pass

    def handle_sub_import(self, text, column):
        m = re.search(r'(from|import)(?:\s+?)(\w*.?\w*)\.(\w*)$', text)
        if m:
            if column < m.end(2):
                return False
            from_module = m.group(2)
            module_path = code.get_package_path_from_name(from_module)
            last_part = m.group(3)
            if module_path:
                defined = self.get_imports(module_path)
                self._string_model.setStringList(defined)
                self.setCompletionPrefix(last_part)
                self.popup().setCurrentIndex(self.completionModel().index(
                    0, 0))
                return True

        return False

    def handle_import_load(self, text, cursor):
        column = cursor.columnNumber() - 1
        text = text[:cursor.columnNumber()]
        m = re.search(r'\s*([a-zA-Z0-9._]+)\.([a-zA-Z0-9_]*)$', text)
        block_number = cursor.blockNumber()
        line_number = block_number + 1
        all_text = self.widget().toPlainText()
        scope_text = all_text[:(cursor.position() - 1)]

        if m and m.group(2):
            scope_text = all_text[:(cursor.position() - len(m.group(2)) + 1)]
        if not m:
            return False

        assignment = m.group(1)
        if column < m.end(1):
            return False

        sub_m = re.search(r'(from|import)\s+(%s)' % assignment, text)
        if sub_m:
            return False

        path = None
        sub_part = None
        target = None

        text = self.widget().toPlainText()
        lines = fileio.get_text_lines(text)

        # Search for assignments
        assign_map = code.get_ast_assignment(scope_text, line_number - 1,
                                             assignment)
        if assign_map:
            if assignment in assign_map:
                target = assign_map[assignment]
            else:
                split_assignment = assignment.split('.')
                inc = 1

                while assignment not in assign_map:
                    sub_assignment = string.join(split_assignment[:(inc * -1)],
                                                 '.')
                    if sub_assignment in assign_map:
                        target = assign_map[sub_assignment]
                        break
                    inc += 1
                    if inc > (len(split_assignment) - 1):
                        break
                sub_part = string.join(split_assignment[inc:], '.')

        module_name = m.group(1)
        if target and len(target) == 2:
            if target[0] == 'import':
                module_name = target[1]
            if not target[0] == 'import':
                module_name = target[0]
                sub_part = target[1]

        # import from module
        if module_name:
            imports = None
            if lines == self.last_lines:
                imports = self.last_imports
            if not imports:
                imports = code.get_line_imports(lines)

            self._last_imports = imports
            self._last_lines = lines

            if module_name in imports:
                path = imports[module_name]
            if module_name not in imports:
                split_assignment = module_name.split('.')
                last_part = split_assignment[-1]
                if last_part in imports:
                    path = imports[last_part]

            if path and not sub_part:
                test_text = ''
                defined = None
                if path == self.last_path:
                    defined = self.current_defined_imports
                if len(m.groups()) > 0:
                    test_text = m.group(2)
                if not defined:
                    defined = self.get_imports(path)
                    if defined:
                        self._current_defined_imports = defined
                    else:
                        defined = self.get_sub_imports(path)

                custom_defined = self.custom_import_load(
                    assign_map, module_name)
                if custom_defined:
                    defined = custom_defined
                if defined:
                    if test_text and test_text[0].islower():
                        defined.sort(key=str.swapcase)
                    self._string_model.setStringList(defined)
                    self.setCompletionPrefix(test_text)
                    self.setCaseSensitivity(Qt.CaseInsensitive)
                    self.popup().setCurrentIndex(self.completionModel().index(
                        0, 0))
                    return True

            # import from a class of a module
            if path and sub_part:

                sub_functions = None
                if self.last_path_and_part:
                    if path == self.last_path_and_part[
                            0] and sub_part == self.last_path_and_part[1]:
                        sub_functions = self.current_sub_functions

                if not sub_functions:
                    sub_functions = code.get_ast_class_sub_functions(
                        path, sub_part)
                    if sub_functions:
                        self._current_sub_functions = sub_functions

                self._last_path_and_part = [path, sub_part]
                if not sub_functions:
                    return False

                test_text = ''
                if len(m.groups()) > 0:
                    test_text = m.group(2)
                if test_text and test_text[0].islower():
                    sub_functions.sort(key=str.swapcase)
                self._string_model.setStringList(sub_functions)
                self.setCompletionPrefix(test_text)
                self.setCaseSensitivity(Qt.CaseInsensitive)
                self.popup().setCurrentIndex(self.completionModel().index(
                    0, 0))
                return True

        module_name = m.group(1)
        if module_name:
            custom_defined = self.custom_import_load(assign_map, module_name)

            test_text = ''
            if len(m.groups()) > 0:
                test_text = m.group(2)

            if test_text and test_text[0].islower():
                custom_defined.sort(key=str.swapcase)
            self._string_model.setStringList(custom_defined)
            self.setCompletionPrefix(test_text)
            self.setCaseSensitivity(Qt.CaseInsensitive)
            self.popup().setCurrentIndex(self.completionModel().index(0, 0))
            return True

        return False

    def handle_from_import(self, text, column):
        m = re.search(
            r'(from)(?:\s+?)(\w*.?\w*)(?:\s+?)(import)(?:\s+?)(\w+)?$', text)
        if m:
            if column < m.end(3):
                return False
            from_module = m.group(2)
            module_path = code.get_package_path_from_name(from_module)

            last_part = m.group(4)
            if not last_part:
                last_part = ''
            if module_path:
                defined = self.get_imports(module_path)
                self._string_model.setStringList(defined)
                self.setCompletionPrefix(last_part)
                self.popup().setCurrentIndex(self.completionModel().index(
                    0, 0))

                return True

        return False

    def custom_import_load(self, assign_map, moduel_name):
        return

    def _get_available_modules(self, paths=None):
        imports = list()
        if not paths:
            paths = sys.path
        if paths:
            paths = python.force_list(paths)

        for path in paths:
            fix_path = path_utils.normalize_path(path)
            stuff_in_folder = folder_utils.get_files_and_folders(fix_path)
            for file_or_folder in stuff_in_folder:
                folder_path = path_utils.join_path(fix_path, file_or_folder)
                files = folder_utils.get_files_with_extension('py',
                                                              folder_path,
                                                              full_path=False)
                if '__init__.py' in files:
                    imports.append(str(file_or_folder))

            python_files = folder_utils.get_files_with_extension(
                'py', fix_path, full_path=False)
            for python_file in python_files:
                if python_file.startswith('__'):
                    continue
                python_file_name = python_file.split('.')[0]
                imports.append(str(python_file_name))

        if imports:
            imports = list(set(imports))

        return imports

    def _on_insert_completion(self, completion_string):
        widget = self.widget()
        cursor = widget.textCursor()
        if completion_string == self.completionPrefix():
            return
        extra = len(self.completionPrefix())
        cursor.movePosition(QTextCursor.Left, cursor.KeepAnchor, extra)
        cursor.removeSelectedText()
        cursor.insertText(completion_string)
        widget.setTextCursor(cursor)
예제 #13
0
class NameIt(base.BaseWidget, object):

    ACTIVE_RULE = None

    def __init__(self, naming_lib, data_file=None, parent=None):
        self._naming_lib = naming_lib
        self._data_file = None
        super(NameIt, self).__init__(parent=parent)
        self.set_data_file(data_file)

    def get_active_rule(self):
        """
        Returns the current naming active rule
        """

        return self._naming_lib.active_rule()

    def set_active_rule(self, name):
        """
        Sets the current active rule
        :param name: str
        """

        # First, we clean the status of the naming library
        self._naming_lib.remove_all_tokens()
        self._naming_lib.remove_all_rules()

        self._naming_lib.load_session()

        # Load rules from the naming manager
        rules = self._naming_lib.rules
        for rule in rules:
            expressions = rule.get_expression_tokens()
            self._naming_lib.add_rule(rule.name, rule.iterator_format,
                                      *expressions)

        # Load tokens from the naming manager
        tokens = self._naming_lib.tokens
        for token in tokens:
            tokens_keywords = token.get_values_as_keyword()
            self._naming_lib.add_token(token.name, **tokens_keywords)

        self._naming_lib.set_active_rule(name)

    def set_active_rule_iterator(self, iterator_format):
        active_rule = self.get_active_rule()
        if not active_rule:
            return

    def set_active_rule_auto_fix(self, auto_fix):
        active_rule = self.get_active_rule()
        if not active_rule:
            return

        self._naming_lib.set_rule_auto_fix(active_rule.name(), auto_fix)

    def solve(self, *args, **kwargs):
        if len(args) > 0 and len(kwargs) > 0:
            return self._naming_lib.solve(*args, **kwargs)
        else:
            if len(args) > 0:
                return self._naming_lib.solve(*args)
            else:
                return self._naming_lib.solve(**kwargs)

    def ui(self):
        super(NameIt, self).ui()

        tools_toolbar = toolbar.ToolBar('Main ToolBar', parent=self)
        tools_toolbar.setMovable(False)
        # tools_toolbar.setAllowedAreas(Qt.TopToolBarArea | Qt.BottomToolBarArea)
        self.main_layout.addWidget(tools_toolbar)

        refresh_btn = buttons.BaseToolButton(parent=tools_toolbar)
        refresh_btn.setIcon(resources.icon('refresh'))
        refresh_btn.clicked.connect(self._on_refresh)
        self._refresh_btn = tools_toolbar.addWidget(refresh_btn)
        self._refresh_btn.setEnabled(False)

        save_btn = buttons.BaseToolButton(parent=tools_toolbar)
        save_btn.setIcon(resources.icon('save'))
        save_btn.clicked.connect(self._on_save)
        self._save_btn = tools_toolbar.addWidget(save_btn)
        self._save_btn.setEnabled(False)

        if self._is_renamer_tool_available():
            renamer_btn = buttons.BaseToolButton(parent=tools_toolbar)
            renamer_btn.setIcon(resources.icon('rename'))
            renamer_btn.clicked.connect(self._on_open_renamer_tool)
            tools_toolbar.addWidget(renamer_btn)

        self._name_file_line = directory.SelectFile(label_text='Naming File',
                                                    parent=tools_toolbar)
        tools_toolbar.addWidget(self._name_file_line)

        base_layout = layouts.HorizontalLayout(spacing=0, margins=(0, 0, 0, 0))
        self.main_layout.addLayout(base_layout)

        panels_splitter = QSplitter(parent=self)
        panels_splitter.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Expanding)
        base_layout.addWidget(panels_splitter)

        left_panel_widget = QWidget()
        left_panel_layout = layouts.VerticalLayout(margins=(5, 0, 5, 0))
        left_panel_widget.setLayout(left_panel_layout)
        panels_splitter.addWidget(left_panel_widget)

        # Tab Widget
        rules_tab = QWidget()
        tokens_tab = QWidget()
        templates_tab = QWidget()
        templates_tokens_tab = QWidget()

        self.tabs = tabs.BaseTabWidget()
        self.tabs.addTab(rules_tab, 'Rules')
        self.tabs.addTab(tokens_tab, 'Tokens')
        self.tabs.addTab(templates_tab, 'Templates')
        self.tabs.addTab(templates_tokens_tab, 'Templates Tokens')
        left_panel_layout.addWidget(self.tabs)

        # Rules Tab
        rules_main_layout = layouts.VerticalLayout(spacing=0,
                                                   margins=(5, 5, 5, 5))
        self.rules_list = QListWidget()
        rules_main_layout.addWidget(self.rules_list)
        left_panel_buttons_layout_rules = layouts.HorizontalLayout(margins=(5,
                                                                            5,
                                                                            5,
                                                                            0))
        rules_main_layout.addLayout(left_panel_buttons_layout_rules)
        self.add_rule_btn = buttons.BaseButton(parent=self)
        self.remove_rule_btn = buttons.BaseButton(parent=self)
        self.add_rule_btn.setIcon(resources.icon('plus'))
        self.remove_rule_btn.setIcon(resources.icon('minus'))
        left_panel_buttons_layout_rules.addStretch()
        left_panel_buttons_layout_rules.addWidget(self.add_rule_btn)
        left_panel_buttons_layout_rules.addWidget(self.remove_rule_btn)
        rules_tab.setLayout(rules_main_layout)

        # Tokens Tab
        tokens_main_layout = layouts.VerticalLayout(margins=(5, 5, 5, 5))
        tokens_main_layout.setSpacing(0)
        self.tokens_list = QListWidget()
        tokens_main_layout.addWidget(self.tokens_list)
        left_panel_buttons_layout_tokens = layouts.HorizontalLayout(
            margins=(5, 5, 5, 0))
        tokens_main_layout.addLayout(left_panel_buttons_layout_tokens)
        self.add_token_btn = buttons.BaseButton(parent=self)
        self.remove_token_btn = buttons.BaseButton(parent=self)
        self.add_token_btn.setIcon(resources.icon('plus'))
        self.remove_token_btn.setIcon(resources.icon('minus'))
        left_panel_buttons_layout_tokens.addStretch()
        left_panel_buttons_layout_tokens.addWidget(self.add_token_btn)
        left_panel_buttons_layout_tokens.addWidget(self.remove_token_btn)
        tokens_tab.setLayout(tokens_main_layout)

        # Templates Tab
        templates_main_layout = layouts.VerticalLayout(spacing=0,
                                                       margins=(5, 5, 5, 5))
        self.templates_list = QListWidget()
        templates_main_layout.addWidget(self.templates_list)
        left_panel_buttons_layout_templates = layouts.HorizontalLayout(
            margins=(5, 5, 5, 0))
        templates_main_layout.addLayout(left_panel_buttons_layout_templates)
        self.add_template_btn = buttons.BaseButton(parent=self)
        self.remove_template_btn = buttons.BaseButton(parent=self)
        self.add_template_btn.setIcon(resources.icon('plus'))
        self.remove_template_btn.setIcon(resources.icon('minus'))
        left_panel_buttons_layout_templates.addStretch()
        left_panel_buttons_layout_templates.addWidget(self.add_template_btn)
        left_panel_buttons_layout_templates.addWidget(self.remove_template_btn)
        templates_tab.setLayout(templates_main_layout)

        # Template Tokens Tab
        templates_tokens_main_layout = layouts.VerticalLayout(spacing=0,
                                                              margins=(5, 5, 5,
                                                                       5))
        self.template_tokens_list = QListWidget()
        templates_tokens_main_layout.addWidget(self.template_tokens_list)
        left_panel_buttons_layout_templates_tokens = layouts.HorizontalLayout(
            margins=(5, 5, 5, 0))
        left_panel_buttons_layout_templates_tokens.setContentsMargins(
            5, 5, 5, 0)
        templates_tokens_main_layout.addLayout(
            left_panel_buttons_layout_templates_tokens)
        self.add_template_token_btn = buttons.BaseButton(parent=self)
        self.remove_template_token_btn = buttons.BaseButton(parent=self)
        self.add_template_token_btn.setIcon(resources.icon('plus'))
        self.remove_template_token_btn.setIcon(resources.icon('minus'))
        left_panel_buttons_layout_templates_tokens.addStretch()
        left_panel_buttons_layout_templates_tokens.addWidget(
            self.add_template_token_btn)
        left_panel_buttons_layout_templates_tokens.addWidget(
            self.remove_template_token_btn)
        templates_tokens_tab.setLayout(templates_tokens_main_layout)

        # === PROPERTIES === #
        main_group = QGroupBox('Properties')
        panels_splitter.addWidget(main_group)

        self.group_layout = layouts.VerticalLayout(spacing=0,
                                                   margins=(5, 5, 5, 5))
        main_group.setLayout(self.group_layout)

        # Rules Panel
        self.rules_widget = QWidget(self)
        rules_layout = layouts.GridLayout()
        self.rules_widget.setLayout(rules_layout)
        expression_lbl = label.BaseLabel('Expression', parent=self)
        self.expression_line = lineedit.BaseLineEdit(parent=self)
        self.expression_btn = buttons.BaseButton('   <', parent=self)
        self.expression_btn.setEnabled(False)
        self.expression_btn.setStyleSheet(
            "QPushButton::menu-indicator{image:url(none.jpg);}")
        self.expression_menu = QMenu(self)
        self.expression_btn.setMenu(self.expression_menu)
        iterator_lbl = label.BaseLabel('Iterator', parent=self)
        self.iterator_cbx = combobox.BaseComboBox(parent=self)
        for it_format in [
                '@', '@^', '#', '##', '###', '####', '#####', 'None'
        ]:
            self.iterator_cbx.addItem(it_format)
        description_rule_lbl = label.BaseLabel('Description', parent=self)
        self.description_rule_text = QTextEdit(parent=self)
        self.group_layout.addWidget(self.rules_widget)

        rules_layout.addWidget(expression_lbl, 0, 0, Qt.AlignRight)
        rules_layout.addWidget(self.expression_line, 0, 1)
        rules_layout.addWidget(self.expression_btn, 0, 2)
        rules_layout.addWidget(iterator_lbl, 1, 0, Qt.AlignRight | Qt.AlignTop)
        rules_layout.addWidget(self.iterator_cbx, 1, 1, 1, 2)
        rules_layout.addWidget(description_rule_lbl, 2, 0,
                               Qt.AlignRight | Qt.AlignTop)
        rules_layout.addWidget(self.description_rule_text, 2, 1, 1, 2)

        # Tokens Panel
        self.tokens_widget = QWidget(parent=self)
        tokens_layout = layouts.GridLayout()
        self.tokens_widget.setLayout(tokens_layout)
        values_lbl = label.BaseLabel('Values')
        data = {'key': list(), 'value': list()}
        self.values_table = TokensTable(data, 0, 2)
        self.values_table.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Expanding)
        values_buttons_layout = layouts.HorizontalLayout(margins=(5, 5, 5, 0))
        self.add_key_value_btn = buttons.BaseButton(parent=self)
        self.remove_key_value_btn = buttons.BaseButton(parent=self)
        self.add_key_value_btn.setIcon(resources.icon('plus'))
        self.remove_key_value_btn.setIcon(resources.icon('minus'))
        values_buttons_layout.addWidget(self.add_key_value_btn)
        values_buttons_layout.addWidget(self.remove_key_value_btn)
        values_buttons_layout.addStretch()
        default_lbl = label.BaseLabel('Default', parent=self)
        self.default_cbx = combobox.BaseComboBox(parent=self)
        description_tokens_lbl = label.BaseLabel('Description', parent=self)
        self.description_token_text = QTextEdit(parent=self)
        self.group_layout.addWidget(self.tokens_widget)
        self.tokens_widget.hide()
        tokens_layout.addWidget(values_lbl, 0, 0, Qt.AlignRight | Qt.AlignTop)
        tokens_layout.addWidget(self.values_table, 0, 1, 2, 1)
        tokens_layout.addLayout(values_buttons_layout, 0, 2)
        tokens_layout.addWidget(default_lbl, 4, 0, Qt.AlignRight)
        tokens_layout.addWidget(self.default_cbx, 4, 1, 1, 2)
        tokens_layout.addWidget(description_tokens_lbl, 5, 0,
                                Qt.AlignRight | Qt.AlignTop)
        tokens_layout.addWidget(self.description_token_text, 5, 1, 1, 2)

        # Templates Panel
        self.templates_widget = QWidget(parent=self)
        templates_layout = layouts.VerticalLayout()
        self.templates_widget.setLayout(templates_layout)
        pattern_layout = layouts.HorizontalLayout(spacing=5,
                                                  margins=(5, 5, 5, 5))
        pattern_lbl = label.BaseLabel('Pattern: ', parent=self)
        self.pattern_line = lineedit.BaseLineEdit(parent=self)
        pattern_layout.addWidget(pattern_lbl)
        pattern_layout.addWidget(self.pattern_line)
        templates_layout.addLayout(pattern_layout)
        templates_layout.addLayout(dividers.DividerLayout())
        self.template_tokens_layout = layouts.GridLayout()
        self.template_tokens_layout.setAlignment(Qt.AlignTop)
        template_tokens_frame = QFrame(parent=self)
        template_tokens_frame.setFrameShape(QFrame.StyledPanel)
        template_tokens_frame.setFrameShadow(QFrame.Sunken)
        template_tokens_frame.setLayout(self.template_tokens_layout)
        templates_layout.addWidget(template_tokens_frame)
        self.group_layout.addWidget(self.templates_widget)
        self.templates_widget.hide()

        # Templates Tokens Panel
        self.templates_tokens_widget = QWidget(parent=self)
        templates_tokens_layout = layouts.VerticalLayout()
        self.templates_tokens_widget.setLayout(templates_tokens_layout)
        description_templates_token_layout = layouts.HorizontalLayout(
            spacing=5, margins=(5, 5, 5, 5))
        description_tokens_layout = layouts.VerticalLayout()
        description_templates_token_lbl = label.BaseLabel('Description: ',
                                                          parent=self)
        description_tokens_layout.addWidget(description_templates_token_lbl)
        description_tokens_layout.addStretch()
        self.description_templates_token_text = QTextEdit(parent=self)
        description_templates_token_layout.addLayout(description_tokens_layout)
        description_templates_token_layout.addWidget(
            self.description_templates_token_text)
        templates_tokens_layout.addLayout(description_templates_token_layout)
        self.group_layout.addWidget(self.templates_tokens_widget)
        self.templates_tokens_widget.hide()

        # Initialize database
        self._init_db()

        # First update of the UI
        self.update_expression_menu()
        self.update_tokens_properties_state()
        self.update_rules_properties_state()
        self.update_templates_properties_state()

    def setup_signals(self):
        super(NameIt, self).setup_signals()

        self.tabs.currentChanged.connect(self._on_change_tab)
        self._name_file_line.directoryChanged.connect(
            self._on_naming_file_changed)
        self.add_rule_btn.clicked.connect(self._on_add_rule)
        self.remove_rule_btn.clicked.connect(self._on_remove_rule)
        self.rules_list.currentItemChanged.connect(self._on_change_rule)
        self.rules_list.itemChanged.connect(self._on_edit_rule_name)
        self.expression_line.textChanged.connect(self._on_edit_rule_expression)
        self.description_rule_text.textChanged.connect(
            self._on_edit_rule_description)
        self.iterator_cbx.currentIndexChanged.connect(
            self._on_edit_rule_iterator)
        self.add_token_btn.clicked.connect(self._on_add_token)
        self.remove_token_btn.clicked.connect(self._on_remove_token)
        self.tokens_list.currentItemChanged.connect(self._on_change_token)
        self.tokens_list.itemChanged.connect(self._on_edit_token_name)
        self.values_table.itemChanged.connect(self._on_change_token_value)
        self.add_key_value_btn.clicked.connect(self._on_add_token_value)
        self.remove_key_value_btn.clicked.connect(self._on_remove_token_value)
        self.description_token_text.textChanged.connect(
            self._on_edit_token_description)
        self.default_cbx.currentIndexChanged.connect(
            self._on_edit_token_default)
        self.add_template_btn.clicked.connect(self._on_add_template)
        self.remove_template_btn.clicked.connect(self._on_remove_template)
        self.templates_list.currentItemChanged.connect(
            self._on_change_template)
        self.templates_list.itemChanged.connect(self._on_edit_template_name)
        self.pattern_line.textChanged.connect(self._on_edit_template_pattern)
        self.add_template_token_btn.clicked.connect(
            self._on_add_template_token)
        self.remove_template_token_btn.clicked.connect(
            self._on_remove_template_token)
        self.template_tokens_list.currentItemChanged.connect(
            self._on_change_template_token)
        self.template_tokens_list.itemChanged.connect(
            self._on_edit_template_token_name)
        self.description_templates_token_text.textChanged.connect(
            self._on_edit_template_token_description)

    def set_data_file(self, data_file):
        """
        Sets the data file used by the naming library
        :param data_file: str
        """

        if data_file and os.path.isfile(data_file):
            self._naming_lib.naming_file = data_file
            self._data_file = data_file
        else:
            naming_file = self._naming_lib.naming_file
            if naming_file and os.path.isfile(naming_file):
                self._data_file = self._naming_lib.naming_file
            else:
                self._data_file = self._get_default_data_file()
            self._naming_lib.naming_file = self._data_file

        self._init_db()

    def add_expression(self, name):
        """
        Add an expression to the list of expressions
        :param str name: Expression name
        :return: None
        """

        if self.expression_line.text() == '':
            self.expression_line.setText('{' + name + '}')
        else:
            self.expression_line.setText(self.expression_line.text() + '_{' +
                                         name + '}')

    def update_expression_menu(self):
        """
        Updates the expression menu
        :return:
        """

        # First, we clear the expression menu
        self.expression_menu.clear()

        tokens = self._naming_lib.tokens
        if tokens and len(tokens) > 0:
            self.expression_btn.setEnabled(True)
            for token in tokens:
                self.expression_menu.addAction(
                    token.name, partial(self.add_expression, token.name))
        else:
            self.expression_btn.setEnabled(False)

    def update_expression_state(self):
        # TODO: This method is used to check the name of the expression (its different parts) and
        # TODO: check if some token of the expression does not exist and in that case, update the expression
        # TODO: so it becomes a valid expression
        pass

    def update_rules_properties_state(self):
        if self.rules_list.count() <= 0 or self.rules_list.currentItem(
        ) is None:
            self.expression_line.setText('')
            self.description_rule_text.setText('')
            self.iterator_cbx.setCurrentIndex(0)
            self.rules_widget.setEnabled(False)
        else:
            rule = self._naming_lib.get_rule(
                self.rules_list.currentItem().text())
            if rule is not None:
                self.expression_line.setText(rule.expression)
                self.description_rule_text.setText(rule.description)
                self.iterator_cbx.setCurrentText(rule.iterator_format)
                self.rules_widget.setEnabled(True)

    def update_tokens_properties_state(self):
        if self.tokens_list.currentItem() is None:
            self.tokens_widget.setEnabled(False)
        else:
            self.tokens_widget.setEnabled(True)

    def update_default_token_list(self):

        self.default_cbx.blockSignals(True)

        for i in range(self.default_cbx.count()):
            self.default_cbx.removeItem(self.default_cbx.count() - 1)

        item_text = self.tokens_list.currentItem().text()
        self.default_cbx.addItem('')
        tokens = self._naming_lib.tokens
        for token in tokens:
            if token.name != item_text:
                continue
            for value in token.values['key']:
                self.default_cbx.addItem(value)

        token = self._naming_lib.get_token(item_text)
        if token:
            self.default_cbx.setCurrentIndex(token.default)

        self.default_cbx.blockSignals(False)

    def update_tokens_key_table(self):

        item_text = self.tokens_list.currentItem().text()
        self.clean_tokens_key_table()
        if self.tokens_list.count() > 0:
            keys = []
            values = []
            tokens = self._naming_lib.tokens
            for token in tokens:
                if token.name != item_text:
                    continue
                for i in range(len(token.values['key'])):
                    self.values_table.insertRow(self.values_table.rowCount())
                    keys.append(QTableWidgetItem())
                    values.append(QTableWidgetItem())

                for index, value in enumerate(token.values['key']):
                    keys[index].setText(value)
                    self.values_table.setItem(index, 0, keys[index])

                for index, value in enumerate(token.values['value']):
                    values[index].setText(value)
                    self.values_table.setItem(index, 1, values[index])

    def clean_tokens_key_table(self):
        for i in range(self.values_table.rowCount()):
            self.values_table.removeRow(self.values_table.rowCount() - 1)

    def update_templates_properties_state(self):
        if self.templates_list.count() <= 0 or self.templates_list.currentItem(
        ) is None:
            self.pattern_line.setText('')
            self.templates_widget.setEnabled(False)
        else:
            template = self._naming_lib.get_template(
                self.templates_list.currentItem().text())
            if template is not None:
                self.pattern_line.setText(template.pattern)
                self.templates_widget.setEnabled(True)
                self._update_template_tokens(template)

    def _init_db(self):
        """
        Initializes the naming data base
        """

        self._naming_lib.init_naming_data()
        self._init_data()
        self._name_file_line.set_directory(str(self._naming_lib.naming_file))

    def _init_data(self):
        if self._load_rules():
            self._load_tokens()
        self._load_templates()
        self._load_template_tokens()

    def _get_default_data_file(self):
        """
        Internal function that returns default path to nameing data file
        :return: str
        """

        return os.path.join(
            os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
            'data', 'naming_data.json')

    def _load_rules(self):
        """
        Internal function that load rules from data file
        """

        self.rules_list.clear()

        rules = self._naming_lib.rules
        if not rules:
            return False

        for rule in rules:
            if rule == '_active':
                continue
            self._on_add_rule(rule)

        return True

    def _load_tokens(self):
        """
        Load tokens from data file
        """

        self.tokens_list.clear()

        tokens = self._naming_lib.tokens
        if not tokens:
            return False

        for token in tokens:
            self._on_add_token(token)

        return True

    def _load_templates(self):
        """
        Internal function that loads templates from DB
        """

        try:
            templates = self._naming_lib.templates
            self.templates_list.clear()
            if templates is not None:
                for template in templates:
                    self._on_add_template(template)
            return True
        except Exception as e:
            logger.error(
                'Error while loading templates from: {} | {} | {}'.format(
                    self.DATA_FILE, e, traceback.format_exc()))

        return False

    def _load_template_tokens(self):
        """
        Internal function that loads template tokens from DB
        """

        try:
            template_tokens = self._naming_lib.template_tokens
            self.template_tokens_list.clear()
            if template_tokens is not None:
                for template_token in template_tokens:
                    self._on_add_template_token(template_token)
            return True
        except Exception as e:
            logger.error(
                'Error while loading template tokens from: {} | {} | {}'.
                format(self.DATA_FILE, e, traceback.format_exc()))

        return False

    def _clear_template_tokens(self):
        """
        Intenral function that clears all template tokens from layout
        """

        for i in range(self.template_tokens_layout.count(), -1, -1):
            item = self.template_tokens_layout.itemAt(i)
            if item is None:
                continue
            item.widget().setParent(None)
            self.template_tokens_layout.removeItem(item)

    def _add_template_token(self,
                            template_token_name,
                            template_token_description=None):
        """
        Adds template token to layout
        :param template_token_name: str
        :param template_token_data: dict
        """

        row = 0
        while self.template_tokens_layout.itemAtPosition(row, 0) is not None:
            row += 1

        self.template_tokens_layout.addWidget(
            label.BaseLabel(template_token_name), row, 0)
        self.template_tokens_layout.addWidget(
            label.BaseLabel(template_token_description
                            if template_token_description else '< NOT FOUND >',
                            parent=self), row, 1)

    def _update_template_tokens(self, template):
        """
        Internal function that updates template tokens currently loaded
        :param template: Template
        """

        if not template:
            return

        temp_tokens = list()
        try:
            temp = self._naming_lib.get_template(template.name)
            # temp = lucidity.Template(template.name, template.pattern)
            temp_template = temp.template
            temp_template.duplicate_placeholder_mode = lucidity.Template.STRICT
            temp_tokens = temp_template.keys()
        except (ValueError, lucidity.error.ResolveError) as exc:
            self._clear_template_tokens()
            return

        template_tokens = self._naming_lib.template_tokens

        self._clear_template_tokens()

        for token in temp_tokens:
            token_found = False
            for template_token in template_tokens:
                if token == template_token.name:
                    self._add_template_token(token, template_token.description)
                    token_found = True

            if not token_found:
                self._add_template_token(token)

    def _on_change_tab(self, tab_index):
        """
        This methods changes the properties tab widgets
        :param tab_index: Index of the current tab (0:rules tab, 1:tokens tab)
        :return: None
        """

        if tab_index == 0:
            self.rules_widget.show()
            self.tokens_widget.hide()
            self.templates_widget.hide()
            self.templates_tokens_widget.hide()
            self.update_expression_menu()
            self.update_expression_state()
        elif tab_index == 1:
            self.rules_widget.hide()
            self.tokens_widget.show()
            self.templates_widget.hide()
            self.templates_tokens_widget.hide()
            self.update_tokens_properties_state()
        elif tab_index == 2:
            self.rules_widget.hide()
            self.tokens_widget.hide()
            self.templates_widget.show()
            self.templates_tokens_widget.hide()
            self.update_templates_properties_state()
        else:
            self.rules_widget.hide()
            self.tokens_widget.hide()
            self.templates_widget.hide()
            self.templates_tokens_widget.show()

    def _on_naming_file_changed(self, file_path):
        """
        Internal callback function that is called when a new file path is set
        :param file_path: str
        """

        self._naming_lib.naming_file = file_path

        if not file_path or not os.path.isfile(file_path):
            self._refresh_btn.setEnabled(False)
            self._save_btn.setEnabled(False)
        else:
            self._refresh_btn.setEnabled(True)
            self._save_btn.setEnabled(True)

        self._on_refresh()

    def _on_add_rule(self, *args):
        """
        Creates a new standard rule and add it to the Naming Manager
        :return:
        """

        load_rule = True
        if len(args) == 0:
            load_rule = False

        self.description_rule_text.blockSignals(True)

        rule = None
        if not load_rule:
            rule = self._naming_lib.get_rule_unique_name(name='New_Rule')
        elif load_rule and len(args) == 1:
            rule = args[0].name

        if rule is not None:
            # Create a new item based on the rule name and add it
            item = QListWidgetItem(rule)
            item.setFlags(item.flags() | Qt.ItemIsEditable)
            self.rules_list.addItem(item)

            # Add the data of the rule to our JSON data file
            if len(args) == 0:
                self._naming_lib.add_rule(rule)

            # Update necessary UI Widgets
            if not load_rule:
                self.rules_list.setCurrentItem(item)
            self.update_expression_menu()
            self.update_rules_properties_state()

        self.description_rule_text.blockSignals(False)

    def _on_remove_rule(self):
        """
        Remove the selected rule from the list of rules
        :return: bool, True if the element deletion is successful or False otherwise
        """

        self.description_rule_text.blockSignals(True)

        curr_rule = self.rules_list.currentItem()
        if curr_rule is not None:
            rule_name = self.rules_list.currentItem().text()
            rule = self._naming_lib.get_rule(rule_name)
            if rule is not None:
                self._naming_lib.remove_rule(rule_name)
                self.rules_list.takeItem(
                    self.rules_list.row(self.rules_list.currentItem()))
            self.update_rules_properties_state()

        self.description_rule_text.blockSignals(False)

    def _on_change_rule(self, rule_item):
        """
        Change the selected rule
        :param rule_item: new QListWidgetItem selected
        :return: None
        """

        if rule_item is not None:
            if rule_item.listWidget().count() > 0:
                rule = self._naming_lib.get_rule(rule_item.text())
                if rule is not None:
                    self.description_rule_text.setText(rule.description)
                    self.expression_line.setText(rule.expression)
                    self.iterator_cbx.setCurrentText(rule.iterator_format)
                    self.update_expression_menu()
                    self.update_rules_properties_state()

    def _on_edit_rule_name(self, rule_item):
        """
        Changes name of the rule
        :param rule_item: Renamed QListWidgetItem
        :return: None
        """

        rule_index = rule_item.listWidget().currentRow()
        rule = self._naming_lib.get_rule_by_index(rule_index)
        if rule:
            rule.name = rule_item.text()

    def _on_edit_rule_expression(self):
        """
        Changes expression of the selected rule
        :return: None
        """

        selected_rule = self.rules_list.currentItem()
        if not selected_rule:
            return
        rule_name = selected_rule.text()
        rule = self._naming_lib.get_rule(rule_name)
        if rule:
            rule.expression = self.expression_line.text()

    def _on_edit_rule_description(self):
        """
        Changes description of the selected rule
        :return: None
        """

        rule_name = self.rules_list.currentItem().text()
        rule = self._naming_lib.get_rule(rule_name)
        if rule:
            rule.description = self.description_rule_text.toPlainText()

    def _on_edit_rule_iterator(self, iterator_index):
        """
        Changes iterator of the selected rule
        :param iterator_index: int
        :return: None
        """

        rule_item = self.rules_list.currentItem()
        if not rule_item:
            return

        rule_name = rule_item.text()
        rule = self._naming_lib.get_rule(rule_name)
        if rule:
            rule.iterator_format = self.iterator_cbx.itemText(iterator_index)

    def _on_add_token(self, *args):
        """
        Creates a new token and add it to the Naming Manager
        :return: None
        """

        load_token = True
        if len(args) == 0:
            load_token = False

        token = None
        if not load_token:
            token = self._naming_lib.get_token_unique_name(name='New_Token')
        elif load_token and len(args) == 1:
            token = args[0].name

        if token:
            # Create a new item based on the token name and add it
            item = QListWidgetItem(token)
            item.setFlags(item.flags() | Qt.ItemIsEditable)
            self.tokens_list.addItem(item)

            # Add the data of the token to our JSON data file
            if len(args) == 0:
                self._naming_lib.add_token(token)

            # Update necessary UI wigdets
            if not load_token:
                self.tokens_list.setCurrentItem(item)

    def _on_remove_token(self):
        """
        Remove the selected token from the list of tokens
        :return: True if the element deletion is successfull or False otherwise
        """

        curr_token = self.tokens_list.currentItem()
        if curr_token is not None:
            token_index = self.tokens_list.currentRow()
            name = self.tokens_list.currentItem().text()
            if token_index > -1 and name is not None:
                token = self._naming_lib.get_token(name)
                if token is not None:
                    if token.name == name:
                        self._naming_lib.remove_token(name)
                        self.tokens_list.takeItem(
                            self.tokens_list.row(
                                self.tokens_list.currentItem()))

    def _on_change_token(self, token_item):
        """
        Change the selected token
        :param token_item: new QListWidgetItem selected
        :return: None
        """

        if token_item is not None:
            if token_item.listWidget().count() > 0:
                token = self._naming_lib.get_token(token_item.text())
                if token:
                    try:
                        self.description_rule_text.blockSignals(True)
                        self.default_cbx.blockSignals(True)
                        self.description_token_text.setText(token.description)
                        self.default_cbx.setCurrentIndex(int(token.default))
                    finally:
                        self.description_rule_text.blockSignals(False)
                        self.default_cbx.blockSignals(False)
                    self.update_tokens_properties_state()
                    self.update_tokens_key_table()
                    self.update_default_token_list()

    def _on_edit_token_name(self, token_item):
        """
        Changes name of the token
        :param token_item: Renamed QListWidgetItem
        :return:
        """

        token_index = self.tokens_list.currentRow()
        token = self._naming_lib.get_token_by_index(token_index)
        if token:
            token.name = token_item.text()

    def _on_change_token_value(self, item):
        """
        Called when we change a token value name
        :return: None
        """

        token_text = self.tokens_list.currentItem().text()
        token = self._naming_lib.get_token(token_text)
        if not token:
            return

        if self.tokens_list.currentRow() > -1 and item.row() > -1:

            if item.column() == 0:
                token.set_token_key(item.row(), item.text())
            else:
                token.set_token_value(item.row(), item.text())

            self.update_default_token_list()

    def _on_add_token_value(self, *args):

        self.description_rule_text.blockSignals(True)

        token_text = self.tokens_list.currentItem().text()
        token = self._naming_lib.get_token(token_text)
        if token:
            key_data = token.add_token_value()
            if key_data:
                self.clean_tokens_key_table()
                keys = list()
                values = list()
                for i in range(len(key_data['key'])):
                    self.values_table.insertRow(self.values_table.rowCount())
                    keys.append(QTableWidgetItem())
                    values.append(QTableWidgetItem())

                for index, value in enumerate(key_data['key']):
                    keys[index].setText(value)
                    self.values_table.setItem(index, 0, keys[index])

                for index, value in enumerate(key_data['value']):
                    values[index].setText(value)
                    self.values_table.setItem(index, 1, values[index])

                self.update_default_token_list()

                # new_index = self.default_cbx.currentIndex() + 2
                # self.default_cbx.setCurrentIndex(new_index)

        self.description_rule_text.blockSignals(False)

    def _on_remove_token_value(self):
        """
        Removes a token value from the list of tokens values
        """

        self.description_rule_text.blockSignals(True)

        token_text = self.tokens_list.currentItem().text()
        token = self._naming_lib.get_token(token_text)
        if token:
            key_data = token.remove_token_value(self.values_table.currentRow())
            if key_data:
                self.clean_tokens_key_table()

                keys = list()
                values = list()
                for i in range(len(key_data['key'])):
                    self.values_table.insertRow(self.values_table.rowCount())
                    keys.append(QTableWidgetItem())
                    values.append(QTableWidgetItem())

                for index, value in enumerate(key_data['key']):
                    keys[index].setText(value)
                    self.values_table.setItem(index, 0, keys[index])

                for index, value in enumerate(key_data['value']):
                    values[index].setText(value)
                    self.values_table.setItem(index, 1, values[index])

                self.update_default_token_list()

                new_index = self.default_cbx.currentIndex()
                token.default = new_index
                self.default_cbx.setCurrentIndex(new_index)

        self.description_rule_text.blockSignals(False)

    def _on_edit_token_default(self, index):
        """
        Edits the default token
        :param index: int, index of the token to edit
        """

        token_text = self.tokens_list.currentItem().text()
        token = self._naming_lib.get_token(token_text)
        if token:
            token.default = index

    def _on_edit_token_description(self):
        """
        Edits the token description
        """

        token_text = self.tokens_list.currentItem().text()
        token = self._naming_lib.get_token(token_text)
        if token:
            token.description = self.description_token_text.toPlainText(
            ).strip()

    def _on_add_template(self, *args):
        """
        Creates a new template and add it to the Naming Manager
        :return:
        """

        load_template = True
        if len(args) == 0:
            load_template = False

        template = None
        if not load_template:
            template = self._naming_lib.get_template_unique_name(
                'New_Template')
        elif load_template and len(args) == 1:
            template = args[0].name

        if template is not None:
            item = QListWidgetItem(template)
            item.setFlags(item.flags() | Qt.ItemIsEditable)
            self.templates_list.addItem(item)

            if len(args) == 0:
                self._naming_lib.add_template(template)

            if not load_template:
                self.templates_list.setCurrentItem(item)

    def _on_remove_template(self):
        """
        Removes the selected template from the list of templates
        :return: bool, True if the element deletion is successful or False otherwise
        """

        current_template = self.templates_list.currentItem()
        if current_template is not None:
            template_index = self.templates_list.currentRow()
            name = self.templates_list.currentItem().text()
            if template_index > -1 and name is not None:
                template = self._naming_lib.get_template(name)
                if template is not None:
                    if template.name == name:
                        valid_remove = self._naming_lib.remove_template(name)
                        if valid_remove:
                            self.templates_list.takeItem(
                                self.templates_list.row(
                                    self.templates_list.currentItem()))

    def _on_change_template(self, template_item):
        """
        Changes the selected template
        :param template_item: new QlistWidgetItem selected
        """

        if not template_item or not template_item.listWidget().count() > 0:
            return

        template_name = template_item.text()
        template = self._naming_lib.get_template(template_name)
        if not template:

            return

        self.pattern_line.setText(template.pattern)

        self.update_templates_properties_state()

    def _on_edit_template_name(self, template_item):
        """
        Changes name of the template
        :param template_item: Renamed QListWidgetItem
        """

        template_index = self.templates_list.currentRow()
        template = self._naming_lib.get_template_by_index(template_index)
        if template:
            template.name = template_item.text()

    def _on_edit_template_pattern(self, pattern_item):
        """
        Changes template pattern
        :param pattern_item:
        """

        template_index = self.templates_list.currentRow()
        template = self._naming_lib.get_template_by_index(template_index)
        if template:
            template.pattern = self.pattern_line.text()
            self._update_template_tokens(template)

    def _on_add_template_token(self, *args):
        """
        Creates a new template token
        :param args:
        :return:
        """

        load_template_token = True
        if len(args) == 0:
            load_template_token = False

        template_token = None
        if not load_template_token:
            template_token = self._naming_lib.get_template_token_unique_name(
                'New_Template_Token')
        elif load_template_token and len(args) == 1:
            template_token = args[0].name

        if template_token is not None:
            item = QListWidgetItem(template_token)
            item.setFlags(item.flags() | Qt.ItemIsEditable)
            self.template_tokens_list.addItem(item)

            if len(args) == 0:
                self._naming_lib.add_template_token(template_token)

            if not load_template_token:
                self.template_tokens_list.setCurrentItem(item)

    def _on_remove_template_token(self):
        """
        Remove the selected template token from the list of template tokens
        :return:
        """

        curr_template_token = self.template_tokens_list.currentItem()
        if curr_template_token is not None:
            template_token_index = self.template_tokens_list.currentRow()
            name = self.template_tokens_list.currentItem().text()
            if template_token_index > -1 and name is not None:
                template = self._naming_lib.get_template_token(name)
                if template.name == name:
                    valid_remove = self._naming_lib.remove_template_token(name)
                    if valid_remove:
                        self.template_tokens_list.takeItem(
                            self.template_tokens_list.row(
                                self.template_tokens_list.currentItem()))

    def _on_change_template_token(self, template_token_item):
        """
        Changes the selected template token
        :param template_item: new QlistWidgetItem selected
        """

        if not template_token_item or not template_token_item.listWidget(
        ).count() > 0:
            return

        template_tokien_name = template_token_item.text()
        template_token = self._naming_lib.get_template_token(
            template_tokien_name)
        if not template_token:
            return

        self.description_templates_token_text.setText(
            template_token.description)

    def _on_edit_template_token_name(self, token_template_item):
        """
        Changes name of the token
        :param token_template_item: Renamed QListWidgetItem
        :return:
        """

        token_index = self.template_tokens_list.currentRow()
        template_token = self._naming_lib.get_template_token_by_index(
            token_index)
        if template_token:
            template_token.name = token_template_item.text()

    def _on_edit_template_token_description(self):
        """
        Edits the template token description
        """

        template_token_text = self.template_tokens_list.currentItem().text()
        template_token = self._naming_lib.get_template_token(
            template_token_text)
        if template_token:
            template_token.description = self.description_templates_token_text.toPlainText(
            ).rstrip()

    def _on_open_renamer_tool(self):
        """
        Internal function that is used by toolbar to open Renamer Tool
        """

        try:
            tools.ToolsManager().launch_tool_by_id(
                'tpDcc-tools-renamer',
                naming_file=self._naming_lib.naming_file)
        except Exception:
            logger.warning('tpDcc-tools-renamer is not available!')
            return None

    def _is_renamer_tool_available(self):
        """
        Returns whether or not tpRenamer tool is available or not
        :return: bool
        """

        try:
            import tpDcc.tools.renamer
        except Exception:
            return False

        return True

    def _on_refresh(self):
        """
        Internal function that is called when save button is pressed
        """

        self._naming_lib.load_session()
        self._init_data()

    def _on_save(self):
        """
        Internal function that is called when save button is pressed
        """

        self._naming_lib.save_session()
예제 #14
0
    def ui(self):
        super(NameIt, self).ui()

        tools_toolbar = toolbar.ToolBar('Main ToolBar', parent=self)
        tools_toolbar.setMovable(False)
        # tools_toolbar.setAllowedAreas(Qt.TopToolBarArea | Qt.BottomToolBarArea)
        self.main_layout.addWidget(tools_toolbar)

        refresh_btn = buttons.BaseToolButton(parent=tools_toolbar)
        refresh_btn.setIcon(resources.icon('refresh'))
        refresh_btn.clicked.connect(self._on_refresh)
        self._refresh_btn = tools_toolbar.addWidget(refresh_btn)
        self._refresh_btn.setEnabled(False)

        save_btn = buttons.BaseToolButton(parent=tools_toolbar)
        save_btn.setIcon(resources.icon('save'))
        save_btn.clicked.connect(self._on_save)
        self._save_btn = tools_toolbar.addWidget(save_btn)
        self._save_btn.setEnabled(False)

        if self._is_renamer_tool_available():
            renamer_btn = buttons.BaseToolButton(parent=tools_toolbar)
            renamer_btn.setIcon(resources.icon('rename'))
            renamer_btn.clicked.connect(self._on_open_renamer_tool)
            tools_toolbar.addWidget(renamer_btn)

        self._name_file_line = directory.SelectFile(label_text='Naming File',
                                                    parent=tools_toolbar)
        tools_toolbar.addWidget(self._name_file_line)

        base_layout = layouts.HorizontalLayout(spacing=0, margins=(0, 0, 0, 0))
        self.main_layout.addLayout(base_layout)

        panels_splitter = QSplitter(parent=self)
        panels_splitter.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Expanding)
        base_layout.addWidget(panels_splitter)

        left_panel_widget = QWidget()
        left_panel_layout = layouts.VerticalLayout(margins=(5, 0, 5, 0))
        left_panel_widget.setLayout(left_panel_layout)
        panels_splitter.addWidget(left_panel_widget)

        # Tab Widget
        rules_tab = QWidget()
        tokens_tab = QWidget()
        templates_tab = QWidget()
        templates_tokens_tab = QWidget()

        self.tabs = tabs.BaseTabWidget()
        self.tabs.addTab(rules_tab, 'Rules')
        self.tabs.addTab(tokens_tab, 'Tokens')
        self.tabs.addTab(templates_tab, 'Templates')
        self.tabs.addTab(templates_tokens_tab, 'Templates Tokens')
        left_panel_layout.addWidget(self.tabs)

        # Rules Tab
        rules_main_layout = layouts.VerticalLayout(spacing=0,
                                                   margins=(5, 5, 5, 5))
        self.rules_list = QListWidget()
        rules_main_layout.addWidget(self.rules_list)
        left_panel_buttons_layout_rules = layouts.HorizontalLayout(margins=(5,
                                                                            5,
                                                                            5,
                                                                            0))
        rules_main_layout.addLayout(left_panel_buttons_layout_rules)
        self.add_rule_btn = buttons.BaseButton(parent=self)
        self.remove_rule_btn = buttons.BaseButton(parent=self)
        self.add_rule_btn.setIcon(resources.icon('plus'))
        self.remove_rule_btn.setIcon(resources.icon('minus'))
        left_panel_buttons_layout_rules.addStretch()
        left_panel_buttons_layout_rules.addWidget(self.add_rule_btn)
        left_panel_buttons_layout_rules.addWidget(self.remove_rule_btn)
        rules_tab.setLayout(rules_main_layout)

        # Tokens Tab
        tokens_main_layout = layouts.VerticalLayout(margins=(5, 5, 5, 5))
        tokens_main_layout.setSpacing(0)
        self.tokens_list = QListWidget()
        tokens_main_layout.addWidget(self.tokens_list)
        left_panel_buttons_layout_tokens = layouts.HorizontalLayout(
            margins=(5, 5, 5, 0))
        tokens_main_layout.addLayout(left_panel_buttons_layout_tokens)
        self.add_token_btn = buttons.BaseButton(parent=self)
        self.remove_token_btn = buttons.BaseButton(parent=self)
        self.add_token_btn.setIcon(resources.icon('plus'))
        self.remove_token_btn.setIcon(resources.icon('minus'))
        left_panel_buttons_layout_tokens.addStretch()
        left_panel_buttons_layout_tokens.addWidget(self.add_token_btn)
        left_panel_buttons_layout_tokens.addWidget(self.remove_token_btn)
        tokens_tab.setLayout(tokens_main_layout)

        # Templates Tab
        templates_main_layout = layouts.VerticalLayout(spacing=0,
                                                       margins=(5, 5, 5, 5))
        self.templates_list = QListWidget()
        templates_main_layout.addWidget(self.templates_list)
        left_panel_buttons_layout_templates = layouts.HorizontalLayout(
            margins=(5, 5, 5, 0))
        templates_main_layout.addLayout(left_panel_buttons_layout_templates)
        self.add_template_btn = buttons.BaseButton(parent=self)
        self.remove_template_btn = buttons.BaseButton(parent=self)
        self.add_template_btn.setIcon(resources.icon('plus'))
        self.remove_template_btn.setIcon(resources.icon('minus'))
        left_panel_buttons_layout_templates.addStretch()
        left_panel_buttons_layout_templates.addWidget(self.add_template_btn)
        left_panel_buttons_layout_templates.addWidget(self.remove_template_btn)
        templates_tab.setLayout(templates_main_layout)

        # Template Tokens Tab
        templates_tokens_main_layout = layouts.VerticalLayout(spacing=0,
                                                              margins=(5, 5, 5,
                                                                       5))
        self.template_tokens_list = QListWidget()
        templates_tokens_main_layout.addWidget(self.template_tokens_list)
        left_panel_buttons_layout_templates_tokens = layouts.HorizontalLayout(
            margins=(5, 5, 5, 0))
        left_panel_buttons_layout_templates_tokens.setContentsMargins(
            5, 5, 5, 0)
        templates_tokens_main_layout.addLayout(
            left_panel_buttons_layout_templates_tokens)
        self.add_template_token_btn = buttons.BaseButton(parent=self)
        self.remove_template_token_btn = buttons.BaseButton(parent=self)
        self.add_template_token_btn.setIcon(resources.icon('plus'))
        self.remove_template_token_btn.setIcon(resources.icon('minus'))
        left_panel_buttons_layout_templates_tokens.addStretch()
        left_panel_buttons_layout_templates_tokens.addWidget(
            self.add_template_token_btn)
        left_panel_buttons_layout_templates_tokens.addWidget(
            self.remove_template_token_btn)
        templates_tokens_tab.setLayout(templates_tokens_main_layout)

        # === PROPERTIES === #
        main_group = QGroupBox('Properties')
        panels_splitter.addWidget(main_group)

        self.group_layout = layouts.VerticalLayout(spacing=0,
                                                   margins=(5, 5, 5, 5))
        main_group.setLayout(self.group_layout)

        # Rules Panel
        self.rules_widget = QWidget(self)
        rules_layout = layouts.GridLayout()
        self.rules_widget.setLayout(rules_layout)
        expression_lbl = label.BaseLabel('Expression', parent=self)
        self.expression_line = lineedit.BaseLineEdit(parent=self)
        self.expression_btn = buttons.BaseButton('   <', parent=self)
        self.expression_btn.setEnabled(False)
        self.expression_btn.setStyleSheet(
            "QPushButton::menu-indicator{image:url(none.jpg);}")
        self.expression_menu = QMenu(self)
        self.expression_btn.setMenu(self.expression_menu)
        iterator_lbl = label.BaseLabel('Iterator', parent=self)
        self.iterator_cbx = combobox.BaseComboBox(parent=self)
        for it_format in [
                '@', '@^', '#', '##', '###', '####', '#####', 'None'
        ]:
            self.iterator_cbx.addItem(it_format)
        description_rule_lbl = label.BaseLabel('Description', parent=self)
        self.description_rule_text = QTextEdit(parent=self)
        self.group_layout.addWidget(self.rules_widget)

        rules_layout.addWidget(expression_lbl, 0, 0, Qt.AlignRight)
        rules_layout.addWidget(self.expression_line, 0, 1)
        rules_layout.addWidget(self.expression_btn, 0, 2)
        rules_layout.addWidget(iterator_lbl, 1, 0, Qt.AlignRight | Qt.AlignTop)
        rules_layout.addWidget(self.iterator_cbx, 1, 1, 1, 2)
        rules_layout.addWidget(description_rule_lbl, 2, 0,
                               Qt.AlignRight | Qt.AlignTop)
        rules_layout.addWidget(self.description_rule_text, 2, 1, 1, 2)

        # Tokens Panel
        self.tokens_widget = QWidget(parent=self)
        tokens_layout = layouts.GridLayout()
        self.tokens_widget.setLayout(tokens_layout)
        values_lbl = label.BaseLabel('Values')
        data = {'key': list(), 'value': list()}
        self.values_table = TokensTable(data, 0, 2)
        self.values_table.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Expanding)
        values_buttons_layout = layouts.HorizontalLayout(margins=(5, 5, 5, 0))
        self.add_key_value_btn = buttons.BaseButton(parent=self)
        self.remove_key_value_btn = buttons.BaseButton(parent=self)
        self.add_key_value_btn.setIcon(resources.icon('plus'))
        self.remove_key_value_btn.setIcon(resources.icon('minus'))
        values_buttons_layout.addWidget(self.add_key_value_btn)
        values_buttons_layout.addWidget(self.remove_key_value_btn)
        values_buttons_layout.addStretch()
        default_lbl = label.BaseLabel('Default', parent=self)
        self.default_cbx = combobox.BaseComboBox(parent=self)
        description_tokens_lbl = label.BaseLabel('Description', parent=self)
        self.description_token_text = QTextEdit(parent=self)
        self.group_layout.addWidget(self.tokens_widget)
        self.tokens_widget.hide()
        tokens_layout.addWidget(values_lbl, 0, 0, Qt.AlignRight | Qt.AlignTop)
        tokens_layout.addWidget(self.values_table, 0, 1, 2, 1)
        tokens_layout.addLayout(values_buttons_layout, 0, 2)
        tokens_layout.addWidget(default_lbl, 4, 0, Qt.AlignRight)
        tokens_layout.addWidget(self.default_cbx, 4, 1, 1, 2)
        tokens_layout.addWidget(description_tokens_lbl, 5, 0,
                                Qt.AlignRight | Qt.AlignTop)
        tokens_layout.addWidget(self.description_token_text, 5, 1, 1, 2)

        # Templates Panel
        self.templates_widget = QWidget(parent=self)
        templates_layout = layouts.VerticalLayout()
        self.templates_widget.setLayout(templates_layout)
        pattern_layout = layouts.HorizontalLayout(spacing=5,
                                                  margins=(5, 5, 5, 5))
        pattern_lbl = label.BaseLabel('Pattern: ', parent=self)
        self.pattern_line = lineedit.BaseLineEdit(parent=self)
        pattern_layout.addWidget(pattern_lbl)
        pattern_layout.addWidget(self.pattern_line)
        templates_layout.addLayout(pattern_layout)
        templates_layout.addLayout(dividers.DividerLayout())
        self.template_tokens_layout = layouts.GridLayout()
        self.template_tokens_layout.setAlignment(Qt.AlignTop)
        template_tokens_frame = QFrame(parent=self)
        template_tokens_frame.setFrameShape(QFrame.StyledPanel)
        template_tokens_frame.setFrameShadow(QFrame.Sunken)
        template_tokens_frame.setLayout(self.template_tokens_layout)
        templates_layout.addWidget(template_tokens_frame)
        self.group_layout.addWidget(self.templates_widget)
        self.templates_widget.hide()

        # Templates Tokens Panel
        self.templates_tokens_widget = QWidget(parent=self)
        templates_tokens_layout = layouts.VerticalLayout()
        self.templates_tokens_widget.setLayout(templates_tokens_layout)
        description_templates_token_layout = layouts.HorizontalLayout(
            spacing=5, margins=(5, 5, 5, 5))
        description_tokens_layout = layouts.VerticalLayout()
        description_templates_token_lbl = label.BaseLabel('Description: ',
                                                          parent=self)
        description_tokens_layout.addWidget(description_templates_token_lbl)
        description_tokens_layout.addStretch()
        self.description_templates_token_text = QTextEdit(parent=self)
        description_templates_token_layout.addLayout(description_tokens_layout)
        description_templates_token_layout.addWidget(
            self.description_templates_token_text)
        templates_tokens_layout.addLayout(description_templates_token_layout)
        self.group_layout.addWidget(self.templates_tokens_widget)
        self.templates_tokens_widget.hide()

        # Initialize database
        self._init_db()

        # First update of the UI
        self.update_expression_menu()
        self.update_tokens_properties_state()
        self.update_rules_properties_state()
        self.update_templates_properties_state()
class InfoMessage(base.BaseWidget, object):
    def __init__(self, name='', description='', instructions='', parent=None):
        self._name = ''
        self._description = ''
        self._instructions = instructions

        super(InfoMessage, self).__init__(parent)

        self.setAttribute(Qt.WA_StyledBackground)
        self.theme_type = message.MessageTypes.INFO
        self.style().polish(self)
        self.name = name
        self.description = description
        self.instructions = instructions

    # =================================================================================================================
    # PROPERTIES
    # =================================================================================================================

    def _get_name(self):
        return self._name

    def _set_name(self, name):
        self._name = str(name)
        self._expandable_frame.set_title(self._name)

    def _get_description(self):
        return self._description

    def _set_description(self, text):
        self._description = str(text)
        self._description_text.setPlainText(self._description)

    def _get_instructions(self):
        return self._instructions

    def _set_instructions(self, instructions):
        self._instructions = str(instructions)
        self._instructions_text.clear()
        self._instructions_text.insertHtml(instructions)
        self._instructions_widget.setVisible(bool(instructions))

    name = Property(str, _get_name, _set_name)
    description = Property(str, _get_description, _set_description)
    instructions = Property(str, _get_instructions, _set_instructions)

    # =================================================================================================================
    # OVERRIDES
    # =================================================================================================================

    def ui(self):
        super(InfoMessage, self).ui()

        self.setMaximumHeight(150)

        info_icon = resources.icon('info')
        self._expandable_frame = expandables.ExpandableFrame(icon=info_icon,
                                                             parent=self)
        self._expandable_frame.setFrameStyle(QFrame.StyledPanel
                                             | QFrame.Raised)

        expandable_layout = layouts.HorizontalLayout(margins=(2, 2, 2, 2))

        texts_layout = layouts.HorizontalLayout(spacing=0,
                                                margins=(0, 0, 0, 0))
        self._description_text = QPlainTextEdit(parent=self)
        self._description_text.setReadOnly(True)
        self._description_text.setSizePolicy(QSizePolicy.Preferred,
                                             QSizePolicy.Maximum)
        self._description_text.setFocusPolicy(Qt.NoFocus)
        self._description_text.setFrameShape(QFrame.NoFrame)
        self._instructions_widget = QWidget()
        instructions_layout = layouts.VerticalLayout(spacing=2,
                                                     margins=(0, 0, 0, 0))
        self._instructions_widget.setLayout(instructions_layout)
        self._instructions_text = QTextEdit(parent=self)
        self._instructions_text.setReadOnly(True)
        self._instructions_text.setSizePolicy(QSizePolicy.Preferred,
                                              QSizePolicy.Maximum)
        self._instructions_text.setFocusPolicy(Qt.NoFocus)
        self._instructions_text.setFrameShape(QFrame.NoFrame)
        self._instructions_widget.setVisible(False)
        # self._instructions_text.insertHtml("<ul><li>text 1</li><li>text 2</li><li>text 3</li></ul> <br />")
        instructions_layout.addWidget(dividers.Divider('Instructions'))
        instructions_layout.addWidget(self._instructions_text)
        texts_layout.addWidget(self._description_text)
        texts_layout.addWidget(self._instructions_widget)

        content_layout = layouts.VerticalLayout()
        content_layout.addLayout(texts_layout)
        expandable_layout.addLayout(content_layout)

        self._expandable_frame.addLayout(expandable_layout)

        self.main_layout.addWidget(self._expandable_frame)
예제 #16
0
 def _on_show_detail(self):
     dlg = QTextEdit(self)
     dlg.setReadOnly(True)
     geo = QApplication.desktop().screenGeometry()
     dlg.setGeometry(geo.width() / 2,
                     geo.height() / 2,
                     geo.width() / 4,
                     geo.height() / 4)
     dlg.setWindowTitle('Error Detail Information')
     dlg.setText(self.property('history'))
     dlg.setWindowFlags(Qt.Dialog)
     dlg.show()
예제 #17
0
class TextEditDialog(QDialog):
    def __init__(self, font, textColor, parent=None):
        super(TextEditDialog, self).__init__(parent)
        self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.FramelessWindowHint)
        self.resize(QtCore.QSize(400, 300))
        self.layout = QVBoxLayout(self)
        self.layout.setContentsMargins(2, 2, 2, 2)
        self.te = QTextEdit()
        self._font = font
        self._font = QtGui.QFont(font)
        self.te.setFont(self._font)
        self.te.setTextColor(textColor)
        self.layout.addWidget(self.te)
        self.buttons = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self)
        self.buttons.accepted.connect(self.onAccept)
        self.buttons.rejected.connect(self.onReject)
        self.layout.addWidget(self.buttons)
        self._result = None
        self.te.textChanged.connect(
            lambda color=textColor: self.te.setTextColor(color))

    def zoomIn(self, factor):
        self.te.zoomIn(factor)

    def setHtml(self, html):
        self.te.setHtml(html)

    def onReject(self):
        self._result = "", False
        self.reject()

    def getResult(self):
        return self._result

    def onAccept(self):
        self.te.selectAll()
        # self._font.setPointSize(self.initialPointSize)
        self.te.setFont(self._font)
        self._result = self.te.toHtml(), True
        self.accept()
예제 #18
0
class MainWindow(QMainWindow):
    def __init__(self, url):
        super().__init__()
        self.setAttribute(Qt.WA_DeleteOnClose, True)
        self.progress = 0

        f = QFile()
        f.setFileName(":/jquery.min.js")
        f.open(QIODevice.ReadOnly)
        self.jQuery = f.readAll().data().decode()
        self.jQuery += "\nvar qt = { 'jQuery': jQuery.noConflict(true) };"
        f.close()

        self.view = QWebEngineView(self)
        self.view.load(url)

        self.view.loadFinished.connect(self.adjustLocation)
        self.view.titleChanged.connect(self.adjustTitle)
        self.view.loadProgress.connect(self.setProgress)
        self.view.loadFinished.connect(self.finishLoading)

        self.locationEdit = QLineEdit(self)
        self.locationEdit.setSizePolicy(
            QSizePolicy.Expanding,
            self.locationEdit.sizePolicy().verticalPolicy())
        self.locationEdit.returnPressed.connect(self.changeLocation)

        toolBar = self.addToolBar(self.tr("Navigation"))
        toolBar.addAction(self.view.pageAction(QWebEnginePage.Back))
        toolBar.addAction(self.view.pageAction(QWebEnginePage.Forward))
        toolBar.addAction(self.view.pageAction(QWebEnginePage.Reload))
        toolBar.addAction(self.view.pageAction(QWebEnginePage.Stop))
        toolBar.addWidget(self.locationEdit)

        viewMenu = self.menuBar().addMenu(self.tr("&View"))
        viewSourceAction = QAction(self.tr("Page Source"), self)
        viewSourceAction.triggered.connect(self.viewSource)
        viewMenu.addAction(viewSourceAction)

        effectMenu = self.menuBar().addMenu(self.tr("&Effect"))
        effectMenu.addAction(self.tr("Highlight all links"),
                             self.highlightAllLinks)

        self.rotateAction = QAction(self)
        self.rotateAction.setIcon(self.style().standardIcon(
            QStyle.SP_FileDialogDetailedView))
        self.rotateAction.setCheckable(True)
        self.rotateAction.setText(self.tr("Turn images upside down"))
        self.rotateAction.toggled.connect(self.rotateImages)
        effectMenu.addAction(self.rotateAction)

        toolsMenu = self.menuBar().addMenu(self.tr("&Tools"))
        toolsMenu.addAction(self.tr("Remove GIF images"), self.removeGifImages)
        toolsMenu.addAction(self.tr("Remove all inline frames"),
                            self.removeInlineFrames)
        toolsMenu.addAction(self.tr("Remove all object elements"),
                            self.removeObjectElements)
        toolsMenu.addAction(self.tr("Remove all embedded elements"),
                            self.removeEmbeddedElements)

        self.setCentralWidget(self.view)

    @Slot()
    def adjustLocation(self):
        self.locationEdit.setText(self.view.url().toString())

    @Slot()
    def changeLocation(self):
        url = QUrl.fromUserInput(self.locationEdit.text())
        self.view.load(url)
        self.view.setFocus()

    @Slot()
    def adjustTitle(self):
        if self.progress <= 0 or self.progress >= 100:
            self.setWindowTitle(self.view.title())
        else:
            self.setWindowTitle("%s (%2d)" %
                                (self.view.title(), self.progress))

    @Slot(int)
    def setProgress(self, p):
        self.progress = p
        self.adjustTitle()

    @Slot()
    def finishLoading(self):
        self.progress = 100
        self.adjustTitle()
        self.view.page().runJavaScript(self.jQuery)
        self.rotateImages(self.rotateAction.isChecked())

    @Slot()
    def viewSource(self):
        self.textEdit = QTextEdit()
        self.textEdit.setAttribute(Qt.WA_DeleteOnClose)
        self.textEdit.adjustSize()
        self.textEdit.move(self.geometry().center() -
                           self.textEdit.rect().center())
        self.textEdit.show()

        self.view.page().toHtml(self.textEdit.setPlainText)

    @Slot()
    def highlightAllLinks(self):
        code = "qt.jQuery('a').each( function () { qt.jQuery(this).css('background-color', 'yellow') } )"
        self.view.page().runJavaScript(code)

    @Slot(bool)
    def rotateImages(self, invert):
        code = ""
        if invert:
            code = "qt.jQuery('img').each( function () { qt.jQuery(this).css('transition', 'transform 2s'); qt.jQuery(this).css('transform', 'rotate(180deg)') } )"  # noqa: E501
        else:
            code = "qt.jQuery('img').each( function () { qt.jQuery(this).css('transition', 'transform 2s'); qt.jQuery(this).css('transform', 'rotate(0deg)') } )"  # noqa: E501
        self.view.page().runJavaScript(code)

    @Slot()
    def removeGifImages(self):
        code = "qt.jQuery('[src*=gif]').remove()"
        self.view.page().runJavaScript(code)

    @Slot()
    def removeInlineFrames(self):
        code = "qt.jQuery('iframe').remove()"
        self.view.page().runJavaScript(code)

    @Slot()
    def removeObjectElements(self):
        code = "qt.jQuery('object').remove()"
        self.view.page().runJavaScript(code)

    @Slot()
    def removeEmbeddedElements(self):
        code = "qt.jQuery('embed').remove()"
        self.view.page().runJavaScript(code)
예제 #19
0
def embed_readme_images(readme_path):
    """
    QTextEdit used to auto detect raw / html / markdown,
    and do the conversion to html.
    """
    readme_dir = os.path.dirname(readme_path)

    dada = None
    with open(readme_path) as f:
        dada = f.read()
    # strip old embeded dada
    dada = re.sub(r'source=\"data:image.*\"', "", dada)

    editor = QTextEdit()
    editor.setText(dada)
    editor.document().setMetaInformation(QTextDocument.DocumentUrl, readme_dir)
    html = editor.toHtml()

    image_elements = list()
    root = ElementTree.fromstring(html)
    for element in root.iter():
        for sub in element[:]:
            if sub.tag == "head":
                element.remove(sub)
        element.attrib.pop("style", None)
        if element.tag == "img":
            image_elements.append(element)

    width_scalar = calculate_width_scalar(readme_dir, image_elements, 577.0)

    for img in image_elements:
        rel_src_path = img.attrib.get("src", "")
        if rel_src_path.startswith("data:image"):
            print(
                "Embeded src. skipping! (readme_path={readme_path!r})".format(
                    **locals()))
            return
        if rel_src_path:
            src_path = os.path.abspath(os.path.join(readme_dir, rel_src_path))
            if not os.path.isfile(src_path):
                print(
                    "image file missing! (readme_dir={readme_dir!r}, src_path={src_path!r})"
                    .format(**locals()))
            else:
                rel_src_path = os.path.relpath(src_path, readme_dir)
                rel_src_path = "./" + rel_src_path.replace("\\", "/")
                # attribute order must be correct !!!
                # ElementTree in python<3.8 uses sort(dict.items())
                # sooo... lets make sure that there is alphaphetical dummy prefix...
                new_attributes = [
                    ("001_DEL_XML_SUCKS_src", rel_src_path),
                    ("002_DEL_XML_SUCKS_source",
                     embeded_image_scale_to_width(src_path,
                                                  width_scalar=width_scalar))
                ]
                new_attributes.extend((k, v)
                                      for k, v in sorted(img.attrib.items())
                                      if k not in {"src", "source"})
                img.attrib.clear()
                img.attrib.update(new_attributes)

    html = ElementTree.tostring(root).decode()
    html = re.sub(r"\d{3}_DEL_XML_SUCKS_", "", html)
    with open(readme_path, "wb") as f:
        f.write(html.encode("utf-8"))