diff --git a/.travis.yml b/.travis.yml index 0430363..cc350d6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: python +sudo: required +dist: trusty install: - chmod +x ./dev/travis-bootstrap.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 460d3bd..0fc3de3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,38 @@ # Changelog +0.7.0 (2016-07-10) + +* Fixed rare bug with the validator. +* Added Dependencies Wizard. +* Children box now lists invalid child nodes greyed out instead of deleting them. +* Fixed issues with saving. +* Nodes should now be properly sorted. +* Added specialized child nodes with colours. +* Added auto-completion for flag labels and their values. +* Fixed recent files issues. +* Properties are now ordered. +* Added node-specific metadata. +* Pattern node's names are now editable. +* Improved Setting's dialog. +* Added Defaults section to settings. +* Added Appearance tab to settings dialog. +* Fixed rare bug with xml preview. +* Disabled Wizards. +* Added user-defined noe sorting with drag and drop. +* Improved logos. +* Added copy and paste functionality. +* Added undo and redo functionality. +* Loading ui should now be slightly faster - ui is now pre-compiled. +* Full keyboard navigation is now supported on the node tree. +* Added context menu to the node tree. +* Actions should now be properly disabled/enabled when appropriate. +* All nodes should now be correct on their allowed number. +* Added plain text editor to most simple text properties and html editor to plugin's description text. +* Added install step ui preview. +* Added tutorial at startup. Added setting to re-enable the tutorial. + +---------------------------------- + 0.6.0 (2016-06-13) * Added check for updates at startup. diff --git a/designer/__main__.py b/designer/__main__.py index 5c816f4..c263992 100644 --- a/designer/__main__.py +++ b/designer/__main__.py @@ -15,15 +15,21 @@ # limitations under the License. import sys -from PyQt5 import QtWidgets +from PyQt5.QtWidgets import QApplication +from PyQt5.QtGui import QPalette, QColor from .exceptions import excepthook -from .gui import IntroWindow +from .gui import IntroWindow, read_settings def main(): sys.excepthook = excepthook - app = QtWidgets.QApplication(sys.argv) + settings = read_settings() + if settings["Appearance"]["style"]: + QApplication.setStyle(settings["Appearance"]["style"]) + app = QApplication(sys.argv) + if settings["Appearance"]["palette"]: + app.setPalette(QPalette(QColor(settings["Appearance"]["palette"]))) IntroWindow() sys.exit(app.exec_()) diff --git a/designer/exceptions.py b/designer/exceptions.py index 686983f..81e2ad9 100644 --- a/designer/exceptions.py +++ b/designer/exceptions.py @@ -69,6 +69,7 @@ class MissingFileError(DesignerError): def __init__(self, fname): self.title = "I/O Error" self.message = "{} is missing.".format(fname.capitalize()) + self.detailed = "" self.file = fname Exception.__init__(self, self.message) @@ -81,6 +82,7 @@ class ParserError(DesignerError): """ def __init__(self, msg): self.title = "Parser Error" + self.detailed = "" if len(msg.split(",")) <= 2: self.msg = "The parser couldn't read the installer file. If you need help visit " \ "W3Schools." @@ -98,6 +100,7 @@ class TagNotFound(DesignerError): def __init__(self, element): self.title = "Tag Lookup Error" self.message = "Tag {} at line {} could not be matched.".format(element.tag, element.sourceline) + self.detailed = "" Exception.__init__(self, self.message) @@ -108,4 +111,5 @@ class BaseInstanceException(Exception): def __init__(self, base_instance): self.title = "Instance Error" self.message = "{} is not meant to be instanced. A subclass should be used instead.".format(type(base_instance)) + self.detailed = "" Exception.__init__(self, self.message) diff --git a/designer/gui.py b/designer/gui.py index 0ee89af..8af11b2 100644 --- a/designer/gui.py +++ b/designer/gui.py @@ -16,32 +16,34 @@ from os import makedirs from os.path import expanduser, normpath, basename, join, relpath, isdir +from io import BytesIO from threading import Thread from queue import Queue from webbrowser import open as web_open from datetime import datetime -from configparser import ConfigParser -from PyQt5.uic import loadUiType -from PyQt5.QtWidgets import (QShortcut, QFileDialog, QColorDialog, QMessageBox, QLabel, QHBoxLayout, QCommandLinkButton, - QFormLayout, QLineEdit, QSpinBox, QComboBox, QWidget, QPushButton, QSizePolicy, QStatusBar) -from PyQt5.QtGui import QIcon, QPixmap, QStandardItemModel, QColor, QFont -from PyQt5.QtCore import Qt, pyqtSignal +from collections import deque +from json import JSONDecodeError +from jsonpickle import encode, decode, set_encoder_options +from lxml.etree import parse, tostring +from PyQt5.QtWidgets import (QFileDialog, QColorDialog, QMessageBox, QLabel, QHBoxLayout, QCommandLinkButton, QDialog, + QFormLayout, QLineEdit, QSpinBox, QComboBox, QWidget, QPushButton, QSizePolicy, QStatusBar, + QCompleter, QApplication, QMainWindow, QUndoCommand, QUndoStack, QMenu) +from PyQt5.QtGui import QIcon, QPixmap, QColor, QFont, QStandardItemModel +from PyQt5.QtCore import Qt, pyqtSignal, QStringListModel, QMimeData +from PyQt5.uic import loadUi from requests import get, codes, ConnectionError, Timeout from validator import validate_tree, check_warnings, ValidatorError from . import cur_folder, __version__ -from .io import import_, new, export, sort_elements, elem_factory -from .previews import PreviewDispatcherThread -from .props import PropertyFile, PropertyColour, PropertyFolder, PropertyCombo, PropertyInt, PropertyText +from .io import import_, new, export, sort_elements, elem_factory, copy_element +from .previews import PreviewDispatcherThread, PreviewMoGui +from .props import PropertyFile, PropertyColour, PropertyFolder, PropertyCombo, PropertyInt, PropertyText, \ + PropertyFlagLabel, PropertyFlagValue, PropertyHTML from .exceptions import DesignerError +from .ui_templates import window_intro, window_mainframe, window_about, window_settings, window_texteditor, \ + window_plaintexteditor -intro_ui = loadUiType(join(cur_folder, "resources/templates/intro.ui")) -base_ui = loadUiType(join(cur_folder, "resources/templates/mainframe.ui")) -settings_ui = loadUiType(join(cur_folder, "resources/templates/settings.ui")) -about_ui = loadUiType(join(cur_folder, "resources/templates/about.ui")) - - -class IntroWindow(intro_ui[0], intro_ui[1]): +class IntroWindow(QMainWindow, window_intro.Ui_MainWindow): """ The class for the intro window. Subclassed from QDialog and created in Qt Designer. """ @@ -52,14 +54,18 @@ def __init__(self): self.setWindowTitle("FOMOD Designer") self.version.setText("Version " + __version__) - settings = read_settings() - for key in sorted(settings["Recent Files"]): - if settings["Recent Files"][key]: - butto = QCommandLinkButton(basename(settings["Recent Files"][key]), settings["Recent Files"][key], self) - butto.clicked.connect(lambda _, path=settings["Recent Files"][key]: self.open_path(path)) - self.scroll_layout.addWidget(butto) + self.settings_dict = read_settings() + recent_files = self.settings_dict["Recent Files"] + for path in recent_files: + if not isdir(path): + recent_files.remove(path) + continue + button = QCommandLinkButton(basename(path), path, self) + button.setIcon(QIcon(join(cur_folder, "resources/logos/logo_enter.png"))) + button.clicked.connect(lambda _, path_=path: self.open_path(path_)) + self.scroll_layout.addWidget(button) - if not settings["General"]["show_intro"]: + if not self.settings_dict["General"]["show_intro"]: main_window = MainFrame() main_window.move(self.pos()) main_window.show() @@ -76,22 +82,53 @@ def open_path(self, path): :param path: The path to open. """ - config = ConfigParser() - config.read_dict(read_settings()) - config["General"]["show_intro"] = str(not self.check_intro.isChecked()).lower() - config["General"]["show_advanced"] = str(self.check_advanced.isChecked()).lower() - makedirs(join(expanduser("~"), ".fomod"), exist_ok=True) - with open(join(expanduser("~"), ".fomod", ".designer"), "w") as configfile: - config.write(configfile) - main_window = MainFrame() - main_window.move(self.pos()) + self_center = self.mapToGlobal(self.rect().center()) + main_center = main_window.mapToGlobal(main_window.rect().center()) + main_window.move(self_center - main_center) main_window.open(path) main_window.show() self.close() + if self.settings_dict["General"]["tutorial_advanced"]: + main_window.setEnabled(False) + tutorial = loadUi(join(cur_folder, "resources/templates/tutorial_advanced.ui")) + tutorial.frame_node.resize(main_window.node_tree_view.size()) + tutorial.frame_node.move( + main_window.node_tree_view.mapTo(main_window, main_window.node_tree_view.pos()) + ) + tutorial.frame_preview.resize(main_window.tabWidget.size()) + tutorial.frame_preview.move( + main_window.tabWidget.mapTo(main_window, main_window.tabWidget.pos()) + ) + tutorial.frame_prop.resize(main_window.dockWidgetContents.size()) + tutorial.frame_prop.move( + main_window.dockWidgetContents.mapTo(main_window, main_window.dockWidgetContents.pos()) + ) + tutorial.frame_child.resize(main_window.dockWidgetContents_3.size()) + tutorial.frame_child.move( + main_window.dockWidgetContents_3.mapTo(main_window, main_window.dockWidgetContents_3.pos()) + ) + tutorial.button_exit.clicked.connect(lambda: main_window.setEnabled(True)) + tutorial.button_exit.clicked.connect(tutorial.close) + tutorial.setParent(main_window) + tutorial.setWindowFlags(Qt.FramelessWindowHint | Qt.Dialog) + tutorial.setAttribute(Qt.WA_TranslucentBackground) + main_center = main_window.mapToGlobal(main_window.rect().center()) + tutorial_center = tutorial.mapToGlobal(tutorial.rect().center()) + tutorial.move(main_center - tutorial_center) + tutorial.setEnabled(True) + tutorial.exec_() + self.settings_dict["General"]["tutorial_advanced"] = False + + self.settings_dict["General"]["show_intro"] = not self.check_intro.isChecked() + self.settings_dict["General"]["show_advanced"] = self.check_advanced.isChecked() + makedirs(join(expanduser("~"), ".fomod"), exist_ok=True) + with open(join(expanduser("~"), ".fomod", ".designer"), "w") as configfile: + set_encoder_options("json", indent=4) + configfile.write(encode(self.settings_dict)) -class MainFrame(base_ui[0], base_ui[1]): +class MainFrame(QMainWindow, window_mainframe.Ui_MainWindow): """ The class for the main window. Subclassed from QMainWindow and created in Qt Designer. """ @@ -99,26 +136,280 @@ class MainFrame(base_ui[0], base_ui[1]): #: Signals the xml code has changed. xml_code_changed = pyqtSignal([object]) - #: Signals the mo preview is updated. - update_mo_preview = pyqtSignal([QWidget]) - - #: Signals the nmm preview is updated. - update_nmm_preview = pyqtSignal([QWidget]) - #: Signals the code preview is updated. update_code_preview = pyqtSignal([str]) #: Signals there is an update available. - update_available = pyqtSignal() + update_check_update_available = pyqtSignal() #: Signals the app is up-to-date. - up_to_date = pyqtSignal() + update_check_up_to_date = pyqtSignal() #: Signals a connection timed out. - timeout = pyqtSignal() + update_check_timeout = pyqtSignal() #: Signals there was an error with the internet connection. - connection_error = pyqtSignal() + update_check_connection_error = pyqtSignal() + + #: Signals a new node has been selected in the node tree. + select_node = pyqtSignal([object]) + + #: Signals the previews need to be updated. + update_previews = pyqtSignal([object]) + + class NodeMimeData(QMimeData): + def __init__(self): + super().__init__() + self._node = None + self._item = None + self._original_item = None + + def has_node(self): + if self._node is None: + return False + else: + return True + + def node(self): + return self._node + + def set_node(self, node): + self._node = node + + def has_item(self): + if self._item is None: + return False + else: + return True + + def item(self): + return self._item + + def set_item(self, item): + self._item = item + + def original_item(self): + return self._original_item + + def set_original_item(self, item): + self._original_item = item + + class NodeStandardModel(QStandardItemModel): + def mimeData(self, index_list): + if not index_list: + return 0 + + mime_data = MainFrame.NodeMimeData() + new_node = copy_element(self.itemFromIndex(index_list[0]).xml_node) + mime_data.set_item(new_node.model_item) + mime_data.set_node(new_node) + mime_data.set_original_item(self.itemFromIndex(index_list[0])) + return mime_data + + def canDropMimeData(self, mime_data, drop_action, row, col, parent_index): + if self.itemFromIndex(parent_index) and mime_data.has_node() and mime_data.has_item() and drop_action == 2: + if isinstance(self.itemFromIndex(parent_index).xml_node, type(mime_data.node().getparent())): + return True + else: + return False + else: + return False + + def dropMimeData(self, mime_data, drop_action, row, col, parent_index): + if not self.canDropMimeData(mime_data, drop_action, row, col, parent_index): + return False + + parent = self.itemFromIndex(parent_index) + xml_node = mime_data.node() + parent.xml_node.remove(mime_data.original_item().xml_node) + parent.xml_node.append(mime_data.node()) + parent.insertRow(row, xml_node.model_item) + for row_index in range(0, parent.rowCount()): + if parent.child(row_index) == mime_data.original_item(): + continue + parent.child(row_index).xml_node.user_sort_order = str(parent.child(row_index).row()).zfill(7) + parent.child(row_index).xml_node.save_metadata() + return True + + def supportedDragActions(self): + return Qt.MoveAction + + class LineEditChangeCommand(QUndoCommand): + def __init__(self, original_text, new_text, current_prop_widgets, widget_index, tree_model, item, select_node): + super().__init__("Line edit changed.") + self.original_text = original_text + self.new_text = new_text + self.current_prop_widgets = current_prop_widgets + self.widget_index = widget_index + self.tree_model = tree_model + self.item = item + self.select_node = select_node + + def redo(self): + self.select_node.emit(self.tree_model.indexFromItem(self.item)) + self.current_prop_widgets[self.widget_index].setText(self.new_text) + + def undo(self): + self.select_node.emit(self.tree_model.indexFromItem(self.item)) + self.current_prop_widgets[self.widget_index].setText(self.original_text) + + class WidgetLineEditChangeCommand(QUndoCommand): + def __init__(self, original_text, new_text, current_prop_widgets, widget_index, tree_model, item, select_node): + super().__init__("Widget with line edit changed.") + self.original_text = original_text + self.new_text = new_text + self.current_prop_widgets = current_prop_widgets + self.widget_index = widget_index + self.tree_model = tree_model + self.item = item + self.select_node = select_node + + def redo(self): + self.select_node.emit(self.tree_model.indexFromItem(self.item)) + line_edit = None + for index in range(self.current_prop_widgets[self.widget_index].layout().count()): + widget = self.current_prop_widgets[self.widget_index].layout().itemAt(index).widget() + if isinstance(widget, QLineEdit): + line_edit = widget + line_edit.setText(self.new_text) + + def undo(self): + self.select_node.emit(self.tree_model.indexFromItem(self.item)) + line_edit = None + for index in range(self.current_prop_widgets[self.widget_index].layout().count()): + widget = self.current_prop_widgets[self.widget_index].layout().itemAt(index).widget() + if isinstance(widget, QLineEdit): + line_edit = widget + line_edit.setText(self.original_text) + + class ComboBoxChangeCommand(QUndoCommand): + def __init__(self, original_text, new_text, current_prop_widgets, widget_index, tree_model, item, select_node): + super().__init__("Combo box changed.") + self.original_text = original_text + self.new_text = new_text + self.current_prop_widgets = current_prop_widgets + self.widget_index = widget_index + self.tree_model = tree_model + self.item = item + self.select_node = select_node + + def redo(self): + self.select_node.emit(self.tree_model.indexFromItem(self.item)) + self.current_prop_widgets[self.widget_index].setCurrentText(self.new_text) + + def undo(self): + self.select_node.emit(self.tree_model.indexFromItem(self.item)) + self.current_prop_widgets[self.widget_index].setCurrentText(self.original_text) + + class SpinBoxChangeCommand(QUndoCommand): + def __init__(self, original_int, new_int, current_prop_widgets, widget_index, tree_model, item, select_node): + super().__init__("Spin box changed.") + self.original_int = original_int + self.new_int = new_int + self.current_prop_widgets = current_prop_widgets + self.widget_index = widget_index + self.tree_model = tree_model + self.item = item + self.select_node = select_node + + def redo(self): + self.select_node.emit(self.tree_model.indexFromItem(self.item)) + self.current_prop_widgets[self.widget_index].setValue(self.new_int) + + def undo(self): + self.select_node.emit(self.tree_model.indexFromItem(self.item)) + self.current_prop_widgets[self.widget_index].setValue(self.original_int) + + class RunWizardCommand(QUndoCommand): + def __init__(self, parent_node, original_node, modified_node, tree_model, select_node_signal): + super().__init__("Wizard was run on this node.") + self.parent_node = parent_node + self.original_node = original_node + self.modified_node = modified_node + self.tree_model = tree_model + self.select_node_signal = select_node_signal + + def redo(self): + self.parent_node.remove_child(self.original_node) + self.parent_node.add_child(self.modified_node) + self.parent_node.model_item.sortChildren(0) + self.select_node_signal.emit(self.tree_model.indexFromItem(self.modified_node.model_item)) + + def undo(self): + self.parent_node.remove_child(self.modified_node) + self.parent_node.add_child(self.original_node) + self.parent_node.model_item.sortChildren(0) + self.select_node_signal.emit(self.tree_model.indexFromItem(self.original_node.model_item)) + + class DeleteCommand(QUndoCommand): + def __init__(self, node_to_delete, tree_model, select_node_signal): + super().__init__("Node deleted.") + self.node_to_delete = node_to_delete + self.parent_node = node_to_delete.getparent() + self.tree_model = tree_model + self.select_node_signal = select_node_signal + + def redo(self): + object_to_delete = self.node_to_delete + new_index = self.tree_model.indexFromItem(self.parent_node.model_item) + self.parent_node.remove_child(object_to_delete) + self.select_node_signal.emit(new_index) + + def undo(self): + self.parent_node.add_child(self.node_to_delete) + self.select_node_signal.emit(self.tree_model.indexFromItem(self.node_to_delete.model_item)) + self.tree_model.sort(0) + + class AddChildCommand(QUndoCommand): + def __init__(self, child_tag, parent_node, tree_model, settings_dict, select_node_signal): + super().__init__("Child added.") + self.child_tag = child_tag + self.parent_node = parent_node + self.tree_model = tree_model + self.settings_dict = settings_dict + self.select_node_signal = select_node_signal + self.new_child_node = None + + def redo(self): + if self.new_child_node is None: + self.new_child_node = elem_factory(self.child_tag, self.parent_node) + defaults_dict = self.settings_dict["Defaults"] + if self.child_tag in defaults_dict and defaults_dict[self.child_tag].enabled(): + self.new_child_node.properties[defaults_dict[self.child_tag].key()].set_value( + defaults_dict[self.child_tag].value() + ) + self.parent_node.add_child(self.new_child_node) + self.tree_model.sort(0) + + # select the new item + self.select_node_signal.emit(self.tree_model.indexFromItem(self.new_child_node.model_item)) + + def undo(self): + self.parent_node.remove_child(self.new_child_node) + + # select the parent after removing + self.select_node_signal.emit(self.tree_model.indexFromItem(self.parent_node.model_item)) + + class PasteCommand(QUndoCommand): + def __init__(self, parent_item, status_bar, tree_model, select_node_signal): + super().__init__("Node pasted.") + self.parent_item = parent_item + self.status_bar = status_bar + self.tree_model = tree_model + self.select_node_signal = select_node_signal + self.pasted_node = None + + def redo(self): + self.pasted_node = copy_element(QApplication.clipboard().mimeData().node()) + self.parent_item.xml_node.append(self.pasted_node) + self.parent_item.appendRow(self.pasted_node.model_item) + self.parent_item.sortChildren(0) + + def undo(self): + self.parent_item.xml_node.remove_child(self.pasted_node) + + # select the parent after removing + self.select_node_signal.emit(self.tree_model.indexFromItem(self.parent_item.xml_node.model_item)) def __init__(self): super().__init__() @@ -133,59 +424,209 @@ def __init__(self): self.action_Delete.setIcon(QIcon(join(cur_folder, "resources/logos/logo_cross.png"))) self.action_About.setIcon(QIcon(join(cur_folder, "resources/logos/logo_notepad.png"))) self.actionHe_lp.setIcon(QIcon(join(cur_folder, "resources/logos/logo_info.png"))) - - # setup any additional info left from designer - self.delete_sec_shortcut = QShortcut(self) - self.delete_sec_shortcut.setKey(Qt.Key_Delete) - + self.actionCopy.setIcon(QIcon(join(cur_folder, "resources/logos/logo_copy.png"))) + self.actionPaste.setIcon(QIcon(join(cur_folder, "resources/logos/logo_paste.png"))) + self.actionRedo.setIcon(QIcon(join(cur_folder, "resources/logos/logo_redo.png"))) + self.actionUndo.setIcon(QIcon(join(cur_folder, "resources/logos/logo_undo.png"))) + self.actionClear.setIcon(QIcon(join(cur_folder, "resources/logos/logo_clear.png"))) + self.menu_Recent_Files.setIcon(QIcon(join(cur_folder, "resources/logos/logo_recent.png"))) + self.actionExpand_All.setIcon(QIcon(join(cur_folder, "resources/logos/logo_expand.png"))) + self.actionCollapse_All.setIcon(QIcon(join(cur_folder, "resources/logos/logo_collapse.png"))) + + # manage undo and redo + self.undo_stack = QUndoStack(self) + self.undo_stack.setUndoLimit(25) + self.undo_stack.canRedoChanged.connect(self.actionRedo.setEnabled) + self.undo_stack.canUndoChanged.connect(self.actionUndo.setEnabled) + self.actionRedo.triggered.connect(self.undo_stack.redo) + self.actionUndo.triggered.connect(self.undo_stack.undo) + + # manage the node tree view + self.node_tree_view.clicked.connect(self.select_node.emit) + self.node_tree_view.activated.connect(self.select_node.emit) + self.node_tree_view.setContextMenuPolicy(Qt.CustomContextMenu) + self.node_tree_view.customContextMenuRequested.connect(self.on_custom_context_menu) + + # manage node tree model + self.node_tree_model = self.NodeStandardModel() + self.node_tree_view.setModel(self.node_tree_model) + self.node_tree_model.itemChanged.connect(lambda item: item.xml_node.save_metadata()) + self.node_tree_model.itemChanged.connect(lambda item: self.xml_code_changed.emit(item.xml_node)) + + # connect actions to the respective methods self.action_Open.triggered.connect(self.open) self.action_Save.triggered.connect(self.save) - self.actionO_ptions.triggered.connect(self.options) + self.actionO_ptions.triggered.connect(self.settings) self.action_Refresh.triggered.connect(self.refresh) self.action_Delete.triggered.connect(self.delete) - self.delete_sec_shortcut.activated.connect(self.delete) self.actionHe_lp.triggered.connect(self.help) self.action_About.triggered.connect(lambda _, self_=self: self.about(self_)) self.actionClear.triggered.connect(self.clear_recent_files) - self.action_Object_Tree.toggled.connect(self.object_tree.setVisible) - self.actionObject_Box.toggled.connect(self.object_box.setVisible) + self.actionCopy.triggered.connect( + lambda: self.copy_item_to_clipboard() + if self.node_tree_view.selectedIndexes() else None + ) + self.actionPaste.triggered.connect( + lambda: self.paste_item_from_clipboard() + if self.node_tree_view.selectedIndexes() else None + ) + self.actionExpand_All.triggered.connect(self.node_tree_view.expandAll) + self.actionCollapse_All.triggered.connect(self.node_tree_view.collapseAll) + self.action_Object_Tree.toggled.connect(self.node_tree.setVisible) + self.actionObject_Box.toggled.connect(self.children_box.setVisible) self.action_Property_Editor.toggled.connect(self.property_editor.setVisible) - - self.object_tree.visibilityChanged.connect(self.action_Object_Tree.setChecked) - self.object_box.visibilityChanged.connect(self.actionObject_Box.setChecked) + self.node_tree.visibilityChanged.connect(self.action_Object_Tree.setChecked) + self.children_box.visibilityChanged.connect(self.actionObject_Box.setChecked) self.property_editor.visibilityChanged.connect(self.action_Property_Editor.setChecked) - self.object_tree_view.clicked.connect(self.selected_object_tree) - - self.fomod_changed = False + # setup any necessary variables self.original_title = self.windowTitle() - self.package_path = "" + self._package_path = "" self.package_name = "" self.settings_dict = read_settings() - self.info_root = None - self.config_root = None - self.current_object = None - self.current_prop_list = [] - self.tree_model = QStandardItemModel() + self._info_root = None + self._config_root = None + self._current_prop_list = [] + self.original_prop_value_list = {} # start the preview threads self.preview_queue = Queue() - self.xml_code_changed.connect(self.preview_queue.put) + self.preview_gui_worker = PreviewMoGui(self.layout_mo) + self.update_previews.connect(self.preview_queue.put) self.update_code_preview.connect(self.xml_code_browser.setHtml) - self.preview_thread = PreviewDispatcherThread(self.preview_queue, self.update_mo_preview, - self.update_nmm_preview, self.update_code_preview) + self.preview_thread = PreviewDispatcherThread( + self.preview_queue, + self.update_code_preview, + **{ + "package_path": self.package_path, + "info_root": self.info_root, + "config_root": self.config_root, + "gui_worker": self.preview_gui_worker + } + ) self.preview_thread.start() # manage the wizard button - self.wizard_button.clicked.connect(self.run_wizard) - self.wizard_button.hide() - - self.object_tree_view.setModel(self.tree_model) - self.object_tree_view.header().hide() + self.button_wizard.clicked.connect(self.run_wizard) + + # manage auto-completion + self.flag_label_model = QStringListModel() + self.flag_label_completer = QCompleter() + self.flag_label_completer.setCaseSensitivity(Qt.CaseInsensitive) + self.flag_label_completer.setModel(self.flag_label_model) + self.flag_value_model = QStringListModel() + self.flag_value_completer = QCompleter() + self.flag_value_completer.setCaseSensitivity(Qt.CaseInsensitive) + self.flag_value_completer.setModel(self.flag_value_model) + + # connect node selected signal + self.current_node = None + self.select_node.connect( + lambda index: self.set_current_node(self.node_tree_model.itemFromIndex(index).xml_node) + ) + self.select_node.connect(lambda index: self.node_tree_view.setCurrentIndex(index)) + self.select_node.connect( + lambda: self.update_previews.emit(self.current_node) + if self.settings_dict["General"]["code_refresh"] >= 2 else None + ) + self.select_node.connect(self.update_children_box) + self.select_node.connect(self.update_props_list) + self.select_node.connect(lambda: self.action_Delete.setEnabled(True)) + self.select_node.connect( + lambda: self.button_wizard.setEnabled(False) + if self.current_node.wizard is None else self.button_wizard.setEnabled(True) + ) + + # manage code changed signal + self.xml_code_changed.connect(self.update_previews.emit) + + # manage clean/dirty states + self.undo_stack.cleanChanged.connect( + lambda clean: self.setWindowTitle(self.package_name + " - " + self.original_title) + if clean + else self.setWindowTitle("*" + self.package_name + " - " + self.original_title) + ) + self.undo_stack.cleanChanged.connect( + lambda clean: self.action_Save.setEnabled(not clean) + ) self.update_recent_files() self.check_updates() + # disable the wizards until they're up-to-date + self.button_wizard.hide() + + def on_custom_context_menu(self, position): + index = self.node_tree_view.indexAt(position) + node_tree_context_menu = QMenu(self.node_tree_view) + node_tree_context_menu.addActions([self.actionExpand_All, self.actionCollapse_All]) + + if index.isValid(): + self.select_node.emit(index) + node_tree_context_menu.addSeparator() + node_tree_context_menu.addAction(self.action_Delete) + node_tree_context_menu.addSeparator() + node_tree_context_menu.addActions([self.actionCopy, self.actionPaste]) + node_tree_context_menu.addSeparator() + node_tree_context_menu.addActions([self.actionUndo, self.actionRedo]) + + node_tree_context_menu.move(self.node_tree_view.mapToGlobal(position)) + node_tree_context_menu.exec_() + + def set_current_node(self, selected_node): + self.current_node = selected_node + + @property + def current_prop_list(self): + return self._current_prop_list + + def info_root(self): + return self._info_root + + def config_root(self): + return self._config_root + + def package_path(self): + return self._package_path + + def copy_item_to_clipboard(self): + item = self.node_tree_model.itemFromIndex(self.node_tree_view.selectedIndexes()[0]) + QApplication.clipboard().setMimeData(self.node_tree_model.mimeData([self.node_tree_model.indexFromItem(item)])) + self.actionPaste.setEnabled(True) + + def paste_item_from_clipboard(self): + parent_item = self.node_tree_model.itemFromIndex(self.node_tree_view.selectedIndexes()[0]) + new_node = copy_element(QApplication.clipboard().mimeData().node()) + if not parent_item.xml_node.can_add_child(new_node): + self.statusBar().showMessage("This parent is not valid!") + else: + self.undo_stack.push( + self.PasteCommand( + parent_item, + self.statusBar(), + self.node_tree_model, + self.select_node + ) + ) + + @staticmethod + def update_flag_label_completer(label_model, elem_root): + label_list = [] + for elem in elem_root.iter(): + if elem.tag == "flag": + value = elem.properties["name"].value + if value not in label_list: + label_list.append(value) + label_model.setStringList(label_list) + + @staticmethod + def update_flag_value_completer(value_model, elem_root, label): + value_list = [] + for elem in elem_root.iter(): + if elem.tag == "flag" and elem.text not in value_list and elem.properties["name"].value == label: + value_list.append(elem.text) + value_model.setStringList(value_list) + def check_updates(self): """ Checks the version number on the remote repository (Github Releases) @@ -205,23 +646,26 @@ def check_remote(): try: response = get("https://api.github.com/repos/GandaG/fomod-designer/releases", timeout=10) if response.status_code == codes.ok and response.json()[0]["tag_name"][1:] > __version__: - self.update_available.emit() + self.update_check_update_available.emit() else: - self.up_to_date.emit() + self.update_check_up_to_date.emit() except Timeout: - self.timeout.emit() + self.update_check_timeout.emit() except ConnectionError: - self.connection_error.emit() - - self.up_to_date.connect(lambda: self.setStatusBar(QStatusBar())) - self.up_to_date.connect(lambda: self.statusBar().addWidget(QLabel("Everything is up-to-date."))) - self.update_available.connect(lambda: self.setStatusBar(QStatusBar())) - self.update_available.connect(update_available_button) - self.timeout.connect(lambda: self.setStatusBar(QStatusBar())) - self.timeout.connect(lambda: self.statusBar().addWidget(QLabel("Connection timed out."))) - self.connection_error.connect(lambda: self.setStatusBar(QStatusBar())) - self.connection_error.connect(lambda: self.statusBar().addWidget(QLabel("Could not connect to remote server, " - "check your internet connection."))) + self.update_check_connection_error.emit() + + self.update_check_up_to_date.connect(lambda: self.setStatusBar(QStatusBar())) + self.update_check_up_to_date.connect(lambda: self.statusBar().addWidget(QLabel("Everything is up-to-date."))) + self.update_check_update_available.connect(lambda: self.setStatusBar(QStatusBar())) + self.update_check_update_available.connect(update_available_button) + self.update_check_timeout.connect(lambda: self.setStatusBar(QStatusBar())) + self.update_check_timeout.connect(lambda: self.statusBar().addWidget(QLabel("Connection timed out."))) + self.update_check_connection_error.connect(lambda: self.setStatusBar(QStatusBar())) + self.update_check_connection_error.connect( + lambda: self.statusBar().addWidget(QLabel( + "Could not connect to remote server, check your internet connection." + )) + ) self.statusBar().addWidget(QLabel("Checking for updates...")) @@ -255,27 +699,40 @@ def open(self, path=""): info_root, config_root = import_(normpath(package_path)) if info_root is not None and config_root is not None: if self.settings_dict["Load"]["validate"]: - validate_tree(config_root, join(cur_folder, "resources", "mod_schema.xsd"), - self.settings_dict["Load"]["validate_ignore"]) + validate_tree( + parse(BytesIO(tostring(config_root, pretty_print=True))), + join(cur_folder, "resources", "mod_schema.xsd"), + self.settings_dict["Load"]["validate_ignore"] + ) if self.settings_dict["Load"]["warnings"]: - check_warnings(package_path, config_root, self.settings_dict["Save"]["warn_ignore"]) + check_warnings( + package_path, + config_root, + self.settings_dict["Save"]["warn_ignore"] + ) else: info_root, config_root = new() - self.package_path = package_path - self.info_root, self.config_root = info_root, config_root + self._package_path = package_path + self._info_root, self._config_root = info_root, config_root - self.tree_model.clear() + self.node_tree_model.clear() - self.tree_model.appendRow(self.info_root.model_item) - self.tree_model.appendRow(self.config_root.model_item) + self.node_tree_model.appendRow(self._info_root.model_item) + self.node_tree_model.appendRow(self._config_root.model_item) - self.package_name = basename(normpath(self.package_path)) - self.fomod_modified(False) - self.current_object = None - self.xml_code_changed.emit(self.current_object) - self.update_recent_files(self.package_path) + self.package_name = basename(normpath(self._package_path)) + self.current_node = None + self.xml_code_changed.emit(self.current_node) + self.undo_stack.setClean() + self.undo_stack.cleanChanged.emit(True) + self.undo_stack.clear() + QApplication.clipboard().clear() + self.actionPaste.setEnabled(False) + self.action_Delete.setEnabled(False) + self.update_recent_files(self._package_path) self.clear_prop_list() + self.button_wizard.setEnabled(False) except (DesignerError, ValidatorError) as p: generic_errorbox(p.title, str(p), p.detailed) return @@ -287,22 +744,30 @@ def save(self): If enabled in the Settings the installer is also validated and checked for common errors. """ try: - if self.info_root is not None and self.config_root is not None: + if self._info_root is None and self._config_root is None: return - elif self.fomod_changed: - sort_elements(self.info_root, self.config_root) + elif not self.undo_stack.isClean(): + sort_elements(self._info_root) + sort_elements(self._config_root) if self.settings_dict["Save"]["validate"]: - validate_tree(self.config_root, join(cur_folder, "resources", "mod_schema.xsd"), - self.settings_dict["Save"]["validate_ignore"]) + validate_tree( + parse(BytesIO(tostring(self._config_root, pretty_print=True))), + join(cur_folder, "resources", "mod_schema.xsd"), + self.settings_dict["Save"]["validate_ignore"] + ) if self.settings_dict["Save"]["warnings"]: - check_warnings(self.package_path, self.config_root, self.settings_dict["Save"]["warn_ignore"]) - export(self.info_root, self.config_root, self.package_path) - self.fomod_modified(False) + check_warnings( + self._package_path, + self._config_root, + self.settings_dict["Save"]["warn_ignore"] + ) + export(self._info_root, self._config_root, self._package_path) + self.undo_stack.setClean() except ValidatorError as e: generic_errorbox(e.title, str(e)) return - def options(self): + def settings(self): """ Opens the Settings dialog. """ @@ -315,21 +780,23 @@ def refresh(self): Refreshes all the previews if the refresh rate in Settings is high enough. """ if self.settings_dict["General"]["code_refresh"] >= 1: - self.xml_code_changed.emit(self.current_object) + self.update_previews.emit(self.current_node) def delete(self): """ Deletes the current node in the tree. No effect when using the Basic View. """ try: - if self.current_object is not None: - object_to_delete = self.current_object - new_index = self.tree_model.indexFromItem(self.current_object.getparent().model_item) - object_to_delete.getparent().remove_child(object_to_delete) - self.fomod_modified(True) - self.selected_object_tree(new_index) + if self.current_node is None: + self.statusBar().showMessage("Can't delete nothing.") + else: + self.undo_stack.push(self.DeleteCommand( + self.current_node, + self.node_tree_model, + self.select_node + )) except AttributeError: - generic_errorbox("You can't do that...", "You can't delete root objects!") + self.statusBar().showMessage("Can't delete root nodes.") @staticmethod def help(): @@ -349,13 +816,11 @@ def clear_recent_files(self): """ Clears the Recent Files gui menu and settings. """ - config = ConfigParser() - config.read_dict(read_settings()) - for key in config["Recent Files"]: - config["Recent Files"][key] = "" + self.settings_dict["Recent Files"].clear() makedirs(join(expanduser("~"), ".fomod"), exist_ok=True) with open(join(expanduser("~"), ".fomod", ".designer"), "w") as configfile: - config.write(configfile) + set_encoder_options("json", indent=4) + configfile.write(encode(self.settings_dict)) for child in self.menu_Recent_Files.actions(): if child is not self.actionClear: @@ -369,90 +834,36 @@ def update_recent_files(self, add_new=None): :param add_new: If a new installer is being opened, add it to the list or move it to the top. """ - def invalid_path(path_): - """ - Called when a Recent Files path in invalid. Requests user decision on wether to delete the item or to leave - it. - - :param path_: The invalid path. - """ - msg_box = QMessageBox() - msg_box.setWindowTitle("This path no longer exists.") - msg_box.setText("Remove it from the Recent Files list?") - msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No) - msg_box.setDefaultButton(QMessageBox.Yes) - answer = msg_box.exec_() - config_ = ConfigParser() - config_.read_dict(read_settings()) - if answer == QMessageBox.Yes: - for key in config_["Recent Files"]: - if config_["Recent Files"][key] == path_: - config_["Recent Files"][key] = "" - with open(join(expanduser("~"), ".fomod", ".designer"), "w") as configfile_: - config_.write(configfile_) - self.update_recent_files() - elif answer == QMessageBox.No: - pass - - file_list = [] - settings = read_settings() - - # Populate the file_list with the existing recent files - for index in range(1, len(settings["Recent Files"])): - if settings["Recent Files"]["file" + str(index)]: - file_list.append(settings["Recent Files"]["file" + str(index)]) - - # remove all duplicates there was an issue with duplicate after invalid path - seen = set() - seen_add = seen.add - file_list = [x for x in file_list if not (x in seen or seen_add(x))] - + file_list = deque(self.settings_dict["Recent Files"], maxlen=5) self.clear_recent_files() + # check for invalid paths and remove them + for path in file_list: + if not isdir(path): + file_list.remove(path) + # check if the path is new or if it already exists - delete the last one or reorder respectively if add_new: if add_new in file_list: file_list.remove(add_new) - elif len(file_list) == 5: - file_list.pop() - file_list.insert(0, add_new) + file_list.appendleft(add_new) # write the new list to the settings file - config = ConfigParser() - config.read_dict(settings) - for path in file_list: - config["Recent Files"]["file" + str(file_list.index(path) + 1)] = path + self.settings_dict["Recent Files"] = file_list makedirs(join(expanduser("~"), ".fomod"), exist_ok=True) with open(join(expanduser("~"), ".fomod", ".designer"), "w") as configfile: - config.write(configfile) + set_encoder_options("json", indent=4) + configfile.write(encode(self.settings_dict)) # populate the gui menu with the new files list self.menu_Recent_Files.removeAction(self.actionClear) - for path in file_list: + for path in self.settings_dict["Recent Files"]: action = self.menu_Recent_Files.addAction(path) - action.triggered.connect(lambda x, path_=path: self.open(path_) if isdir(path_) else invalid_path(path_)) + action.triggered.connect(lambda _, path_=path: self.open(path_)) self.menu_Recent_Files.addSeparator() self.menu_Recent_Files.addAction(self.actionClear) - def selected_object_tree(self, index): - """ - Called when the user selects a node in the Object Tree. - - Updates the current object, emits the preview update signal if Settings allows it, - updates the possible children list, the properties list and wizard buttons. - - :param index: The selected node's index. - """ - self.current_object = self.tree_model.itemFromIndex(index).xml_node - self.object_tree_view.setCurrentIndex(index) - if self.settings_dict["General"]["code_refresh"] >= 2: - self.xml_code_changed.emit(self.current_object) - - self.update_box_list() - self.update_props_list() - self.update_wizard_button() - - def update_box_list(self): + def update_children_box(self): """ Updates the possible children to add in Object Box. """ @@ -462,51 +873,62 @@ def update_box_list(self): if widget is not None: widget.deleteLater() - for child in self.current_object.allowed_children: + for child in self.current_node.allowed_children: new_object = child() - if self.current_object.can_add_child(new_object): - child_button = QPushButton(new_object.name) - font_button = QFont() - font_button.setPointSize(8) - child_button.setFont(font_button) - child_button.setMaximumSize(5000, 30) - child_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - child_button.clicked.connect(lambda _, tag_=new_object.tag: self.selected_object_list(tag_)) - self.layout_box.addWidget(child_button) + child_button = QPushButton(new_object.name) + font_button = QFont() + font_button.setPointSize(8) + child_button.setFont(font_button) + child_button.setMaximumSize(5000, 30) + child_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + child_button.setStatusTip("A possible child node.") + child_button.clicked.connect( + lambda _, + tag_=new_object.tag, + parent_node=self.current_node, + tree_model=self.node_tree_model, + settings_dict=self.settings_dict, + : self.undo_stack.push(self.AddChildCommand( + tag_, + parent_node, + tree_model, + settings_dict, + self.select_node + )) + ) + if not self.current_node.can_add_child(new_object): + child_button.setEnabled(False) + if child in self.current_node.required_children: + child_button.setStyleSheet( + "background-color: " + QColor(self.settings_dict["Appearance"]["required_colour"]).name() + ) + child_button.setStatusTip( + "A button of this colour indicates that at least one of this node is required." + ) + if child in self.current_node.either_children_group: + child_button.setStyleSheet( + "background-color: " + QColor(self.settings_dict["Appearance"]["either_colour"]).name() + ) + child_button.setStatusTip( + "A button of this colour indicates that only one of these buttons must be used." + ) + if child in self.current_node.at_least_one_children_group: + child_button.setStyleSheet( + "background-color: " + QColor(self.settings_dict["Appearance"]["atleastone_colour"]).name() + ) + child_button.setStatusTip( + "A button of this colour indicates that from all of these buttons, at least one is required." + ) + self.layout_box.addWidget(child_button) self.layout_box.addSpacerItem(spacer) - def selected_object_list(self, tag): - """ - Called when the user selects a possible child in the Object Box. - - Adds the child corresponding to the tag and updates the possible children list. - - :param tag: The tag of the child to add. - """ - new_child = elem_factory(tag, self.current_object) - self.current_object.add_child(new_child) - - # expand the parent - current_index = self.tree_model.indexFromItem(self.current_object.model_item) - self.object_tree_view.expand(current_index) - - # select the new item - self.object_tree_view.setCurrentIndex(self.tree_model.indexFromItem(new_child.model_item)) - self.selected_object_tree(self.tree_model.indexFromItem(new_child.model_item)) - - # reload the object box - self.update_box_list() - - # set the installer as changed - self.fomod_modified(True) - def clear_prop_list(self): """ Deletes all the properties from the Property Editor """ - self.current_prop_list.clear() - for index in reversed(range(self.formLayout.count())): - widget = self.formLayout.takeAt(index).widget() + self._current_prop_list.clear() + for index in reversed(range(self.layout_prop_editor.count())): + widget = self.layout_prop_editor.takeAt(index).widget() if widget is not None: widget.deleteLater() @@ -518,27 +940,9 @@ def update_props_list(self): self.clear_prop_list() prop_index = 0 - prop_list = self.current_prop_list - props = self.current_object.properties - - if self.current_object.allow_text: - text_label = QLabel(self.dockWidgetContents) - text_label.setObjectName("text_label") - text_label.setText("Text") - self.formLayout.setWidget(prop_index, QFormLayout.LabelRole, text_label) - prop_list.append(QLineEdit(self.dockWidgetContents)) - prop_list[prop_index].setObjectName(str(prop_index)) - prop_list[prop_index].setText(self.current_object.text) - prop_list[prop_index].textEdited[str].connect(self.current_object.set_text) - prop_list[prop_index].textEdited[str].connect(self.current_object.write_attribs) - prop_list[prop_index].textEdited[str].connect(self.fomod_modified) - prop_list[prop_index].textEdited[str].connect(lambda: self.xml_code_changed.emit(self.current_object) - if self.settings_dict["General"]["code_refresh"] >= 3 - else None) - self.formLayout.setWidget(prop_index, QFormLayout.FieldRole, - prop_list[prop_index]) - - prop_index += 1 + og_values = self.original_prop_value_list + prop_list = self._current_prop_list + props = self.current_node.properties for key in props: if not props[key].editable: @@ -547,142 +951,438 @@ def update_props_list(self): label = QLabel(self.dockWidgetContents) label.setObjectName("label_" + str(prop_index)) label.setText(props[key].name) - self.formLayout.setWidget(prop_index, QFormLayout.LabelRole, label) - - if isinstance(props[key], PropertyText): + self.layout_prop_editor.setWidget(prop_index, QFormLayout.LabelRole, label) + + if type(props[key]) is PropertyText: + def open_plain_editor(line_edit_): + dialog_ui = window_plaintexteditor.Ui_Dialog() + dialog = QDialog(self) + dialog_ui.setupUi(dialog) + dialog_ui.edit_text.setPlainText(line_edit_.text()) + dialog_ui.buttonBox.accepted.connect(dialog.close) + dialog_ui.buttonBox.accepted.connect(lambda: line_edit_.setText(dialog_ui.edit_text.toPlainText())) + dialog_ui.buttonBox.accepted.connect(line_edit_.editingFinished.emit) + dialog.exec_() + + og_values[prop_index] = props[key].value + prop_list.append(QWidget(self.dockWidgetContents)) + layout = QHBoxLayout(prop_list[prop_index]) + text_edit = QLineEdit(prop_list[prop_index]) + text_button = QPushButton(prop_list[prop_index]) + text_button.setText("...") + text_button.setMaximumWidth(30) + layout.addWidget(text_edit) + layout.addWidget(text_button) + layout.setContentsMargins(0, 0, 0, 0) + text_edit.setText(props[key].value) + text_edit.textChanged.connect(props[key].set_value) + text_edit.textChanged[str].connect(self.current_node.write_attribs) + text_edit.textChanged[str].connect(self.current_node.update_item_name) + text_edit.textChanged[str].connect( + lambda: self.xml_code_changed.emit(self.current_node) + if self.settings_dict["General"]["code_refresh"] >= 3 else None + ) + text_edit.editingFinished.connect( + lambda index=prop_index: self.undo_stack.push( + self.WidgetLineEditChangeCommand( + og_values[index], + text_edit.text(), + self.current_prop_list, + index, + self.node_tree_model, + self.current_node.model_item, + self.select_node + ) + ) + if og_values[index] != text_edit.text() else None + ) + text_edit.editingFinished.connect( + lambda index=prop_index: og_values.update({index: text_edit.text()}) + ) + text_button.clicked.connect(lambda _, line_edit_=text_edit: open_plain_editor(line_edit_)) + + if type(props[key]) is PropertyHTML: + def open_plain_editor(line_edit_): + dialog_ui = window_texteditor.Ui_Dialog() + dialog = QDialog(self) + dialog_ui.setupUi(dialog) + + dialog_ui.radio_html.toggled.connect(dialog_ui.widget_warning.setVisible) + dialog_ui.button_colour.clicked.connect( + lambda: dialog_ui.edit_text.setTextColor(QColorDialog.getColor()) + ) + dialog_ui.button_bold.clicked.connect( + lambda: dialog_ui.edit_text.setFontWeight(QFont.Bold) + if dialog_ui.edit_text.fontWeight() == QFont.Normal + else dialog_ui.edit_text.setFontWeight(QFont.Normal) + ) + dialog_ui.button_italic.clicked.connect( + lambda: dialog_ui.edit_text.setFontItalic(not dialog_ui.edit_text.fontItalic()) + ) + dialog_ui.button_underline.clicked.connect( + lambda: dialog_ui.edit_text.setFontUnderline(not dialog_ui.edit_text.fontUnderline()) + ) + dialog_ui.button_align_left.clicked.connect( + lambda: dialog_ui.edit_text.setAlignment(Qt.AlignLeft) + ) + dialog_ui.button_align_center.clicked.connect( + lambda: dialog_ui.edit_text.setAlignment(Qt.AlignCenter) + ) + dialog_ui.button_align_right.clicked.connect( + lambda: dialog_ui.edit_text.setAlignment(Qt.AlignRight) + ) + dialog_ui.button_align_justify.clicked.connect( + lambda: dialog_ui.edit_text.setAlignment(Qt.AlignJustify) + ) + dialog_ui.buttonBox.accepted.connect(dialog.close) + dialog_ui.buttonBox.accepted.connect( + lambda: line_edit_.setText(dialog_ui.edit_text.toPlainText()) + if dialog_ui.radio_plain.isChecked() + else line_edit_.setText(dialog_ui.edit_text.toHtml()) + ) + dialog_ui.buttonBox.accepted.connect(line_edit_.editingFinished.emit) + + dialog_ui.widget_warning.hide() + dialog_ui.label_warning.setPixmap(QPixmap(join(cur_folder, "resources/logos/logo_danger.png"))) + dialog_ui.button_colour.setIcon(QIcon(join(cur_folder, "resources/logos/logo_font_colour.png"))) + dialog_ui.button_bold.setIcon(QIcon(join(cur_folder, "resources/logos/logo_font_bold.png"))) + dialog_ui.button_italic.setIcon(QIcon(join(cur_folder, "resources/logos/logo_font_italic.png"))) + dialog_ui.button_underline.setIcon(QIcon( + join(cur_folder, "resources/logos/logo_font_underline.png") + )) + dialog_ui.button_align_left.setIcon(QIcon( + join(cur_folder, "resources/logos/logo_font_align_left.png") + )) + dialog_ui.button_align_center.setIcon(QIcon( + join(cur_folder, "resources/logos/logo_font_align_center.png") + )) + dialog_ui.button_align_right.setIcon(QIcon( + join(cur_folder, "resources/logos/logo_font_align_right.png") + )) + dialog_ui.button_align_justify.setIcon(QIcon( + join(cur_folder, "resources/logos/logo_font_align_justify.png") + )) + dialog_ui.edit_text.setText(line_edit_.text()) + dialog.exec_() + + og_values[prop_index] = props[key].value + prop_list.append(QWidget(self.dockWidgetContents)) + layout = QHBoxLayout(prop_list[prop_index]) + text_edit = QLineEdit(prop_list[prop_index]) + text_button = QPushButton(prop_list[prop_index]) + text_button.setText("...") + text_button.setMaximumWidth(30) + layout.addWidget(text_edit) + layout.addWidget(text_button) + layout.setContentsMargins(0, 0, 0, 0) + text_edit.setText(props[key].value) + text_edit.textChanged.connect(props[key].set_value) + text_edit.textChanged[str].connect(self.current_node.write_attribs) + text_edit.textChanged[str].connect(self.current_node.update_item_name) + text_edit.textChanged[str].connect( + lambda: self.xml_code_changed.emit(self.current_node) + if self.settings_dict["General"]["code_refresh"] >= 3 else None + ) + text_edit.editingFinished.connect( + lambda index=prop_index: self.undo_stack.push( + self.WidgetLineEditChangeCommand( + og_values[index], + text_edit.text(), + self.current_prop_list, + index, + self.node_tree_model, + self.current_node.model_item, + self.select_node + ) + ) + if og_values[index] != text_edit.text() else None + ) + text_edit.editingFinished.connect( + lambda index=prop_index: og_values.update({index: text_edit.text()}) + ) + text_button.clicked.connect(lambda _, line_edit_=text_edit: open_plain_editor(line_edit_)) + + if type(props[key]) is PropertyFlagLabel: + og_values[prop_index] = props[key].value prop_list.append(QLineEdit(self.dockWidgetContents)) + self.update_flag_label_completer(self.flag_label_model, self._config_root) + self.flag_label_completer.activated[str].connect(prop_list[prop_index].setText) + prop_list[prop_index].setCompleter(self.flag_label_completer) + prop_list[prop_index].textChanged[str].connect( + lambda text: self.update_flag_value_completer(self.flag_value_model, self._config_root, text) + ) prop_list[prop_index].setText(props[key].value) - prop_list[prop_index].textEdited[str].connect(props[key].set_value) - prop_list[prop_index].textEdited[str].connect(self.current_object.write_attribs) - prop_list[prop_index].textEdited[str].connect(self.current_object.update_item_name) - prop_list[prop_index].textEdited[str].connect(self.fomod_modified) - prop_list[prop_index].textEdited[str].connect(lambda: self.xml_code_changed.emit(self.current_object) - if self.settings_dict["General"]["code_refresh"] >= 3 - else None) - - elif isinstance(props[key], PropertyInt): + prop_list[prop_index].textChanged[str].connect(props[key].set_value) + prop_list[prop_index].textChanged[str].connect(self.current_node.write_attribs) + prop_list[prop_index].textChanged[str].connect(self.current_node.update_item_name) + prop_list[prop_index].textChanged[str].connect( + lambda: self.xml_code_changed.emit(self.current_node) + if self.settings_dict["General"]["code_refresh"] >= 3 else None + ) + prop_list[prop_index].editingFinished.connect( + lambda index=prop_index: self.undo_stack.push( + self.LineEditChangeCommand( + og_values[index], + prop_list[index].text(), + self.current_prop_list, + index, + self.node_tree_model, + self.current_node.model_item, + self.select_node + ) + ) + if og_values[index] != prop_list[index].text() else None + ) + prop_list[prop_index].editingFinished.connect( + lambda index=prop_index: og_values.update({index: prop_list[index].text()}) + ) + + if type(props[key]) is PropertyFlagValue: + og_values[prop_index] = props[key].value + prop_list.append(QLineEdit(self.dockWidgetContents)) + prop_list[prop_index].setCompleter(self.flag_value_completer) + self.flag_value_completer.activated[str].connect(prop_list[prop_index].setText) + prop_list[prop_index].setText(props[key].value) + prop_list[prop_index].textChanged[str].connect(props[key].set_value) + prop_list[prop_index].textChanged[str].connect(self.current_node.write_attribs) + prop_list[prop_index].textChanged[str].connect(self.current_node.update_item_name) + prop_list[prop_index].textChanged[str].connect( + lambda: self.xml_code_changed.emit(self.current_node) + if self.settings_dict["General"]["code_refresh"] >= 3 else None + ) + prop_list[prop_index].editingFinished.connect( + lambda index=prop_index: self.undo_stack.push( + self.LineEditChangeCommand( + og_values[index], + prop_list[index].text(), + self.current_prop_list, + index, + self.node_tree_model, + self.current_node.model_item, + self.select_node + ) + ) + if og_values[index] != prop_list[index].text() else None + ) + prop_list[prop_index].editingFinished.connect( + lambda index=prop_index: og_values.update({index: prop_list[index].text()}) + ) + + elif type(props[key]) is PropertyInt: + og_values[prop_index] = props[key].value prop_list.append(QSpinBox(self.dockWidgetContents)) prop_list[prop_index].setValue(int(props[key].value)) prop_list[prop_index].setMinimum(props[key].min) prop_list[prop_index].setMaximum(props[key].max) prop_list[prop_index].valueChanged.connect(props[key].set_value) - prop_list[prop_index].valueChanged.connect(self.current_object.write_attribs) - prop_list[prop_index].valueChanged.connect(self.fomod_modified) - prop_list[prop_index].valueChanged.connect(lambda: self.xml_code_changed.emit(self.current_object) - if self.settings_dict["General"]["code_refresh"] >= 3 - else None) - - elif isinstance(props[key], PropertyCombo): + prop_list[prop_index].valueChanged.connect(self.current_node.write_attribs) + prop_list[prop_index].valueChanged.connect( + lambda: self.xml_code_changed.emit(self.current_node) + if self.settings_dict["General"]["code_refresh"] >= 3 else None + ) + prop_list[prop_index].valueChanged.connect( + lambda new_value, index=prop_index: self.undo_stack.push( + self.SpinBoxChangeCommand( + og_values[index], + new_value, + self.current_prop_list, + index, + self.node_tree_model, + self.current_node.model_item, + self.select_node + ) + ) + if og_values[index] != new_value else None + ) + prop_list[prop_index].valueChanged.connect( + lambda new_value, index=prop_index: og_values.update({index: new_value}) + ) + + elif type(props[key]) is PropertyCombo: + og_values[prop_index] = props[key].value prop_list.append(QComboBox(self.dockWidgetContents)) prop_list[prop_index].insertItems(0, props[key].values) prop_list[prop_index].setCurrentIndex(props[key].values.index(props[key].value)) - prop_list[prop_index].activated[str].connect(props[key].set_value) - prop_list[prop_index].activated[str].connect(self.current_object.write_attribs) - prop_list[prop_index].activated[str].connect(self.current_object.update_item_name) - prop_list[prop_index].activated[str].connect(self.fomod_modified) - prop_list[prop_index].activated[str].connect(lambda: self.xml_code_changed.emit(self.current_object) - if self.settings_dict["General"]["code_refresh"] >= 3 - else None) - - elif isinstance(props[key], PropertyFile): - def button_clicked(): + prop_list[prop_index].currentTextChanged.connect(props[key].set_value) + prop_list[prop_index].currentTextChanged.connect(self.current_node.write_attribs) + prop_list[prop_index].currentTextChanged.connect(self.current_node.update_item_name) + prop_list[prop_index].currentTextChanged.connect( + lambda: self.xml_code_changed.emit(self.current_node) + if self.settings_dict["General"]["code_refresh"] >= 3 else None + ) + prop_list[prop_index].activated[str].connect( + lambda new_value, index=prop_index: self.undo_stack.push( + self.ComboBoxChangeCommand( + og_values[index], + new_value, + self.current_prop_list, + index, + self.node_tree_model, + self.current_node.model_item, + self.select_node + ) + ) + ) + prop_list[prop_index].activated[str].connect( + lambda new_value, index=prop_index: og_values.update({index: new_value}) + ) + + elif type(props[key]) is PropertyFile: + def button_clicked(line_edit_): open_dialog = QFileDialog() - file_path = open_dialog.getOpenFileName(self, "Select File:", self.package_path) + file_path = open_dialog.getOpenFileName(self, "Select File:", self._package_path) if file_path[0]: - line_edit.setText(relpath(file_path[0], self.package_path)) + line_edit.setText(relpath(file_path[0], self._package_path)) + line_edit_.editingFinished.emit() + og_values[prop_index] = props[key].value prop_list.append(QWidget(self.dockWidgetContents)) layout = QHBoxLayout(prop_list[prop_index]) line_edit = QLineEdit(prop_list[prop_index]) - path_button = QPushButton(prop_list[prop_index]) - path_button.setText("...") + push_button = QPushButton(prop_list[prop_index]) + push_button.setText("...") + push_button.setMaximumWidth(30) layout.addWidget(line_edit) - layout.addWidget(path_button) + layout.addWidget(push_button) layout.setContentsMargins(0, 0, 0, 0) line_edit.setText(props[key].value) line_edit.textChanged.connect(props[key].set_value) - line_edit.textChanged[str].connect(self.current_object.write_attribs) - line_edit.textChanged[str].connect(self.current_object.update_item_name) - line_edit.textChanged[str].connect(self.fomod_modified) - line_edit.textChanged[str].connect(lambda: self.xml_code_changed.emit(self.current_object) - if self.settings_dict["General"]["code_refresh"] >= 3 else None) - path_button.clicked.connect(button_clicked) - - elif isinstance(props[key], PropertyFolder): - def button_clicked(): + line_edit.textChanged[str].connect(self.current_node.write_attribs) + line_edit.textChanged[str].connect(self.current_node.update_item_name) + line_edit.textChanged[str].connect( + lambda: self.xml_code_changed.emit(self.current_node) + if self.settings_dict["General"]["code_refresh"] >= 3 else None + ) + line_edit.editingFinished.connect( + lambda index=prop_index: self.undo_stack.push( + self.WidgetLineEditChangeCommand( + og_values[index], + line_edit.text(), + self.current_prop_list, + index, + self.node_tree_model, + self.current_node.model_item, + self.select_node + ) + ) + if og_values[index] != line_edit.text() else None + ) + line_edit.editingFinished.connect( + lambda index=prop_index: og_values.update({index: line_edit.text()}) + ) + push_button.clicked.connect(lambda _, line_edit_=line_edit: button_clicked(line_edit_)) + + elif type(props[key]) is PropertyFolder: + def button_clicked(line_edit_): open_dialog = QFileDialog() - folder_path = open_dialog.getExistingDirectory(self, "Select folder:", self.package_path) + folder_path = open_dialog.getExistingDirectory(self, "Select folder:", self._package_path) if folder_path: - line_edit.setText(relpath(folder_path, self.package_path)) + line_edit.setText(relpath(folder_path, self._package_path)) + line_edit_.editingFinished.emit() + og_values[prop_index] = props[key].value prop_list.append(QWidget(self.dockWidgetContents)) layout = QHBoxLayout(prop_list[prop_index]) line_edit = QLineEdit(prop_list[prop_index]) - path_button = QPushButton(prop_list[prop_index]) - path_button.setText("...") + push_button = QPushButton(prop_list[prop_index]) + push_button.setText("...") + push_button.setMaximumWidth(30) layout.addWidget(line_edit) - layout.addWidget(path_button) + layout.addWidget(push_button) layout.setContentsMargins(0, 0, 0, 0) line_edit.setText(props[key].value) line_edit.textChanged.connect(props[key].set_value) - line_edit.textChanged.connect(self.current_object.write_attribs) - line_edit.textChanged.connect(self.current_object.update_item_name) - line_edit.textChanged.connect(self.fomod_modified) - line_edit.textChanged.connect(lambda: self.xml_code_changed.emit(self.current_object) - if self.settings_dict["General"]["code_refresh"] >= 3 else None) - path_button.clicked.connect(button_clicked) - - elif isinstance(props[key], PropertyColour): - def button_clicked(): + line_edit.textChanged.connect(self.current_node.write_attribs) + line_edit.textChanged.connect(self.current_node.update_item_name) + line_edit.textChanged.connect( + lambda: self.xml_code_changed.emit(self.current_node) + if self.settings_dict["General"]["code_refresh"] >= 3 else None + ) + line_edit.editingFinished.connect( + lambda index=prop_index: self.undo_stack.push( + self.WidgetLineEditChangeCommand( + og_values[index], + line_edit.text(), + self.current_prop_list, + index, + self.node_tree_model, + self.current_node.model_item, + self.select_node + ) + ) + if og_values[index] != line_edit.text() else None + ) + line_edit.editingFinished.connect( + lambda index=prop_index: og_values.update({index: line_edit.text()}) + ) + push_button.clicked.connect(lambda _, line_edit_=line_edit: button_clicked(line_edit_)) + + elif type(props[key]) is PropertyColour: + def button_clicked(line_edit_): init_colour = QColor("#" + props[key].value) colour_dialog = QColorDialog() colour = colour_dialog.getColor(init_colour, self, "Choose Colour:") if colour.isValid(): line_edit.setText(colour.name()[1:]) + line_edit_.editingFinished.emit() def update_button_colour(text): colour = QColor("#" + text) if colour.isValid() and len(text) == 6: - path_button.setStyleSheet("background-color: " + colour.name()) - path_button.setIcon(QIcon()) + push_button.setStyleSheet("background-color: " + colour.name()) + push_button.setIcon(QIcon()) else: - path_button.setStyleSheet("background-color: #ffffff") + push_button.setStyleSheet("background-color: #ffffff") icon = QIcon() icon.addPixmap(QPixmap(join(cur_folder, "resources/logos/logo_danger.png")), QIcon.Normal, QIcon.Off) - path_button.setIcon(icon) + push_button.setIcon(icon) + og_values[prop_index] = props[key].value prop_list.append(QWidget(self.dockWidgetContents)) layout = QHBoxLayout(prop_list[prop_index]) line_edit = QLineEdit(prop_list[prop_index]) line_edit.setMaxLength(6) - path_button = QPushButton(prop_list[prop_index]) + push_button = QPushButton(prop_list[prop_index]) + push_button.setMinimumHeight(21) + push_button.setMinimumWidth(30) + push_button.setMaximumHeight(21) + push_button.setMaximumWidth(30) layout.addWidget(line_edit) - layout.addWidget(path_button) + layout.addWidget(push_button) layout.setContentsMargins(0, 0, 0, 0) line_edit.setText(props[key].value) update_button_colour(line_edit.text()) line_edit.textChanged.connect(props[key].set_value) line_edit.textChanged.connect(update_button_colour) - line_edit.textChanged.connect(self.current_object.write_attribs) - line_edit.textChanged.connect(self.fomod_modified) - line_edit.textChanged.connect(lambda: self.xml_code_changed.emit(self.current_object) - if self.settings_dict["General"]["code_refresh"] >= 3 else None) - path_button.clicked.connect(button_clicked) - - self.formLayout.setWidget(prop_index, QFormLayout.FieldRole, prop_list[prop_index]) + line_edit.textChanged.connect(self.current_node.write_attribs) + line_edit.textChanged.connect( + lambda: self.xml_code_changed.emit(self.current_node) + if self.settings_dict["General"]["code_refresh"] >= 3 else None + ) + line_edit.editingFinished.connect( + lambda index=prop_index: self.undo_stack.push( + self.WidgetLineEditChangeCommand( + og_values[index], + line_edit.text(), + self.current_prop_list, + index, + self.node_tree_model, + self.current_node.model_item, + self.select_node + ) + ) + if og_values[index] != line_edit.text() else None + ) + line_edit.editingFinished.connect( + lambda index=prop_index: og_values.update({index: line_edit.text()}) + ) + push_button.clicked.connect(lambda _, line_edit_=line_edit: button_clicked(line_edit_)) + + self.layout_prop_editor.setWidget(prop_index, QFormLayout.FieldRole, prop_list[prop_index]) prop_list[prop_index].setObjectName(str(prop_index)) prop_index += 1 - def update_wizard_button(self): - """ - Updates the wizard button, hides or shows it. - """ - if self.current_object.wizard: - self.wizard_button.show() - else: - self.wizard_button.hide() - def run_wizard(self): """ Called when the wizard button is clicked. @@ -698,7 +1398,7 @@ def close(): self.menu_Tools.setEnabled(True) self.menu_View.setEnabled(True) - current_index = self.tree_model.indexFromItem(self.current_object.model_item) + current_index = self.node_tree_model.indexFromItem(self.current_node.model_item) enabled_tree = self.action_Object_Tree.isChecked() enabled_box = self.actionObject_Box.isChecked() enabled_list = self.action_Property_Editor.isChecked() @@ -709,31 +1409,34 @@ def close(): self.menu_Tools.setEnabled(False) self.menu_View.setEnabled(False) - wizard = self.current_object.wizard(self, self.current_object, self) + parent_node = self.current_node.getparent() + original_node = self.current_node + + kwargs = {"package_path": self._package_path} + wizard = self.current_node.wizard(self, self.current_node, self.xml_code_changed, **kwargs) self.splitter.insertWidget(0, wizard) wizard.cancelled.connect(close) - wizard.cancelled.connect(lambda: self.selected_object_tree(current_index)) + wizard.cancelled.connect(lambda: self.select_node.emit(current_index)) wizard.finished.connect(close) - wizard.finished.connect(lambda: self.selected_object_tree(current_index)) - wizard.finished.connect(lambda: self.fomod_modified(True)) - - def fomod_modified(self, changed): - """ - Changes the modified state of the installer, according to the parameter. - """ - if changed is False: - self.fomod_changed = False - self.setWindowTitle(self.package_name + " - " + self.original_title) - else: - self.fomod_changed = True - self.setWindowTitle("*" + self.package_name + " - " + self.original_title) + wizard.finished.connect( + lambda result: self.undo_stack.push( + self.RunWizardCommand( + parent_node, + original_node, + result, + self.node_tree_model, + self.select_node + ) + ) + ) + wizard.finished.connect(lambda: self.select_node.emit(current_index)) def check_fomod_state(self): """ Checks whether the installer has unsaved changes. """ - if self.fomod_changed: + if not self.undo_stack.isClean(): msg_box = QMessageBox() msg_box.setWindowTitle("The installer has been modified.") msg_box.setText("Do you want to save your changes?") @@ -759,7 +1462,7 @@ def closeEvent(self, event): event.ignore() -class SettingsDialog(settings_ui[0], settings_ui[1]): +class SettingsDialog(QDialog, window_settings.Ui_Dialog): """ The class for the settings window. Subclassed from QDialog and created in Qt Designer. """ @@ -768,82 +1471,167 @@ def __init__(self, parent): self.setupUi(self) self.setWindowFlags(Qt.WindowSystemMenuHint | Qt.WindowTitleHint | Qt.Dialog) + self.label_warning_palette.setPixmap(QPixmap(join(cur_folder, "resources/logos/logo_danger.png"))) + self.label_warning_style.setPixmap(QPixmap(join(cur_folder, "resources/logos/logo_danger.png"))) + self.widget_warning_palette.hide() + self.widget_warning_style.hide() + self.settings_dict = read_settings() self.buttonBox.accepted.connect(self.accepted) - self.buttonBox.rejected.connect(self.rejected) - self.check_valid_load.stateChanged.connect(self.update_valid_load) - self.check_warn_load.stateChanged.connect(self.update_warn_load) - self.check_valid_save.stateChanged.connect(self.update_valid_save) - self.check_warn_save.stateChanged.connect(self.update_warn_save) - - config = read_settings() - self.combo_code_refresh.setCurrentIndex(config["General"]["code_refresh"]) - self.check_intro.setChecked(config["General"]["show_intro"]) - self.check_advanced.setChecked(config["General"]["show_advanced"]) - self.check_valid_load.setChecked(config["Load"]["validate"]) - self.check_valid_load_ignore.setChecked(config["Load"]["validate_ignore"]) - self.check_warn_load.setChecked(config["Load"]["warnings"]) - self.check_warn_load_ignore.setChecked(config["Load"]["warn_ignore"]) - self.check_valid_save.setChecked(config["Save"]["validate"]) - self.check_valid_save_ignore.setChecked(config["Save"]["validate_ignore"]) - self.check_warn_save.setChecked(config["Save"]["warnings"]) - self.check_warn_save_ignore.setChecked(config["Save"]["warn_ignore"]) - - self.check_valid_load.stateChanged.emit(self.check_valid_load.isChecked()) - self.check_warn_load.stateChanged.emit(self.check_warn_load.isChecked()) - self.check_valid_save.stateChanged.emit(self.check_valid_save.isChecked()) - self.check_warn_save.stateChanged.emit(self.check_warn_save.isChecked()) + self.buttonBox.rejected.connect(self.close) + + self.check_valid_load.stateChanged.connect(self.check_valid_load_ignore.setEnabled) + self.check_warn_load.stateChanged.connect(self.check_warn_load_ignore.setEnabled) + self.check_valid_save.stateChanged.connect(self.check_valid_save_ignore.setEnabled) + self.check_warn_save.stateChanged.connect(self.check_warn_save_ignore.setEnabled) + + self.check_installSteps.stateChanged.connect(self.combo_installSteps.setEnabled) + self.check_optionalFileGroups.stateChanged.connect(self.combo_optionalFileGroups.setEnabled) + self.check_type.stateChanged.connect(self.combo_type.setEnabled) + self.check_defaultType.stateChanged.connect(self.combo_defaultType.setEnabled) + + self.button_colour_required.clicked.connect( + lambda: self.button_colour_required.setStyleSheet( + "background-color: " + QColorDialog().getColor( + QColor(self.button_colour_required.styleSheet().split()[1]), + self, + "Choose Colour:" + ).name() + ) + ) + self.button_colour_atleastone.clicked.connect( + lambda: self.button_colour_atleastone.setStyleSheet( + "background-color: " + QColorDialog().getColor( + QColor(self.button_colour_atleastone.styleSheet().split()[1]), + self, + "Choose Colour:" + ).name() + ) + ) + self.button_colour_either.clicked.connect( + lambda: self.button_colour_either.setStyleSheet( + "background-color: " + QColorDialog().getColor( + QColor(self.button_colour_either.styleSheet().split()[1]), + self, + "Choose Colour:" + ).name() + ) + ) + self.button_colour_reset_required.clicked.connect( + lambda: self.button_colour_required.setStyleSheet("background-color: #d90027") + ) + self.button_colour_reset_atleastone.clicked.connect( + lambda: self.button_colour_atleastone.setStyleSheet("background-color: #d0d02e") + ) + self.button_colour_reset_either.clicked.connect( + lambda: self.button_colour_either.setStyleSheet("background-color: #ffaa7f") + ) + self.combo_style.currentTextChanged.connect( + lambda text: self.widget_warning_style.show() + if text != self.settings_dict["Appearance"]["style"] + else self.widget_warning_style.hide() + ) + self.combo_palette.currentTextChanged.connect( + lambda text: self.widget_warning_palette.show() + if text != self.settings_dict["Appearance"]["palette"] + else self.widget_warning_palette.hide() + ) + + self.combo_code_refresh.setCurrentIndex(self.settings_dict["General"]["code_refresh"]) + self.check_intro.setChecked(self.settings_dict["General"]["show_intro"]) + self.check_advanced.setChecked(self.settings_dict["General"]["show_advanced"]) + self.check_tutorial.setChecked(self.settings_dict["General"]["tutorial_advanced"]) + + self.check_valid_load.setChecked(self.settings_dict["Load"]["validate"]) + self.check_valid_load_ignore.setChecked(self.settings_dict["Load"]["validate_ignore"]) + self.check_warn_load.setChecked(self.settings_dict["Load"]["warnings"]) + self.check_warn_load_ignore.setChecked(self.settings_dict["Load"]["warn_ignore"]) + + self.check_valid_save.setChecked(self.settings_dict["Save"]["validate"]) + self.check_valid_save_ignore.setChecked(self.settings_dict["Save"]["validate_ignore"]) + self.check_warn_save.setChecked(self.settings_dict["Save"]["warnings"]) + self.check_warn_save_ignore.setChecked(self.settings_dict["Save"]["warn_ignore"]) + + self.check_installSteps.setChecked(self.settings_dict["Defaults"]["installSteps"].enabled()) + self.combo_installSteps.setEnabled(self.settings_dict["Defaults"]["installSteps"].enabled()) + self.combo_installSteps.setCurrentText(self.settings_dict["Defaults"]["installSteps"].value()) + self.check_optionalFileGroups.setChecked(self.settings_dict["Defaults"]["optionalFileGroups"].enabled()) + self.combo_optionalFileGroups.setEnabled(self.settings_dict["Defaults"]["optionalFileGroups"].enabled()) + self.combo_optionalFileGroups.setCurrentText(self.settings_dict["Defaults"]["optionalFileGroups"].value()) + self.check_type.setChecked(self.settings_dict["Defaults"]["type"].enabled()) + self.combo_type.setEnabled(self.settings_dict["Defaults"]["type"].enabled()) + self.combo_type.setCurrentText(self.settings_dict["Defaults"]["type"].value()) + self.check_defaultType.setChecked(self.settings_dict["Defaults"]["defaultType"].enabled()) + self.combo_defaultType.setEnabled(self.settings_dict["Defaults"]["defaultType"].enabled()) + self.combo_defaultType.setCurrentText(self.settings_dict["Defaults"]["defaultType"].value()) + + self.button_colour_required.setStyleSheet( + "background-color: " + self.settings_dict["Appearance"]["required_colour"] + ) + self.button_colour_atleastone.setStyleSheet( + "background-color: " + self.settings_dict["Appearance"]["atleastone_colour"] + ) + self.button_colour_either.setStyleSheet( + "background-color: " + self.settings_dict["Appearance"]["either_colour"] + ) + if self.settings_dict["Appearance"]["style"]: + self.combo_style.setCurrentText(self.settings_dict["Appearance"]["style"]) + else: + self.combo_style.setCurrentText("Default") + if self.settings_dict["Appearance"]["palette"]: + self.combo_palette.setCurrentText(self.settings_dict["Appearance"]["palette"]) + else: + self.combo_palette.setCurrentText("Default") def accepted(self): - config = ConfigParser() - config.read_dict(read_settings()) - config["General"]["code_refresh"] = str(self.combo_code_refresh.currentIndex()) - config["General"]["show_intro"] = str(self.check_intro.isChecked()).lower() - config["General"]["show_advanced"] = str(self.check_advanced.isChecked()).lower() - config["Load"]["validate"] = str(self.check_valid_load.isChecked()).lower() - config["Load"]["validate_ignore"] = str(self.check_valid_load_ignore.isChecked()).lower() - config["Load"]["warnings"] = str(self.check_warn_load.isChecked()).lower() - config["Load"]["warn_ignore"] = str(self.check_warn_load_ignore.isChecked()).lower() - config["Save"]["validate"] = str(self.check_valid_save.isChecked()).lower() - config["Save"]["validate_ignore"] = str(self.check_valid_save_ignore.isChecked()).lower() - config["Save"]["warnings"] = str(self.check_warn_save.isChecked()).lower() - config["Save"]["warn_ignore"] = str(self.check_warn_save_ignore.isChecked()).lower() + self.settings_dict["General"]["code_refresh"] = self.combo_code_refresh.currentIndex() + self.settings_dict["General"]["show_intro"] = self.check_intro.isChecked() + self.settings_dict["General"]["show_advanced"] = self.check_advanced.isChecked() + self.settings_dict["General"]["tutorial_advanced"] = self.check_tutorial.isChecked() + + self.settings_dict["Load"]["validate"] = self.check_valid_load.isChecked() + self.settings_dict["Load"]["validate_ignore"] = self.check_valid_load_ignore.isChecked() + self.settings_dict["Load"]["warnings"] = self.check_warn_load.isChecked() + self.settings_dict["Load"]["warn_ignore"] = self.check_warn_load_ignore.isChecked() + + self.settings_dict["Save"]["validate"] = self.check_valid_save.isChecked() + self.settings_dict["Save"]["validate_ignore"] = self.check_valid_save_ignore.isChecked() + self.settings_dict["Save"]["warnings"] = self.check_warn_save.isChecked() + self.settings_dict["Save"]["warn_ignore"] = self.check_warn_save_ignore.isChecked() + + self.settings_dict["Defaults"]["installSteps"].set_enabled(self.check_installSteps.isChecked()) + self.settings_dict["Defaults"]["installSteps"].set_value(self.combo_installSteps.currentText()) + + self.settings_dict["Defaults"]["optionalFileGroups"].set_enabled(self.check_optionalFileGroups.isChecked()) + self.settings_dict["Defaults"]["optionalFileGroups"].set_value(self.combo_optionalFileGroups.currentText() + ) + self.settings_dict["Defaults"]["type"].set_enabled(self.check_type.isChecked()) + self.settings_dict["Defaults"]["type"].set_value(self.combo_type.currentText()) + + self.settings_dict["Defaults"]["defaultType"].set_enabled(self.check_defaultType.isChecked()) + self.settings_dict["Defaults"]["defaultType"].set_value(self.combo_defaultType.currentText()) + + self.settings_dict["Appearance"]["required_colour"] = self.button_colour_required.styleSheet().split()[1] + self.settings_dict["Appearance"]["atleastone_colour"] = self.button_colour_atleastone.styleSheet().split()[1] + self.settings_dict["Appearance"]["either_colour"] = self.button_colour_either.styleSheet().split()[1] + if self.combo_style.currentText() != "Default": + self.settings_dict["Appearance"]["style"] = self.combo_style.currentText() + else: + self.settings_dict["Appearance"]["style"] = "" + if self.combo_palette.currentText() != "Default": + self.settings_dict["Appearance"]["palette"] = self.combo_palette.currentText() + else: + self.settings_dict["Appearance"]["palette"] = "" makedirs(join(expanduser("~"), ".fomod"), exist_ok=True) with open(join(expanduser("~"), ".fomod", ".designer"), "w") as configfile: - config.write(configfile) + set_encoder_options("json", indent=4) + configfile.write(encode(self.settings_dict)) self.close() - def rejected(self): - self.close() - - def update_valid_load(self, new_state): - if not new_state: - self.check_valid_load_ignore.setEnabled(False) - else: - self.check_valid_load_ignore.setEnabled(True) - - def update_warn_load(self, new_state): - if not new_state: - self.check_warn_load_ignore.setEnabled(False) - else: - self.check_warn_load_ignore.setEnabled(True) - - def update_valid_save(self, new_state): - if not new_state: - self.check_valid_save_ignore.setEnabled(False) - else: - self.check_valid_save_ignore.setEnabled(True) - def update_warn_save(self, new_state): - if not new_state: - self.check_warn_save_ignore.setEnabled(False) - else: - self.check_warn_save_ignore.setEnabled(True) - - -class About(about_ui[0], about_ui[1]): +class About(QDialog, window_about.Ui_Dialog): """ The class for the about window. Subclassed from QDialog and created in Qt Designer. """ @@ -891,40 +1679,90 @@ def generic_errorbox(title, text, detail=""): def read_settings(): """ Reads the settings from the ~/.fomod/.designer file. If such a file does not exist it uses the default settings. - The settings are processed to be ready to be used in Python code (p.e. "option=1" translates to True). + The settings are processed to be ready to be used in Python code. :return: The processed settings. """ - default_settings = {"General": {"code_refresh": 3, - "show_intro": True, - "show_advanced": False}, - "Load": {"validate": True, - "validate_ignore": False, - "warnings": True, - "warn_ignore": True}, - "Save": {"validate": True, - "validate_ignore": False, - "warnings": True, - "warn_ignore": True}, - "Recent Files": {"file1": "", - "file2": "", - "file3": "", - "file4": "", - "file5": ""}} - config = ConfigParser() - config.read_dict(default_settings) - config.read(join(expanduser("~"), ".fomod", ".designer")) - - settings = {} - for section in default_settings: - settings[section] = {} - for key in default_settings[section]: - if isinstance(default_settings[section][key], bool): - settings[section][key] = config.getboolean(section, key) - elif isinstance(default_settings[section][key], int): - settings[section][key] = config.getint(section, key) - elif isinstance(default_settings[section][key], float): - settings[section][key] = config.getfloat(section, key) + class DefaultsSettings(object): + def __init__(self, key, default_enabled, default_value): + self.__enabled = default_enabled + self.__property_key = key + self.__property_value = default_value + + def set_enabled(self, enabled): + self.__enabled = enabled + + def set_value(self, value): + self.__property_value = value + + def enabled(self): + return self.__enabled + + def value(self): + return self.__property_value + + def key(self): + return self.__property_key + + def deep_merge(a, b, path=None): + """merges b into a""" + if path is None: + path = [] + for key in b: + if key in a: + if isinstance(a[key], dict) and isinstance(b[key], dict): + deep_merge(a[key], b[key], path + [str(key)]) + elif a[key] == b[key]: + pass # same leaf value + elif isinstance(b[key], type(a[key])): + a[key] = b[key] + elif not isinstance(b[key], type(a[key])): + pass # user has messed with conf files + else: + raise Exception('Conflict at {}'.format('.'.join(path + [str(key)]))) else: - settings[section][key] = config.get(section, key) - return settings + a[key] = b[key] + return a + + default_settings = { + "General": { + "code_refresh": 3, + "show_intro": True, + "show_advanced": False, + "tutorial_advanced": True, + }, + "Appearance": { + "required_colour": "#ba4d0e", + "atleastone_colour": "#d0d02e", + "either_colour": "#ffaa7f", + "style": "", + "palette": "", + }, + "Defaults": { + "installSteps": DefaultsSettings("order", True, "Explicit"), + "optionalFileGroups": DefaultsSettings("order", True, "Explicit"), + "type": DefaultsSettings("name", True, "Optional"), + "defaultType": DefaultsSettings("name", True, "Optional"), + }, + "Load": { + "validate": True, + "validate_ignore": False, + "warnings": True, + "warn_ignore": True, + }, + "Save": { + "validate": True, + "validate_ignore": False, + "warnings": True, + "warn_ignore": True, + }, + "Recent Files": deque(maxlen=5), + } + + try: + with open(join(expanduser("~"), ".fomod", ".designer"), "r") as configfile: + settings_dict = decode(configfile.read()) + deep_merge(default_settings, settings_dict) + return default_settings + except (FileNotFoundError, JSONDecodeError): + return default_settings diff --git a/designer/io.py b/designer/io.py index e1494da..b9b95c3 100644 --- a/designer/io.py +++ b/designer/io.py @@ -16,14 +16,24 @@ from os import listdir, makedirs from os.path import join -from lxml.etree import (PythonElementClassLookup, XMLParser, tostring, fromstring, - Element, SubElement, parse, ParseError, ElementTree) +from lxml.etree import (PythonElementClassLookup, XMLParser, tostring, fromstring, CommentBase, + Element, SubElement, parse, ParseError, ElementTree, CustomElementClassLookup) from .exceptions import MissingFileError, ParserError, TagNotFound -module_parser = XMLParser(remove_comments=True, remove_pis=True, remove_blank_text=True) +module_parser = XMLParser(remove_pis=True, remove_blank_text=True) -class _NodeLookup(PythonElementClassLookup): +class _CommentLookup(CustomElementClassLookup): + def lookup(self, elem_type, doc, namespace, name): + from .nodes import NodeComment + + if elem_type == "comment": + return NodeComment + else: + return None + + +class _NodeClassLookup(PythonElementClassLookup): """ Class that handles the custom lookup for the element factories. """ @@ -86,7 +96,9 @@ def lookup(self, doc, element): elif element.tag == "files": return nodes.NodeConfigFiles elif element.tag == "dependencies": - if element.getparent().tag == "dependencies": + if element.getparent().tag == "dependencies" or \ + element.getparent().tag == "moduleDependencies" or \ + element.getparent().tag == "visible": return nodes.NodeConfigNestedDependencies else: return nodes.NodeConfigDependencies @@ -123,7 +135,7 @@ def lookup(self, doc, element): raise TagNotFound(element) -module_parser.set_element_class_lookup(_NodeLookup()) +module_parser.set_element_class_lookup(_CommentLookup(_NodeClassLookup())) def _check_file(base_path, file_): @@ -193,6 +205,23 @@ def elem_factory(tag, parent): return parsed_list[len(parsed_list) - 1] +def copy_element(element_): + result = elem_factory(element_.tag, element_.getparent()) + element_.write_attribs() + result.text = element_.text + for key in element_.keys(): + result.set(key, element_.get(key)) + result.parse_attribs() + for child in element_: + if isinstance(child, CommentBase): + result.append(type(child)(child.text)) + else: + new_child = copy_element(child) + result.add_child(new_child) + result.load_metadata() + return result + + def import_(package_path): """ Function used to import an existing installer from *package_path*. @@ -216,15 +245,17 @@ def import_(package_path): config_root = parse(config_path, parser=module_parser).getroot() for root in (info_root, config_root): - for element in root.iter(): + for element in root.iter(tag=Element): element.parse_attribs() for elem in element: - element.model_item.appendRow(elem.model_item) - if not _validate_child(elem): - element.remove_child(elem) + if not isinstance(elem, CommentBase): + element.model_item.appendRow(elem.model_item) + if not _validate_child(elem): + element.remove_child(elem) element.write_attribs() + element.load_metadata() except ParseError as e: raise ParserError(str(e)) @@ -284,13 +315,14 @@ def export(info_root, config_root, package_path): config_tree.write(configfile, pretty_print=True) -def sort_elements(info_root, config_root): +def sort_elements(root_element): """ Sorts the xml elements according to their sort_order member. - :param info_root: The root element of the info.xml file. - :param config_root: The root element of the moduleconfig.xml file. + :param root_element: The root element of xml tree. """ - for root in (info_root, config_root): - for parent in root.xpath('//*[./*]'): - parent[:] = sorted(parent, key=lambda x: x.sort_order) + for parent in root_element.xpath('//*[./*]'): + parent[:] = sorted( + parent, + key=lambda x: x.sort_order + "." + x.user_sort_order if not isinstance(x, CommentBase) else "0" + ) diff --git a/designer/nodes.py b/designer/nodes.py index 8d160c3..d673857 100644 --- a/designer/nodes.py +++ b/designer/nodes.py @@ -15,13 +15,22 @@ # limitations under the License. from os import sep +from collections import OrderedDict from PyQt5.QtGui import QStandardItem +from PyQt5.QtCore import Qt from lxml import etree -from .wizards import WizardFiles -from .props import PropertyCombo, PropertyInt, PropertyText, PropertyFile, PropertyFolder, PropertyColour +from jsonpickle import encode, decode, set_encoder_options +from json import JSONDecodeError +from .wizards import WizardFiles, WizardDepend +from .props import PropertyCombo, PropertyInt, PropertyText, PropertyFile, PropertyFolder, PropertyColour, \ + PropertyFlagLabel, PropertyFlagValue, PropertyHTML from .exceptions import BaseInstanceException +class NodeComment(etree.CommentBase): + pass + + class _NodeBase(etree.ElementBase): """ The base class for all nodes. Should never be instantiated directly. @@ -31,26 +40,52 @@ def _init(self): raise BaseInstanceException(self) super()._init() - def init(self, name, tag, allowed_instances, sort_order=0, allow_text=False, allowed_children=None, properties=None, - wizard=None): + def init( + self, + name, + tag, + allowed_instances, + sort_order="0", + allowed_children=None, + properties=None, + wizard=None, + required_children=None, + either_children_group=None, + at_least_one_children_group=None, + name_editable=False, + ): if not properties: - properties = {} + properties = OrderedDict() if not allowed_children: allowed_children = () + if not required_children: + required_children = () + if not either_children_group: + either_children_group = () + if not at_least_one_children_group: + at_least_one_children_group = () self.name = name self.tag = tag self.sort_order = sort_order self.properties = properties self.allowed_children = allowed_children - self.allow_text = allow_text + self.required_children = required_children + self.either_children_group = either_children_group + self.at_least_one_children_group = at_least_one_children_group self.allowed_instances = allowed_instances self.wizard = wizard + self.metadata = {} + self.user_sort_order = "0" self.model_item = NodeStandardItem(self) self.model_item.setText(self.name) - self.model_item.setEditable(False) + if allowed_instances > 1 or not allowed_instances: + self.model_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsEnabled | Qt.ItemIsEditable) + else: + self.model_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsDropEnabled | Qt.ItemIsEnabled | Qt.ItemIsEditable) + self.model_item.setEditable(name_editable) def can_add_child(self, child): """ @@ -80,6 +115,7 @@ def add_child(self, child): self.append(child) self.model_item.appendRow(child.model_item) child.write_attribs() + child.load_metadata() def remove_child(self, child): """ @@ -96,6 +132,9 @@ def parse_attribs(self): Reads the values from the BaseElement's attrib dictionary into the node's properties. """ for key in self.properties: + if key == "": + self.properties[key].set_value(self.text) + continue if key not in self.attrib.keys(): continue self.properties[key].set_value(self.attrib[key]) @@ -107,6 +146,9 @@ def write_attribs(self): """ self.attrib.clear() for key in self.properties: + if key == "": + self.text = self.properties[key].value + continue self.set(key, str(self.properties[key].value)) def update_item_name(self): @@ -119,25 +161,61 @@ def update_item_name(self): if "name" in self.properties: if not self.properties["name"].value: self.model_item.setText(self.name) - return + return self.name self.model_item.setText(self.properties["name"].value) + return self.properties["name"].value elif "source" in self.properties: if not self.properties["source"].value: self.model_item.setText(self.name) - return + return self.name split_name = self.properties["source"].value.split(sep) self.model_item.setText(split_name[len(split_name) - 1]) + return split_name[len(split_name) - 1] else: self.model_item.setText(self.name) + return self.name - def set_text(self, text): + def load_metadata(self): """ - Method used to set the node's text, if allowed. - - :param text: The text to set. + Loads this node's metadata which is stored in a child comment encoded in json. + """ + for child in self: + if type(child) is NodeComment: + if child.text.split()[0] == "": + try: + self.metadata = decode(child.text.split(maxsplit=1)[1]) + except JSONDecodeError: + continue + + self.model_item.setText(self.metadata.get("name", self.update_item_name())) + self.user_sort_order = self.metadata.get("user_sort", "0".zfill(7)) + + def save_metadata(self): + """ + Saves this node's metadata. """ - if self.allow_text: - self.text = text + if self.model_item.text() != self.name: + self.metadata["name"] = self.model_item.text() + else: + self.metadata.pop("name", None) + if self.user_sort_order: + self.metadata["user_sort"] = self.user_sort_order + else: + self.metadata.pop("user_sort", None) + + if not self.allowed_children and "" not in self.properties.keys(): + return + else: + meta_comment = None + set_encoder_options("json", separators=(',', ':')) + for child in self: + if type(child) is NodeComment and self.metadata: + if child.text.split()[0] == "": + meta_comment = child + child.text = " " + encode(self.metadata) + + if meta_comment is None: + self.append(NodeComment(" " + encode(self.metadata))) class NodeStandardItem(QStandardItem): @@ -146,6 +224,14 @@ def __init__(self, node): self.xml_node = node super().__init__() + def __lt__(self, other): + self_sort = self.xml_node.sort_order + "." + self.xml_node.user_sort_order + other_sort = other.xml_node.sort_order + "." + other.xml_node.user_sort_order + if self_sort < other_sort: + return True + else: + return False + class NodeInfoRoot(_NodeBase): """ @@ -154,9 +240,21 @@ class NodeInfoRoot(_NodeBase): tag = "fomod" def _init(self): - allowed_children = (NodeInfoName, NodeInfoAuthor, NodeInfoDescription, - NodeInfoID, NodeInfoGroup, NodeInfoVersion, NodeInfoWebsite) - self.init("Info", type(self).tag, 1, allow_text=False, allowed_children=allowed_children) + allowed_children = ( + NodeInfoName, + NodeInfoAuthor, + NodeInfoDescription, + NodeInfoID, + NodeInfoGroup, + NodeInfoVersion, + NodeInfoWebsite + ) + self.init( + "Info", + type(self).tag, + 1, + allowed_children=allowed_children + ) super()._init() @@ -167,7 +265,15 @@ class NodeInfoName(_NodeBase): tag = "Name" def _init(self): - self.init("Name", type(self).tag, 1, allow_text=True) + properties = OrderedDict([ + ("", PropertyText("Name")) + ]) + self.init( + "Name", + type(self).tag, + 1, + properties=properties + ) super()._init() @@ -178,7 +284,15 @@ class NodeInfoAuthor(_NodeBase): tag = "Author" def _init(self): - self.init("Author", type(self).tag, 1, allow_text=True) + properties = OrderedDict([ + ("", PropertyText("Author")) + ]) + self.init( + "Author", + type(self).tag, + 1, + properties=properties + ) super()._init() @@ -189,7 +303,15 @@ class NodeInfoVersion(_NodeBase): tag = "Version" def _init(self): - self.init("Version", type(self).tag, 1, allow_text=True) + properties = OrderedDict([ + ("", PropertyText("Version")) + ]) + self.init( + "Version", + type(self).tag, + 1, + properties=properties + ) super()._init() @@ -200,7 +322,15 @@ class NodeInfoID(_NodeBase): tag = "Id" def _init(self): - self.init("ID", type(self).tag, 1, allow_text=True) + properties = OrderedDict([ + ("", PropertyText("ID")) + ]) + self.init( + "ID", + type(self).tag, + 1, + properties=properties + ) super()._init() @@ -211,7 +341,15 @@ class NodeInfoWebsite(_NodeBase): tag = "Website" def _init(self): - self.init("Website", type(self).tag, 1, allow_text=True) + properties = OrderedDict([ + ("", PropertyText("Website")) + ]) + self.init( + "Website", + type(self).tag, + 1, + properties=properties + ) super()._init() @@ -222,7 +360,15 @@ class NodeInfoDescription(_NodeBase): tag = "Description" def _init(self): - self.init("Description", type(self).tag, 1, allow_text=True) + properties = OrderedDict([ + ("", PropertyText("Description")) + ]) + self.init( + "Description", + type(self).tag, + 1, + properties=properties + ) super()._init() @@ -233,8 +379,15 @@ class NodeInfoGroup(_NodeBase): tag = "Groups" def _init(self): - allowed_child = (NodeInfoElement,) - self.init("Categories Group", type(self).tag, 1, allowed_children=allowed_child) + allowed_child = ( + NodeInfoElement, + ) + self.init( + "Categories Group", + type(self).tag, + 1, + allowed_children=allowed_child + ) super()._init() @@ -245,7 +398,15 @@ class NodeInfoElement(_NodeBase): tag = "element" def _init(self): - self.init("Category", type(self).tag, 0, allow_text=True) + properties = OrderedDict([ + ("", PropertyText("Category")) + ]) + self.init( + "Category", + type(self).tag, + 0, + properties=properties + ) super()._init() @@ -256,11 +417,40 @@ class NodeConfigRoot(_NodeBase): tag = "config" def _init(self): - allowed_children = (NodeConfigModName, NodeConfigModImage, NodeConfigModDepend, - NodeConfigInstallSteps, NodeConfigReqFiles, NodeConfigCondInstall) - properties = {"{http://www.w3.org/2001/XMLSchema-instance}noNamespaceSchemaLocation": - PropertyText("xsi", "http://qconsulting.ca/fo3/ModConfig5.0.xsd", False)} - self.init("Config", type(self).tag, 1, allowed_children=allowed_children, properties=properties) + allowed_children = ( + NodeConfigModName, + NodeConfigModImage, + NodeConfigModDepend, + NodeConfigInstallSteps, + NodeConfigReqFiles, + NodeConfigCondInstall + ) + required = ( + NodeConfigModName, + ) + at_least_one = ( + NodeConfigModDepend, + NodeConfigInstallSteps, + NodeConfigReqFiles, + NodeConfigCondInstall + ) + properties = OrderedDict( + [ + ("{http://www.w3.org/2001/XMLSchema-instance}noNamespaceSchemaLocation", + PropertyText( + "xsi", "http://qconsulting.ca/fo3/ModConfig5.0.xsd", False + )) + ] + ) + self.init( + "Config", + type(self).tag, + 1, + allowed_children=allowed_children, + properties=properties, + required_children=required, + at_least_one_children_group=at_least_one + ) super()._init() @@ -271,9 +461,18 @@ class NodeConfigModName(_NodeBase): tag = "moduleName" def _init(self): - properties = {"position": PropertyCombo("Position", ("Left", "Right", "RightOfImage")), - "colour": PropertyColour("Colour", "000000")} - self.init("Name", type(self).tag, 1, allow_text=True, properties=properties, sort_order=1) + properties = OrderedDict([ + ("", PropertyText("Name")), + ("position", PropertyCombo("Position", ("Left", "Right", "RightOfImage"))), + ("colour", PropertyColour("Colour", "000000")) + ]) + self.init( + "Name", + type(self).tag, + 1, + properties=properties, + sort_order="1" + ) super()._init() @@ -284,10 +483,19 @@ class NodeConfigModImage(_NodeBase): tag = "moduleImage" def _init(self): - properties = {"path": PropertyFile("Path"), "showImage": PropertyCombo("Show Image", ("true", "false")), - "showFade": PropertyCombo("Show Fade", ("true", "false")), - "height": PropertyInt("Height", -1, 9999, -1)} - self.init("Image", "moduleImage", 1, properties=properties, sort_order=2) + properties = OrderedDict([ + ("path", PropertyFile("Path")), + ("showImage", PropertyCombo("Show Image", ("true", "false"))), + ("showFade", PropertyCombo("Show Fade", ("true", "false"))), + ("height", PropertyInt("Height", -1, 9999, -1)) + ]) + self.init( + "Image", + "moduleImage", + 1, + properties=properties, + sort_order="2" + ) super()._init() @@ -298,10 +506,24 @@ class NodeConfigModDepend(_NodeBase): tag = "moduleDependencies" def _init(self): - allowed_children = (NodeConfigDependFile, NodeConfigDependFlag, NodeConfigDependGame) - properties = {"operator": PropertyCombo("Type", ["And", "Or"])} - self.init("Mod Dependencies", type(self).tag, 1, allowed_children=allowed_children, - properties=properties, sort_order=3) + allowed_children = ( + NodeConfigDependFile, + NodeConfigDependFlag, + NodeConfigDependGame, + NodeConfigNestedDependencies + ) + properties = OrderedDict([ + ("operator", PropertyCombo("Type", ["And", "Or"])) + ]) + self.init( + "Mod Dependencies", + type(self).tag, + 1, + allowed_children=allowed_children, + properties=properties, + sort_order="3", + wizard=WizardDepend + ) super()._init() @@ -312,9 +534,18 @@ class NodeConfigReqFiles(_NodeBase): tag = "requiredInstallFiles" def _init(self): - allowed_children = (NodeConfigFile, NodeConfigFolder) - self.init("Mod Requirements", type(self).tag, 1, allowed_children=allowed_children, - sort_order=4, wizard=WizardFiles) + allowed_children = ( + NodeConfigFile, + NodeConfigFolder + ) + self.init( + "Mod Requirements", + type(self).tag, + 1, + allowed_children=allowed_children, + sort_order="4", + wizard=WizardFiles + ) super()._init() @@ -325,10 +556,24 @@ class NodeConfigInstallSteps(_NodeBase): tag = "installSteps" def _init(self): - allowed_children = (NodeConfigInstallStep,) - properties = {"order": PropertyCombo("Order", ["Ascending", "Descending", "Explicit"])} - self.init("Installation Steps", type(self).tag, 1, allowed_children=allowed_children, - properties=properties, sort_order=5) + allowed_children = ( + NodeConfigInstallStep, + ) + required = ( + NodeConfigInstallStep, + ) + properties = OrderedDict([ + ("order", PropertyCombo("Order", ["Ascending", "Descending", "Explicit"])) + ]) + self.init( + "Installation Steps", + type(self).tag, + 1, + allowed_children=allowed_children, + properties=properties, + sort_order="5", + required_children=required + ) super()._init() @@ -339,8 +584,20 @@ class NodeConfigCondInstall(_NodeBase): tag = "conditionalFileInstalls" def _init(self): - allowed_children = (NodeConfigPatterns,) - self.init("Conditional Installation", type(self).tag, 1, allowed_children=allowed_children, sort_order=6) + allowed_children = ( + NodeConfigPatterns, + ) + required = ( + NodeConfigPatterns, + ) + self.init( + "Conditional Installation", + type(self).tag, + 1, + allowed_children=allowed_children, + sort_order="6", + required_children=required + ) super()._init() @@ -351,9 +608,16 @@ class NodeConfigDependFile(_NodeBase): tag = "fileDependency" def _init(self): - properties = {"file": PropertyText("File"), - "state": PropertyCombo("State", ("Active", "Inactive", "Missing"))} - self.init("File Dependency", type(self).tag, 0, properties=properties) + properties = OrderedDict([ + ("file", PropertyText("File")), + ("state", PropertyCombo("State", ("Active", "Inactive", "Missing"))) + ]) + self.init( + "File Dependency", + type(self).tag, + 0, + properties=properties + ) super()._init() @@ -364,8 +628,16 @@ class NodeConfigDependFlag(_NodeBase): tag = "flagDependency" def _init(self): - properties = {"flag": PropertyText("Flag"), "value": PropertyText("Value")} - self.init("Flag Dependency", type(self).tag, 0, properties=properties) + properties = OrderedDict([ + ("flag", PropertyFlagLabel("Label")), + ("value", PropertyFlagValue("Value")) + ]) + self.init( + "Flag Dependency", + type(self).tag, + 0, + properties=properties + ) super()._init() @@ -376,8 +648,15 @@ class NodeConfigDependGame(_NodeBase): tag = "gameDependency" def _init(self): - properties = {"version": PropertyText("Version")} - self.init("Game Dependency", "gameDependency", 1, properties=properties) + properties = OrderedDict([ + ("version", PropertyText("Version")) + ]) + self.init( + "Game Dependency", + "gameDependency", + 1, + properties=properties + ) super()._init() @@ -388,12 +667,19 @@ class NodeConfigFile(_NodeBase): tag = "file" def _init(self): - properties = {"source": PropertyFile("Source"), - "destination": PropertyText("Destination"), - "priority": PropertyInt("Priority", 0, 99, 0), - "alwaysInstall": PropertyCombo("Always Install", ("false", "true")), - "installIfUsable": PropertyCombo("Install If Usable", ("false", "true"))} - self.init("File", type(self).tag, 0, properties=properties) + properties = OrderedDict([ + ("source", PropertyFile("Source")), + ("destination", PropertyText("Destination")), + ("priority", PropertyInt("Priority", 0, 99, 0)), + ("alwaysInstall", PropertyCombo("Always Install", ("false", "true"))), + ("installIfUsable", PropertyCombo("Install If Usable", ("false", "true"))) + ]) + self.init( + "File", + type(self).tag, + 0, + properties=properties + ) super()._init() @@ -404,12 +690,19 @@ class NodeConfigFolder(_NodeBase): tag = "folder" def _init(self): - properties = {"source": PropertyFolder("Source"), - "destination": PropertyText("Destination"), - "priority": PropertyInt("Priority", 0, 99, 0), - "alwaysInstall": PropertyCombo("Always Install", ("false", "true")), - "installIfUsable": PropertyCombo("Install If Usable", ("false", "true"))} - self.init("Folder", type(self).tag, 0, properties=properties) + properties = OrderedDict([ + ("source", PropertyFolder("Source")), + ("destination", PropertyText("Destination")), + ("priority", PropertyInt("Priority", 0, 99, 0)), + ("alwaysInstall", PropertyCombo("Always Install", ("false", "true"))), + ("installIfUsable", PropertyCombo("Install If Usable", ("false", "true"))) + ]) + self.init( + "Folder", + type(self).tag, + 0, + properties=properties + ) super()._init() @@ -420,8 +713,19 @@ class NodeConfigPatterns(_NodeBase): tag = "patterns" def _init(self): - allowed_children = (NodeConfigPattern,) - self.init("Patterns", type(self).tag, 1, allowed_children=allowed_children) + allowed_children = ( + NodeConfigPattern, + ) + required = ( + NodeConfigPattern, + ) + self.init( + "Patterns", + type(self).tag, + 1, + allowed_children=allowed_children, + required_children=required + ) super()._init() @@ -432,8 +736,22 @@ class NodeConfigPattern(_NodeBase): tag = "pattern" def _init(self): - allowed_children = (NodeConfigFiles, NodeConfigDependencies) - self.init("Pattern", type(self).tag, 0, allowed_children=allowed_children) + allowed_children = ( + NodeConfigFiles, + NodeConfigDependencies + ) + required = ( + NodeConfigFiles, + NodeConfigDependencies + ) + self.init( + "Pattern", + type(self).tag, + 0, + allowed_children=allowed_children, + required_children=required, + name_editable=True + ) super()._init() @@ -444,8 +762,18 @@ class NodeConfigFiles(_NodeBase): tag = "files" def _init(self): - allowed_children = (NodeConfigFile, NodeConfigFolder) - self.init("Files", type(self).tag, 1, allowed_children=allowed_children, sort_order=3, wizard=WizardFiles) + allowed_children = ( + NodeConfigFile, + NodeConfigFolder + ) + self.init( + "Files", + type(self).tag, + 1, + allowed_children=allowed_children, + sort_order="3", + wizard=WizardFiles + ) super()._init() @@ -456,11 +784,24 @@ class NodeConfigDependencies(_NodeBase): tag = "dependencies" def _init(self): - allowed_children = (NodeConfigDependFile, NodeConfigDependFlag, - NodeConfigDependGame, NodeConfigNestedDependencies) - properties = {"operator": PropertyCombo("Type", ["And", "Or"])} - self.init("Dependencies", type(self).tag, 1, allowed_children=allowed_children, - properties=properties, sort_order=1) + allowed_children = ( + NodeConfigDependFile, + NodeConfigDependFlag, + NodeConfigDependGame, + NodeConfigNestedDependencies + ) + properties = OrderedDict([ + ("operator", PropertyCombo("Type", ["And", "Or"])) + ]) + self.init( + "Dependencies", + type(self).tag, + 1, + allowed_children=allowed_children, + properties=properties, + sort_order="1", + wizard=WizardDepend + ) super()._init() @@ -471,10 +812,23 @@ class NodeConfigNestedDependencies(_NodeBase): tag = "dependencies" def _init(self): - allowed_children = (NodeConfigDependFile, NodeConfigDependFlag, - NodeConfigDependGame, NodeConfigNestedDependencies) - properties = {"operator": PropertyCombo("Type", ["And", "Or"])} - self.init("Dependencies", type(self).tag, 0, allowed_children=allowed_children, properties=properties) + allowed_children = ( + NodeConfigDependFile, + NodeConfigDependFlag, + NodeConfigDependGame, + NodeConfigNestedDependencies + ) + properties = OrderedDict([ + ("operator", PropertyCombo("Type", ["And", "Or"])) + ]) + self.init( + "Dependencies", + type(self).tag, + 0, + allowed_children=allowed_children, + properties=properties, + wizard=WizardDepend + ) super()._init() @@ -485,9 +839,24 @@ class NodeConfigInstallStep(_NodeBase): tag = "installStep" def _init(self): - allowed_children = (NodeConfigVisible, NodeConfigOptGroups) - properties = {"name": PropertyText("Name")} - self.init("Install Step", type(self).tag, 0, allowed_children=allowed_children, properties=properties) + allowed_children = ( + NodeConfigVisible, + NodeConfigOptGroups + ) + required = ( + NodeConfigOptGroups, + ) + properties = OrderedDict([ + ("name", PropertyText("Name")) + ]) + self.init( + "Install Step", + type(self).tag, + 0, + allowed_children=allowed_children, + properties=properties, + required_children=required + ) super()._init() @@ -498,8 +867,24 @@ class NodeConfigVisible(_NodeBase): tag = "visible" def _init(self): - allowed_children = (NodeConfigDependFile, NodeConfigDependFlag, NodeConfigDependGame, NodeConfigDependencies) - self.init("Visibility", type(self).tag, 1, allowed_children=allowed_children, sort_order=1) + allowed_children = ( + NodeConfigDependFile, + NodeConfigDependFlag, + NodeConfigDependGame, + NodeConfigNestedDependencies + ) + properties = OrderedDict([ + ("operator", PropertyCombo("Type", ["And", "Or"])) + ]) + self.init( + "Visibility", + type(self).tag, + 1, + allowed_children=allowed_children, + sort_order="1", + wizard=WizardDepend, + properties=properties + ) super()._init() @@ -510,10 +895,24 @@ class NodeConfigOptGroups(_NodeBase): tag = "optionalFileGroups" def _init(self): - allowed_children = (NodeConfigGroup,) - properties = {"order": PropertyCombo("Order", ["Ascending", "Descending", "Explicit"])} - self.init("Option Group", type(self).tag, 0, allowed_children=allowed_children, - properties=properties, sort_order=2) + allowed_children = ( + NodeConfigGroup, + ) + required = ( + NodeConfigGroup, + ) + properties = OrderedDict([ + ("order", PropertyCombo("Order", ["Ascending", "Descending", "Explicit"])) + ]) + self.init( + "Option Group", + type(self).tag, + 1, + allowed_children=allowed_children, + properties=properties, + sort_order="2", + required_children=required + ) super()._init() @@ -524,11 +923,30 @@ class NodeConfigGroup(_NodeBase): tag = "group" def _init(self): - allowed_children = (NodeConfigPlugins,) - properties = {"name": PropertyText("Name"), - "type": PropertyCombo("Type", ["SelectAny", "SelectAtMostOne", - "SelectExactlyOne", "SelectAll", "SelectAtLeastOne"])} - self.init("Group", type(self).tag, 0, allowed_children=allowed_children, properties=properties) + allowed_children = ( + NodeConfigPlugins, + ) + required = ( + NodeConfigPlugins, + ) + properties = OrderedDict([ + ("name", PropertyText("Name")), + ("type", PropertyCombo("Type", [ + "SelectAny", + "SelectAtMostOne", + "SelectExactlyOne", + "SelectAll", + "SelectAtLeastOne" + ])) + ]) + self.init( + "Group", + type(self).tag, + 0, + allowed_children=allowed_children, + properties=properties, + required_children=required + ) super()._init() @@ -539,9 +957,23 @@ class NodeConfigPlugins(_NodeBase): tag = "plugins" def _init(self): - allowed_children = (NodeConfigPlugin,) - properties = {"order": PropertyCombo("Order", ["Ascending", "Descending", "Explicit"])} - self.init("Plugins", type(self).tag, 0, allowed_children=allowed_children, properties=properties) + allowed_children = ( + NodeConfigPlugin, + ) + required = ( + NodeConfigPlugin, + ) + properties = OrderedDict([ + ("order", PropertyCombo("Order", ["Ascending", "Descending", "Explicit"])) + ]) + self.init( + "Plugins", + type(self).tag, + 1, + allowed_children=allowed_children, + properties=properties, + required_children=required + ) super()._init() @@ -552,10 +984,32 @@ class NodeConfigPlugin(_NodeBase): tag = "plugin" def _init(self): - allowed_children = (NodeConfigPluginDescription, NodeConfigImage, NodeConfigFiles, - NodeConfigConditionFlags, NodeConfigTypeDesc) - properties = {"name": PropertyText("Name")} - self.init("Plugin", type(self).tag, 0, allowed_children=allowed_children, properties=properties) + allowed_children = ( + NodeConfigPluginDescription, + NodeConfigImage, + NodeConfigFiles, + NodeConfigConditionFlags, + NodeConfigTypeDesc + ) + required = ( + NodeConfigPluginDescription, + ) + at_least_one_child = ( + NodeConfigFiles, + NodeConfigConditionFlags + ) + properties = OrderedDict([ + ("name", PropertyText("Name")) + ]) + self.init( + "Plugin", + type(self).tag, + 0, + allowed_children=allowed_children, + properties=properties, + at_least_one_children_group=at_least_one_child, + required_children=required + ) super()._init() @@ -566,7 +1020,16 @@ class NodeConfigPluginDescription(_NodeBase): tag = "description" def _init(self): - self.init("Description", type(self).tag, 1, allow_text=True, sort_order=1) + properties = OrderedDict([ + ("", PropertyHTML("Description")) + ]) + self.init( + "Description", + type(self).tag, + 1, + properties=properties, + sort_order="1" + ) super()._init() @@ -577,8 +1040,16 @@ class NodeConfigImage(_NodeBase): tag = "image" def _init(self): - properties = {"path": PropertyFile("Path")} - self.init("Image", type(self).tag, 1, properties=properties, sort_order=2) + properties = OrderedDict([ + ("path", PropertyFile("Path")) + ]) + self.init( + "Image", + type(self).tag, + 1, + properties=properties, + sort_order="2" + ) super()._init() @@ -589,8 +1060,20 @@ class NodeConfigConditionFlags(_NodeBase): tag = "conditionFlags" def _init(self): - allowed_children = (NodeConfigFlag,) - self.init("Flags", type(self).tag, 1, allowed_children=allowed_children, sort_order=3) + allowed_children = ( + NodeConfigFlag, + ) + required = ( + NodeConfigFlag, + ) + self.init( + "Flags", + type(self).tag, + 1, + allowed_children=allowed_children, + sort_order="3", + required_children=required + ) super()._init() @@ -601,8 +1084,22 @@ class NodeConfigTypeDesc(_NodeBase): tag = "typeDescriptor" def _init(self): - allowed_children = (NodeConfigDependencyType, NodeConfigType) - self.init("Type Descriptor", type(self).tag, 1, allowed_children=allowed_children, sort_order=4) + allowed_children = ( + NodeConfigDependencyType, + NodeConfigType + ) + either_children = ( + NodeConfigDependencyType, + NodeConfigType + ) + self.init( + "Type Descriptor", + type(self).tag, + 1, + allowed_children=allowed_children, + sort_order="4", + either_children_group=either_children + ) super()._init() def can_add_child(self, child): @@ -619,8 +1116,16 @@ class NodeConfigFlag(_NodeBase): tag = "flag" def _init(self): - properties = {"name": PropertyText("Name")} - self.init("Flag", type(self).tag, 0, properties=properties, allow_text=True) + properties = OrderedDict([ + ("name", PropertyFlagLabel("Label")), + ("", PropertyText("Value")), + ]) + self.init( + "Flag", + type(self).tag, + 0, + properties=properties, + ) super()._init() @@ -631,8 +1136,21 @@ class NodeConfigDependencyType(_NodeBase): tag = "dependencyType" def _init(self): - allowed_children = (NodeConfigInstallPatterns, NodeConfigDefaultType) - self.init("Dependency Type", type(self).tag, 1, allowed_children=allowed_children) + allowed_children = ( + NodeConfigInstallPatterns, + NodeConfigDefaultType + ) + required = ( + NodeConfigInstallPatterns, + NodeConfigDefaultType + ) + self.init( + "Dependency Type", + type(self).tag, + 1, + allowed_children=allowed_children, + required_children=required + ) super()._init() @@ -643,9 +1161,16 @@ class NodeConfigDefaultType(_NodeBase): tag = "defaultType" def _init(self): - properties = {"name": PropertyCombo("Name", - ["Required", "Recommended", "Optional", "CouldBeUsable", "NotUsable"])} - self.init("Default Type", type(self).tag, 1, properties=properties, sort_order=1) + properties = OrderedDict([ + ("name", PropertyCombo("Type", ["Required", "Recommended", "Optional", "CouldBeUsable", "NotUsable"])) + ]) + self.init( + "Default Type", + type(self).tag, + 1, + properties=properties, + sort_order="1" + ) super()._init() @@ -656,9 +1181,16 @@ class NodeConfigType(_NodeBase): tag = "type" def _init(self): - properties = {"name": PropertyCombo("Name", - ["Required", "Recommended", "Optional", "CouldBeUsable", "NotUsable"])} - self.init("Type", type(self).tag, 1, properties=properties, sort_order=2) + properties = OrderedDict([ + ("name", PropertyCombo("Type", ["Required", "Recommended", "Optional", "CouldBeUsable", "NotUsable"])) + ]) + self.init( + "Type", + type(self).tag, + 1, + properties=properties, + sort_order="2" + ) super()._init() @@ -669,8 +1201,20 @@ class NodeConfigInstallPatterns(_NodeBase): tag = "patterns" def _init(self): - allowed_children = (NodeConfigInstallPattern,) - self.init("Patterns", type(self).tag, 1, allowed_children=allowed_children, sort_order=2) + allowed_children = ( + NodeConfigInstallPattern, + ) + required = ( + NodeConfigInstallPattern, + ) + self.init( + "Patterns", + type(self).tag, + 1, + allowed_children=allowed_children, + sort_order="2", + required_children=required + ) super()._init() @@ -681,6 +1225,20 @@ class NodeConfigInstallPattern(_NodeBase): tag = "pattern" def _init(self): - allowed_children = (NodeConfigType, NodeConfigDependencies) - self.init("Pattern", type(self).tag, 0, allowed_children=allowed_children) + allowed_children = ( + NodeConfigType, + NodeConfigDependencies + ) + required = ( + NodeConfigType, + NodeConfigDependencies + ) + self.init( + "Pattern", + type(self).tag, + 0, + allowed_children=allowed_children, + required_children=required, + name_editable=True + ) super()._init() diff --git a/designer/previews.py b/designer/previews.py index daec769..690bdfd 100644 --- a/designer/previews.py +++ b/designer/previews.py @@ -14,13 +14,21 @@ # See the License for the specific language governing permissions and # limitations under the License. +from os.path import join, sep, normpath, isfile, isdir +from os import listdir from queue import Queue -from PyQt5.QtCore import QThread +from PyQt5.QtCore import QThread, Qt, pyqtSignal, QEvent +from PyQt5.QtWidgets import QWidget, QLabel, QGroupBox, QVBoxLayout, QRadioButton, QCheckBox, QHeaderView, QMenu, \ + QAction +from PyQt5.QtGui import QStandardItemModel, QStandardItem, QPixmap, QIcon from lxml.etree import XML, tostring from lxml.objectify import deannotate from pygments import highlight from pygments.formatters.html import HtmlFormatter from pygments.lexers.html import XmlLexer +from . import cur_folder +from .io import sort_elements +from .ui_templates import preview_mo class PreviewDispatcherThread(QThread): @@ -32,30 +40,29 @@ class PreviewDispatcherThread(QThread): :param nmm_signal: The signal to pass to the NMM preview worker, updates the NMM preview. :param code_signal: The signal to pass to the code preview worker, updates the code preview. """ - def __init__(self, queue, mo_signal, nmm_signal, code_signal): + def __init__(self, queue, code_signal, **kwargs): super().__init__() self.queue = queue - self.mo_queue = Queue() - self.nmm_queue = Queue() + self.gui_queue = Queue() self.code_queue = Queue() self.code_thread = PreviewCodeWorker(self.code_queue, code_signal) self.code_thread.start() + self.gui_thread = PreviewGuiWorker(self.gui_queue, **kwargs) + self.gui_thread.start() def run(self): while True: # wait for next element element = self.queue.get() - if element is None: # needed because connecting the signal to the queue adds a NoneType, no idea why. - continue - # turn the element into "normal" lxml elements for easier processing. - element.write_attribs() - element = XML(tostring(element)) + if element is not None: + element.write_attribs() + element.load_metadata() + sort_elements(element) # dispatch to every queue - self.mo_queue.put(element) - self.nmm_queue.put(element) + self.gui_queue.put(element) self.code_queue.put(element) @@ -77,7 +84,576 @@ def run(self): # wait for next element element = self.queue.get() + if element is None: + self.return_signal.emit("") + continue + + element = XML(tostring(element)) + # process the element deannotate(element, cleanup_namespaces=True) code = tostring(element, encoding="Unicode", pretty_print=True, xml_declaration=False) - self.return_signal.emit(highlight(code, XmlLexer(), HtmlFormatter(noclasses=True, style="autumn", linenos="table"))) + self.return_signal.emit(highlight(code, XmlLexer(), HtmlFormatter( + noclasses=True, style="autumn", linenos="table" + ))) + + +class PreviewGuiWorker(QThread): + class InstallStepData(object): + def __init__(self, name): + self.name = name + self.group_list = [] + + def set_group_list(self, group_list): + self.group_list = group_list + + def sort_ascending(self): + self.group_list = sorted(self.group_list, key=lambda x: x.name) + + def sort_descending(self): + self.group_list = sorted(self.group_list, reverse=True, key=lambda x: x.name) + + class GroupData(object): + def __init__(self, name, group_type): + self.name = name + self.type = group_type + self.plugin_list = [] + + def set_plugin_list(self, plugin_list): + self.plugin_list = plugin_list + + def sort_ascending(self): + self.plugin_list = sorted(self.plugin_list, key=lambda x: x.name) + + def sort_descending(self): + self.plugin_list = sorted(self.plugin_list, reverse=True, key=lambda x: x.name) + + class PluginData(object): + def __init__(self, name, description, image_path, file_list, folder_list, flag_list, plugin_type): + self.name = name + self.description = description + self.image_path = image_path + self.file_list = file_list + self.folder_list = folder_list + self.flag_list = flag_list + self.type = plugin_type + + class FileData(object): + def __init__(self, abs_source, rel_source, destination, priority, always_install, install_usable): + self.abs_source = abs_source + self.rel_source = rel_source + self.destination = destination + self.priority = priority + self.always_install = always_install + self.install_usable = install_usable + + class FolderData(FileData): + pass + + class FlagData(object): + def __init__(self, label, value): + self.label = label + self.value = value + + def __init__(self, queue, **kwargs): + super().__init__() + self.queue = queue + self.kwargs = kwargs + + def run(self): + while True: + # wait for next element + element = self.queue.get() + + if element is None: + self.kwargs["gui_worker"].invalid_node_signal.emit() + continue + elif element.tag == "installStep": + pass + elif [elem for elem in element.iterancestors() if elem.tag == "installStep"]: + element = [elem for elem in element.iterancestors() if elem.tag == "installStep"][0] + elif not [elem for elem in self.kwargs["config_root"]().iter() if elem.tag == "installStep"]: + self.kwargs["gui_worker"].missing_node_signal.emit() + continue + else: + self.kwargs["gui_worker"].invalid_node_signal.emit() + continue + + self.kwargs["gui_worker"].clear_tab_signal.emit() + self.kwargs["gui_worker"].clear_ui_signal.emit() + info_name = self.kwargs["info_root"]().find("Name").text + info_author = self.kwargs["info_root"]().find("Author").text + info_version = self.kwargs["info_root"]().find("Version").text + info_website = self.kwargs["info_root"]().find("Website").text + self.kwargs["gui_worker"].set_labels_signal.emit(info_name, info_author, info_version, info_website) + + step_data = self.InstallStepData(element.get("name")) + opt_group_elem = element.find("optionalFileGroups") + if opt_group_elem is not None: + group_data_list = [] + + for group_elem in opt_group_elem.findall("group"): + group_data = self.GroupData(group_elem.get("name"), group_elem.get("type")) + + plugins_elem = group_elem.find("plugins") + if plugins_elem is not None: + plugin_data_list = [] + + for plugin_elem in plugins_elem.findall("plugin"): + name_ = plugin_elem.get("name") + description_ = plugin_elem.find("description").text \ + if plugin_elem.find("description") is not None else "" + image_ = plugin_elem.find("image").get("path") \ + if plugin_elem.find("image") is not None else "" + if image_: + # normalize path, for some reason normpath wasn't working + image_ = join(self.kwargs["package_path"](), image_).replace("\\", "/") + image_ = image_.replace("/", sep) + + file_data_list = [] + for file_elem in plugin_elem.findall("files/file"): + file_data_list.append( + self.FileData( + normpath(join( + self.kwargs["package_path"](), + file_elem.get("source").replace("\\", "/") + )), + file_elem.get("source"), + normpath(file_elem.get("destination").replace("\\", "/")), + file_elem.get("priority"), + file_elem.get("alwaysInstall"), + file_elem.get("installIfUsable") + ) + ) + + folder_data_list = [] + for folder_elem in plugin_elem.findall("files/folder"): + folder_data_list.append( + self.FolderData( + normpath(join( + self.kwargs["package_path"](), + folder_elem.get("source").replace("\\", "/") + )), + folder_elem.get("source"), + normpath(folder_elem.get("destination").replace("\\", "/")), + folder_elem.get("priority"), + folder_elem.get("alwaysInstall"), + folder_elem.get("installIfUsable") + ) + ) + + flag_data_list = [] + for flag_elem in plugin_elem.findall("conditionFlags/flag"): + flag_data_list.append( + self.FlagData( + flag_elem.get("name"), + flag_elem.text + ) + ) + + type_elem = plugin_elem.find("typeDescriptor/type") + default_type_elem = plugin_elem.find("typeDescriptor/dependencyType/defaultType") + if type_elem is not None: + type_ = type_elem.get("name") + elif default_type_elem is not None: + type_ = default_type_elem.get("name") + else: + type_ = "Required" + + plugin_data_list.append( + self.PluginData( + name_, + description_, + image_, + file_data_list, + folder_data_list, + flag_data_list, + type_ + ) + ) + + group_data.set_plugin_list(plugin_data_list) + if plugins_elem.get("order") == "Ascending": + group_data.sort_ascending() + elif plugins_elem.get("order") == "Descending": + group_data.sort_descending() + + group_data_list.append(group_data) + + step_data.set_group_list(group_data_list) + if opt_group_elem.get("order") == "Ascending": + step_data.sort_ascending() + elif opt_group_elem.get("order") == "Descending": + step_data.sort_descending() + + self.kwargs["gui_worker"].create_page_signal.emit(step_data) + + +class PreviewMoGui(QWidget, preview_mo.Ui_Form): + clear_tab_signal = pyqtSignal() + clear_ui_signal = pyqtSignal() + invalid_node_signal = pyqtSignal() + missing_node_signal = pyqtSignal() + set_labels_signal = pyqtSignal([str, str, str, str]) + create_page_signal = pyqtSignal([object]) + + class ScaledLabel(QLabel): + def __init__(self, parent=None): + super().__init__(parent) + self.original_pixmap = None + self.setMinimumSize(320, 200) + + def set_scalable_pixmap(self, pixmap): + self.original_pixmap = pixmap + self.setPixmap(self.original_pixmap.scaled(self.size(), Qt.KeepAspectRatio)) + + def resizeEvent(self, event): + if self.pixmap() and self.original_pixmap: + self.setPixmap(self.original_pixmap.scaled(event.size(), Qt.KeepAspectRatio)) + + class PreviewItem(QStandardItem): + def set_priority(self, value): + self.priority = value + + def __init__(self, mo_preview_layout): + super().__init__() + self.mo_preview_layout = mo_preview_layout + self.setupUi(self) + self.mo_preview_layout.addWidget(self) + self.label_image = self.ScaledLabel(self) + self.splitter_label.addWidget(self.label_image) + self.hide() + + self.button_preview_more.setIcon(QIcon(join(cur_folder, "resources/logos/logo_more.png"))) + self.button_preview_less.setIcon(QIcon(join(cur_folder, "resources/logos/logo_less.png"))) + self.button_preview_more.clicked.connect(self.button_preview_more.hide) + self.button_preview_more.clicked.connect(self.button_preview_less.show) + self.button_preview_more.clicked.connect(self.widget_preview.show) + self.button_preview_less.clicked.connect(self.button_preview_less.hide) + self.button_preview_less.clicked.connect(self.button_preview_more.show) + self.button_preview_less.clicked.connect(self.widget_preview.hide) + self.button_preview_more.clicked.emit() + self.button_results_more.setIcon(QIcon(join(cur_folder, "resources/logos/logo_more.png"))) + self.button_results_less.setIcon(QIcon(join(cur_folder, "resources/logos/logo_less.png"))) + self.button_results_more.clicked.connect(self.button_results_more.hide) + self.button_results_more.clicked.connect(self.button_results_less.show) + self.button_results_more.clicked.connect(self.widget_results.show) + self.button_results_less.clicked.connect(self.button_results_less.hide) + self.button_results_less.clicked.connect(self.button_results_more.show) + self.button_results_less.clicked.connect(self.widget_results.hide) + self.button_results_less.clicked.emit() + + self.model_files = QStandardItemModel() + self.tree_results.expanded.connect( + lambda: self.tree_results.header().resizeSections(QHeaderView.Stretch) + ) + self.tree_results.collapsed.connect( + lambda: self.tree_results.header().resizeSections(QHeaderView.Stretch) + ) + self.tree_results.setContextMenuPolicy(Qt.CustomContextMenu) + self.tree_results.customContextMenuRequested.connect(self.on_custom_context_menu) + self.model_flags = QStandardItemModel() + self.list_flags.expanded.connect( + lambda: self.list_flags.header().resizeSections(QHeaderView.Stretch) + ) + self.list_flags.collapsed.connect( + lambda: self.list_flags.header().resizeSections(QHeaderView.Stretch) + ) + self.reset_models() + + self.label_invalid = QLabel( + "Select an Installation Step node or one of its children to preview its installer page." + ) + self.label_invalid.setAlignment(Qt.AlignCenter) + self.mo_preview_layout.addWidget(self.label_invalid) + self.label_invalid.hide() + + self.label_missing = QLabel( + "In order to preview an installer page, create an Installation Step node." + ) + self.label_missing.setAlignment(Qt.AlignCenter) + self.mo_preview_layout.addWidget(self.label_missing) + self.label_missing.hide() + + self.clear_tab_signal.connect(self.clear_tab) + self.clear_ui_signal.connect(self.clear_ui) + self.invalid_node_signal.connect(self.invalid_node) + self.missing_node_signal.connect(self.missing_node) + self.set_labels_signal.connect(self.set_labels) + self.create_page_signal.connect(self.create_page) + + def on_custom_context_menu(self, position): + node_tree_context_menu = QMenu(self.tree_results) + + action_expand = QAction(QIcon(join(cur_folder, "resources/logos/logo_expand.png")), "Expand All", self) + action_collapse = QAction(QIcon(join(cur_folder, "resources/logos/logo_collapse.png")), "Collapse All", self) + + action_expand.triggered.connect(self.tree_results.expandAll) + action_collapse.triggered.connect(self.tree_results.collapseAll) + + node_tree_context_menu.addActions([action_expand, action_collapse]) + + node_tree_context_menu.move(self.tree_results.mapToGlobal(position)) + node_tree_context_menu.exec_() + + def eventFilter(self, object_, event): + if event.type() == QEvent.HoverEnter: + self.label_description.setText(object_.property("description")) + self.label_image.set_scalable_pixmap(QPixmap(object_.property("image_path"))) + + return QWidget().eventFilter(object_, event) + + def clear_ui(self): + self.label_name.clear() + self.label_author.clear() + self.label_version.clear() + self.label_website.clear() + self.label_description.clear() + self.label_image.clear() + [widget.deleteLater() for widget in [ + self.layout_widget.itemAt(index).widget() for index in range(self.layout_widget.count()) + if self.layout_widget.itemAt(index).widget() + ]] + self.reset_models() + + def reset_models(self): + self.model_files.clear() + self.model_files.setHorizontalHeaderLabels(["Files Preview", "Source", "Plugin"]) + self.model_files_root = QStandardItem(QIcon(join(cur_folder, "resources/logos/logo_folder.png")), "") + self.model_files.appendRow(self.model_files_root) + self.tree_results.setModel(self.model_files) + self.model_flags.clear() + self.model_flags.setHorizontalHeaderLabels(["Flag Label", "Flag Value", "Plugin"]) + self.list_flags.setModel(self.model_flags) + + def clear_tab(self): + for index in reversed(range(self.mo_preview_layout.count())): + widget = self.mo_preview_layout.itemAt(index).widget() + if widget is not None: + widget.hide() + + def invalid_node(self): + self.clear_tab() + self.label_invalid.show() + + def missing_node(self): + self.clear_tab() + self.label_missing.show() + + def set_labels(self, name, author, version, website): + self.label_name.setText(name) + self.label_author.setText(author) + self.label_version.setText(version) + self.label_website.setText("link".format(website)) + + # this is pretty horrendous, need to come up with a better way of doing this. + def create_page(self, page_data): + group_step = QGroupBox(page_data.name) + layout_step = QVBoxLayout() + group_step.setLayout(layout_step) + + check_first_radio = True + for group in page_data.group_list: + group_group = QGroupBox(group.name) + layout_group = QVBoxLayout() + group_group.setLayout(layout_group) + + for plugin in group.plugin_list: + if group.type in ["SelectAny", "SelectAll", "SelectAtLeastOne"]: + button_plugin = QCheckBox(plugin.name, self) + + if group.type == "SelectAll": + button_plugin.setChecked(True) + button_plugin.setEnabled(False) + elif group.type == "SelectAtLeastOne": + button_plugin.toggled.connect( + lambda checked, button=button_plugin: button.setChecked(True) + if not checked and not [ + button for button in [ + layout_group.itemAt(index).widget() for index in range(layout_group.count()) + if layout_group.itemAt(index).widget() + ] if button.isChecked() + ] + else None + ) + + elif group.type in ["SelectExactlyOne", "SelectAtMostOne"]: + button_plugin = QRadioButton(plugin.name, self) + if check_first_radio and not button_plugin.isChecked(): + button_plugin.animateClick(0) + check_first_radio = False + + button_plugin.setProperty("description", plugin.description) + button_plugin.setProperty("image_path", plugin.image_path) + button_plugin.setProperty("file_list", plugin.file_list) + button_plugin.setProperty("folder_list", plugin.folder_list) + button_plugin.setProperty("flag_list", plugin.flag_list) + button_plugin.setProperty("type", plugin.type) + button_plugin.setAttribute(Qt.WA_Hover) + + if plugin.type == "Required": + button_plugin.setEnabled(False) + elif plugin.type == "Recommended": + button_plugin.animateClick(0) if not button_plugin.isChecked() else None + elif plugin.type == "NotUsable": + button_plugin.setChecked(False) + button_plugin.setEnabled(False) + + button_plugin.toggled.connect(self.reset_models) + button_plugin.toggled.connect(self.update_installed_files) + button_plugin.toggled.connect(self.update_set_flags) + + button_plugin.installEventFilter(self) + button_plugin.setObjectName("preview_button") + layout_group.addWidget(button_plugin) + + if group.type == "SelectAtMostOne": + button_none = QRadioButton("None") + layout_group.addWidget(button_none) + + layout_step.addWidget(group_group) + + self.layout_widget.addWidget(group_step) + self.reset_models() + self.update_installed_files() + self.update_set_flags() + self.show() + + def update_installed_files(self): + def recurse_add_items(folder, parent): + for boop in listdir(folder): # I was very tired + if isdir(join(folder, boop)): + folder_item = None + existing_folder_ = self.model_files.findItems(boop, Qt.MatchRecursive) + if existing_folder_: + for boopity in existing_folder_: + if boopity.parent() is parent: + folder_item = boopity + break + if not folder_item: + folder_item = self.PreviewItem( + QIcon(join(cur_folder, "resources/logos/logo_folder.png")), + boop + ) + folder_item.set_priority(folder_.priority) + parent.appendRow([folder_item, QStandardItem(rel_source), QStandardItem(button.text())]) + recurse_add_items(join(folder, boop), folder_item) + + elif isfile(join(folder, boop)): + file_item_ = None + existing_file_ = self.model_files.findItems(boop, Qt.MatchRecursive) + if existing_file_: + for boopity in existing_file_: + if boopity.parent() is parent: + if folder_.priority < boopity.priority: + file_item_ = boopity + break + else: + parent.removeRow(boopity.row()) + break + if not file_item_: + file_item_ = self.PreviewItem( + QIcon(join(cur_folder, "resources/logos/logo_file.png")), + boop + ) + file_item_.set_priority(folder_.priority) + parent.appendRow([file_item_, QStandardItem(rel_source), QStandardItem(button.text())]) + + for button in self.findChildren((QCheckBox, QRadioButton), "preview_button"): + for folder_ in button.property("folder_list"): + if (button.isChecked() and button.property("type") != "NotUsable" or + folder_.always_install or + folder_.install_usable and button.property("type") != "NotUsable" or + button.property("type") == "Required"): + destination = folder_.destination + abs_source = folder_.abs_source + rel_source = folder_.rel_source + parent_item = self.model_files_root + + destination_split = destination.split("/") + if destination_split[0] == ".": + destination_split = destination_split[1:] + for dest_folder in destination_split: + existing_folder_list = self.model_files.findItems(dest_folder, Qt.MatchRecursive) + if existing_folder_list: + for existing_folder in existing_folder_list: + if existing_folder.parent() is parent_item: + parent_item = existing_folder + break + continue + item_ = self.PreviewItem( + QIcon(join(cur_folder, "resources/logos/logo_folder.png")), + dest_folder + ) + item_.set_priority(folder_.priority) + parent_item.appendRow([item_, QStandardItem(), QStandardItem(button.text())]) + parent_item = item_ + + if isdir(abs_source): + recurse_add_items(abs_source, parent_item) + + for file_ in button.property("file_list"): + if (button.isChecked() or folder_.always_install or + folder_.install_usable and button.property("type") != "NotUsable"): + destination = file_.destination + abs_source = file_.abs_source + rel_source = file_.rel_source + parent_item = self.model_files_root + + destination_split = destination.split("/") + if destination_split[0] == ".": + destination_split = destination_split[1:] + for dest_folder in destination_split: + existing_folder_list = self.model_files.findItems(dest_folder, Qt.MatchRecursive) + if existing_folder_list: + for existing_folder in existing_folder_list: + if existing_folder.parent() is parent_item: + parent_item = existing_folder + break + continue + item_ = self.PreviewItem( + QIcon(join(cur_folder, "resources/logos/logo_folder.png")), + dest_folder + ) + item_.set_priority(file_.priority) + parent_item.appendRow([item_, QStandardItem(), QStandardItem(button.text())]) + parent_item = item_ + + source_file = abs_source.split("/")[len(abs_source.split("/")) - 1] + file_item = None + existing_file_list = self.model_files.findItems(source_file, Qt.MatchRecursive) + if existing_file_list: + for existing_file in existing_file_list: + if existing_file.parent() is parent_item: + if file_.priority < existing_file.priority: + file_item = existing_file + break + else: + parent_item.removeRow(existing_file.row()) + break + if not file_item: + file_item = self.PreviewItem( + QIcon(join(cur_folder, "resources/logos/logo_file.png")), + source_file + ) + file_item.set_priority(file_.priority) + parent_item.appendRow([file_item, QStandardItem(rel_source), QStandardItem(button.text())]) + + self.tree_results.header().resizeSections(QHeaderView.Stretch) + + def update_set_flags(self): + for button in self.findChildren((QCheckBox, QRadioButton), "preview_button"): + if button.isChecked(): + for flag in button.property("flag_list"): + flag_label = QStandardItem(flag.label) + flag_value = QStandardItem(flag.value) + flag_plugin = QStandardItem(button.text()) + existing_flag = self.model_flags.findItems(flag.label) + if existing_flag: + previous_flag_row = existing_flag[0].row() + self.model_flags.removeRow(previous_flag_row) + self.model_flags.insertRow(previous_flag_row, [flag_label, flag_value, flag_plugin]) + else: + self.model_flags.appendRow([flag_label, flag_value, flag_plugin]) + + self.list_flags.header().resizeSections(QHeaderView.Stretch) diff --git a/designer/props.py b/designer/props.py index 6c48b67..a008295 100644 --- a/designer/props.py +++ b/designer/props.py @@ -92,28 +92,43 @@ def set_value(self, value): super().set_value(value) -class PropertyFolder(_PropertyBase): +class PropertyFolder(PropertyText): """ A property that holds the path to a folder. """ - def __init__(self, name, text="", editable=True): - super().__init__(name, (), editable) - self.value = text + pass -class PropertyFile(_PropertyBase): +class PropertyFile(PropertyText): """ A property that holds the path to a file. """ - def __init__(self, name, text="", editable=True): - super().__init__(name, (), editable) - self.value = text + pass -class PropertyColour(_PropertyBase): +class PropertyColour(PropertyText): """ A property that holds a colour hex value. """ - def __init__(self, name, text="", editable=True): - super().__init__(name, (), editable) - self.value = text + pass + + +class PropertyFlagLabel(PropertyText): + """ + A property that holds a flag's label. + """ + pass + + +class PropertyFlagValue(PropertyText): + """ + A property that holds a flag's value. + """ + pass + + +class PropertyHTML(PropertyText): + """ + A property that allows html text. Used for plugin descriptions. + """ + pass diff --git a/designer/ui_templates/__init__.py b/designer/ui_templates/__init__.py new file mode 100644 index 0000000..d8f5fac --- /dev/null +++ b/designer/ui_templates/__init__.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +# Copyright 2016 Daniel Nunes +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/designer/ui_templates/preview_mo.py b/designer/ui_templates/preview_mo.py new file mode 100644 index 0000000..c8cd0c7 --- /dev/null +++ b/designer/ui_templates/preview_mo.py @@ -0,0 +1,255 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/preview_mo.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(627, 581) + self.verticalLayout = QtWidgets.QVBoxLayout(Form) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.verticalLayout.setSpacing(3) + self.verticalLayout.setObjectName("verticalLayout") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem) + self.label_8 = QtWidgets.QLabel(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_8.sizePolicy().hasHeightForWidth()) + self.label_8.setSizePolicy(sizePolicy) + self.label_8.setMaximumSize(QtCore.QSize(16777215, 23)) + font = QtGui.QFont() + font.setPointSize(14) + font.setBold(True) + font.setWeight(75) + self.label_8.setFont(font) + self.label_8.setObjectName("label_8") + self.horizontalLayout_2.addWidget(self.label_8) + self.button_preview_more = QtWidgets.QPushButton(Form) + self.button_preview_more.setMaximumSize(QtCore.QSize(24, 16777215)) + self.button_preview_more.setText("") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap("../logos/logo_more.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_preview_more.setIcon(icon) + self.button_preview_more.setFlat(True) + self.button_preview_more.setObjectName("button_preview_more") + self.horizontalLayout_2.addWidget(self.button_preview_more) + self.button_preview_less = QtWidgets.QPushButton(Form) + self.button_preview_less.setMaximumSize(QtCore.QSize(24, 16777215)) + self.button_preview_less.setText("") + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap("../logos/logo_less.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_preview_less.setIcon(icon1) + self.button_preview_less.setFlat(True) + self.button_preview_less.setObjectName("button_preview_less") + self.horizontalLayout_2.addWidget(self.button_preview_less) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem1) + self.verticalLayout.addLayout(self.horizontalLayout_2) + self.widget_preview = QtWidgets.QWidget(Form) + self.widget_preview.setObjectName("widget_preview") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.widget_preview) + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_3.setSpacing(3) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.formLayout = QtWidgets.QFormLayout() + self.formLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) + self.formLayout.setFieldGrowthPolicy(QtWidgets.QFormLayout.FieldsStayAtSizeHint) + self.formLayout.setObjectName("formLayout") + self.label = QtWidgets.QLabel(self.widget_preview) + self.label.setObjectName("label") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label) + self.label_name = QtWidgets.QLabel(self.widget_preview) + self.label_name.setText("") + self.label_name.setObjectName("label_name") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.label_name) + self.label_3 = QtWidgets.QLabel(self.widget_preview) + self.label_3.setObjectName("label_3") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_3) + self.label_author = QtWidgets.QLabel(self.widget_preview) + self.label_author.setText("") + self.label_author.setObjectName("label_author") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.label_author) + self.label_5 = QtWidgets.QLabel(self.widget_preview) + self.label_5.setObjectName("label_5") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_5) + self.label_version = QtWidgets.QLabel(self.widget_preview) + self.label_version.setText("") + self.label_version.setObjectName("label_version") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.label_version) + self.label_7 = QtWidgets.QLabel(self.widget_preview) + self.label_7.setObjectName("label_7") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_7) + self.label_website = QtWidgets.QLabel(self.widget_preview) + self.label_website.setText("") + self.label_website.setObjectName("label_website") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.label_website) + self.verticalLayout_3.addLayout(self.formLayout) + self.splitter_2 = QtWidgets.QSplitter(self.widget_preview) + self.splitter_2.setOrientation(QtCore.Qt.Horizontal) + self.splitter_2.setChildrenCollapsible(False) + self.splitter_2.setObjectName("splitter_2") + self.splitter_label = QtWidgets.QSplitter(self.splitter_2) + self.splitter_label.setOrientation(QtCore.Qt.Vertical) + self.splitter_label.setChildrenCollapsible(False) + self.splitter_label.setObjectName("splitter_label") + self.label_description = QtWidgets.QTextBrowser(self.splitter_label) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.label_description.sizePolicy().hasHeightForWidth()) + self.label_description.setSizePolicy(sizePolicy) + self.label_description.setObjectName("label_description") + self.widget_base = QtWidgets.QWidget(self.splitter_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widget_base.sizePolicy().hasHeightForWidth()) + self.widget_base.setSizePolicy(sizePolicy) + self.widget_base.setObjectName("widget_base") + self.layout_widget = QtWidgets.QVBoxLayout(self.widget_base) + self.layout_widget.setContentsMargins(0, 0, 0, 0) + self.layout_widget.setSpacing(3) + self.layout_widget.setObjectName("layout_widget") + self.verticalLayout_3.addWidget(self.splitter_2) + self.verticalLayout.addWidget(self.widget_preview) + self.line = QtWidgets.QFrame(Form) + self.line.setMidLineWidth(1) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.verticalLayout.addWidget(self.line) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem2) + self.label_4 = QtWidgets.QLabel(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth()) + self.label_4.setSizePolicy(sizePolicy) + self.label_4.setMaximumSize(QtCore.QSize(16777215, 23)) + font = QtGui.QFont() + font.setPointSize(14) + font.setBold(True) + font.setItalic(False) + font.setWeight(75) + self.label_4.setFont(font) + self.label_4.setAlignment(QtCore.Qt.AlignCenter) + self.label_4.setObjectName("label_4") + self.horizontalLayout.addWidget(self.label_4) + self.button_results_more = QtWidgets.QPushButton(Form) + self.button_results_more.setMaximumSize(QtCore.QSize(24, 16777215)) + self.button_results_more.setText("") + self.button_results_more.setIcon(icon) + self.button_results_more.setFlat(True) + self.button_results_more.setObjectName("button_results_more") + self.horizontalLayout.addWidget(self.button_results_more) + self.button_results_less = QtWidgets.QPushButton(Form) + self.button_results_less.setMaximumSize(QtCore.QSize(24, 16777215)) + self.button_results_less.setText("") + self.button_results_less.setIcon(icon1) + self.button_results_less.setFlat(True) + self.button_results_less.setObjectName("button_results_less") + self.horizontalLayout.addWidget(self.button_results_less) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem3) + self.verticalLayout.addLayout(self.horizontalLayout) + self.widget_results = QtWidgets.QWidget(Form) + self.widget_results.setObjectName("widget_results") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.widget_results) + self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_2.setSpacing(3) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.label_2 = QtWidgets.QLabel(self.widget_results) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth()) + self.label_2.setSizePolicy(sizePolicy) + self.label_2.setMaximumSize(QtCore.QSize(16777215, 21)) + font = QtGui.QFont() + font.setBold(True) + font.setItalic(True) + font.setWeight(75) + self.label_2.setFont(font) + self.label_2.setAlignment(QtCore.Qt.AlignCenter) + self.label_2.setObjectName("label_2") + self.verticalLayout_2.addWidget(self.label_2) + self.tree_results = QtWidgets.QTreeView(self.widget_results) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.tree_results.sizePolicy().hasHeightForWidth()) + self.tree_results.setSizePolicy(sizePolicy) + self.tree_results.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.tree_results.setIndentation(10) + self.tree_results.setUniformRowHeights(True) + self.tree_results.setObjectName("tree_results") + self.tree_results.header().setCascadingSectionResizes(False) + self.tree_results.header().setDefaultSectionSize(150) + self.tree_results.header().setMinimumSectionSize(100) + self.verticalLayout_2.addWidget(self.tree_results) + self.label_6 = QtWidgets.QLabel(self.widget_results) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_6.sizePolicy().hasHeightForWidth()) + self.label_6.setSizePolicy(sizePolicy) + self.label_6.setMaximumSize(QtCore.QSize(16777215, 21)) + font = QtGui.QFont() + font.setBold(True) + font.setItalic(True) + font.setWeight(75) + self.label_6.setFont(font) + self.label_6.setAlignment(QtCore.Qt.AlignCenter) + self.label_6.setObjectName("label_6") + self.verticalLayout_2.addWidget(self.label_6) + self.list_flags = QtWidgets.QTreeView(self.widget_results) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.list_flags.sizePolicy().hasHeightForWidth()) + self.list_flags.setSizePolicy(sizePolicy) + self.list_flags.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.list_flags.setObjectName("list_flags") + self.verticalLayout_2.addWidget(self.list_flags) + self.verticalLayout.addWidget(self.widget_results) + spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem4) + self.button_full_preview = QtWidgets.QPushButton(Form) + self.button_full_preview.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.button_full_preview.sizePolicy().hasHeightForWidth()) + self.button_full_preview.setSizePolicy(sizePolicy) + self.button_full_preview.setObjectName("button_full_preview") + self.verticalLayout.addWidget(self.button_full_preview, 0, QtCore.Qt.AlignHCenter) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label_8.setText(_translate("Form", "Step Preview")) + self.label.setText(_translate("Form", "Name")) + self.label_3.setText(_translate("Form", "Author")) + self.label_5.setText(_translate("Form", "Version")) + self.label_7.setText(_translate("Form", "Website")) + self.label_4.setText(_translate("Form", "Page Results")) + self.label_2.setText(_translate("Form", "Files Installed")) + self.label_6.setText(_translate("Form", "Flags Set")) + self.button_full_preview.setText(_translate("Form", "Start Full Preview")) + diff --git a/designer/ui_templates/tutorial_advanced.py b/designer/ui_templates/tutorial_advanced.py new file mode 100644 index 0000000..50bacb4 --- /dev/null +++ b/designer/ui_templates/tutorial_advanced.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/tutorial_advanced.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(1115, 659) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth()) + Dialog.setSizePolicy(sizePolicy) + self.frame_node = QtWidgets.QFrame(Dialog) + self.frame_node.setGeometry(QtCore.QRect(20, 210, 241, 121)) + self.frame_node.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame_node.setFrameShadow(QtWidgets.QFrame.Sunken) + self.frame_node.setObjectName("frame_node") + self.verticalLayout = QtWidgets.QVBoxLayout(self.frame_node) + self.verticalLayout.setObjectName("verticalLayout") + self.label = QtWidgets.QLabel(self.frame_node) + self.label.setAlignment(QtCore.Qt.AlignCenter) + self.label.setWordWrap(True) + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + self.frame_preview = QtWidgets.QFrame(Dialog) + self.frame_preview.setGeometry(QtCore.QRect(270, 230, 551, 251)) + self.frame_preview.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame_preview.setFrameShadow(QtWidgets.QFrame.Sunken) + self.frame_preview.setObjectName("frame_preview") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame_preview) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.label_2 = QtWidgets.QLabel(self.frame_preview) + self.label_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.label_2.setAlignment(QtCore.Qt.AlignCenter) + self.label_2.setWordWrap(True) + self.label_2.setObjectName("label_2") + self.verticalLayout_2.addWidget(self.label_2) + self.button_exit = QtWidgets.QPushButton(self.frame_preview) + self.button_exit.setObjectName("button_exit") + self.verticalLayout_2.addWidget(self.button_exit) + self.frame_prop = QtWidgets.QFrame(Dialog) + self.frame_prop.setGeometry(QtCore.QRect(850, 10, 241, 271)) + self.frame_prop.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame_prop.setFrameShadow(QtWidgets.QFrame.Sunken) + self.frame_prop.setObjectName("frame_prop") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.frame_prop) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.label_3 = QtWidgets.QLabel(self.frame_prop) + self.label_3.setAlignment(QtCore.Qt.AlignCenter) + self.label_3.setWordWrap(True) + self.label_3.setObjectName("label_3") + self.verticalLayout_3.addWidget(self.label_3) + self.frame_child = QtWidgets.QFrame(Dialog) + self.frame_child.setGeometry(QtCore.QRect(850, 320, 241, 271)) + self.frame_child.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame_child.setFrameShadow(QtWidgets.QFrame.Sunken) + self.frame_child.setObjectName("frame_child") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.frame_child) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.label_4 = QtWidgets.QLabel(self.frame_child) + self.label_4.setAlignment(QtCore.Qt.AlignCenter) + self.label_4.setWordWrap(True) + self.label_4.setObjectName("label_4") + self.verticalLayout_4.addWidget(self.label_4) + + self.retranslateUi(Dialog) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Dialog")) + self.label.setText(_translate("Dialog", "

This is the Node Tree.

Here you\'ll find the nodes that make up your installer.

You can navigate the tree with the little arrows on the left side of each node.

")) + self.label_2.setText(_translate("Dialog", "

These are the Preview Tabs.

Here you can preview what your installer looks like and what the XML code will be once you save.

")) + self.button_exit.setText(_translate("Dialog", "Continue")) + self.label_3.setText(_translate("Dialog", "

This is the Property Editor.

Here you can edit the individual properties each node has.

")) + self.label_4.setText(_translate("Dialog", "

This is the Children Box.

Here you can view which children nodes are available to the currently selected node and add them if possible.

You can only have one of some children while others are available infinitely.

")) + diff --git a/designer/ui_templates/window_about.py b/designer/ui_templates/window_about.py new file mode 100644 index 0000000..bba3cb9 --- /dev/null +++ b/designer/ui_templates/window_about.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/window_about.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.setWindowModality(QtCore.Qt.ApplicationModal) + Dialog.resize(340, 355) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth()) + Dialog.setSizePolicy(sizePolicy) + Dialog.setMinimumSize(QtCore.QSize(340, 355)) + Dialog.setMaximumSize(QtCore.QSize(340, 355)) + Dialog.setModal(True) + self.verticalLayout = QtWidgets.QVBoxLayout(Dialog) + self.verticalLayout.setObjectName("verticalLayout") + self.label = QtWidgets.QLabel(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(2) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setFamily("Arial") + font.setPointSize(22) + self.label.setFont(font) + self.label.setAlignment(QtCore.Qt.AlignCenter) + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + self.version = QtWidgets.QLabel(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.version.sizePolicy().hasHeightForWidth()) + self.version.setSizePolicy(sizePolicy) + self.version.setScaledContents(False) + self.version.setAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop) + self.version.setObjectName("version") + self.verticalLayout.addWidget(self.version) + self.copyright = QtWidgets.QLabel(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.copyright.sizePolicy().hasHeightForWidth()) + self.copyright.setSizePolicy(sizePolicy) + self.copyright.setAlignment(QtCore.Qt.AlignCenter) + self.copyright.setObjectName("copyright") + self.verticalLayout.addWidget(self.copyright) + self.label_2 = QtWidgets.QLabel(Dialog) + self.label_2.setAlignment(QtCore.Qt.AlignCenter) + self.label_2.setObjectName("label_2") + self.verticalLayout.addWidget(self.label_2) + self.label_4 = QtWidgets.QLabel(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(5) + sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth()) + self.label_4.setSizePolicy(sizePolicy) + self.label_4.setTextFormat(QtCore.Qt.AutoText) + self.label_4.setScaledContents(False) + self.label_4.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter) + self.label_4.setWordWrap(True) + self.label_4.setObjectName("label_4") + self.verticalLayout.addWidget(self.label_4) + self.button = QtWidgets.QPushButton(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.button.sizePolicy().hasHeightForWidth()) + self.button.setSizePolicy(sizePolicy) + self.button.setDefault(False) + self.button.setObjectName("button") + self.verticalLayout.addWidget(self.button, 0, QtCore.Qt.AlignHCenter) + + self.retranslateUi(Dialog) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "About")) + self.label.setText(_translate("Dialog", "FOMOD Designer")) + self.version.setText(_translate("Dialog", "Version: 0.0.0.0")) + self.copyright.setText(_translate("Dialog", "Copyright 2016 Daniel Nunes")) + self.label_2.setText(_translate("Dialog", "

Special Thanks to Hishutup.

")) + self.label_4.setText(_translate("Dialog", "

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions and limitations under the License.

")) + self.button.setText(_translate("Dialog", "Exit")) + diff --git a/designer/ui_templates/window_intro.py b/designer/ui_templates/window_intro.py new file mode 100644 index 0000000..a6c76b1 --- /dev/null +++ b/designer/ui_templates/window_intro.py @@ -0,0 +1,161 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/window_intro.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(609, 436) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) + MainWindow.setSizePolicy(sizePolicy) + MainWindow.setMinimumSize(QtCore.QSize(609, 436)) + MainWindow.setMaximumSize(QtCore.QSize(609, 436)) + MainWindow.setWindowTitle("") + self.centralwidget = QtWidgets.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) + self.verticalLayout.setObjectName("verticalLayout") + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem) + self.title = QtWidgets.QLabel(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.title.sizePolicy().hasHeightForWidth()) + self.title.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setPointSize(25) + self.title.setFont(font) + self.title.setText("FOMOD Designer") + self.title.setAlignment(QtCore.Qt.AlignCenter) + self.title.setWordWrap(False) + self.title.setObjectName("title") + self.verticalLayout.addWidget(self.title) + self.version = QtWidgets.QLabel(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.version.sizePolicy().hasHeightForWidth()) + self.version.setSizePolicy(sizePolicy) + self.version.setAlignment(QtCore.Qt.AlignCenter) + self.version.setObjectName("version") + self.verticalLayout.addWidget(self.version) + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem1) + spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem2) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem3) + self.new_button = QtWidgets.QPushButton(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.new_button.sizePolicy().hasHeightForWidth()) + self.new_button.setSizePolicy(sizePolicy) + self.new_button.setAutoFillBackground(False) + self.new_button.setObjectName("new_button") + self.horizontalLayout.addWidget(self.new_button) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem4) + self.verticalLayout.addLayout(self.horizontalLayout) + self.horizontalLayout_4 = QtWidgets.QHBoxLayout() + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_4.addItem(spacerItem5) + self.button_about = QtWidgets.QPushButton(self.centralwidget) + self.button_about.setObjectName("button_about") + self.horizontalLayout_4.addWidget(self.button_about) + spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_4.addItem(spacerItem6) + self.verticalLayout.addLayout(self.horizontalLayout_4) + spacerItem7 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem7) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + spacerItem8 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem8) + self.widget = QtWidgets.QWidget(self.centralwidget) + self.widget.setObjectName("widget") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.widget) + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.check_intro = QtWidgets.QCheckBox(self.widget) + self.check_intro.setObjectName("check_intro") + self.verticalLayout_3.addWidget(self.check_intro) + self.check_advanced = QtWidgets.QCheckBox(self.widget) + self.check_advanced.setEnabled(False) + self.check_advanced.setChecked(False) + self.check_advanced.setObjectName("check_advanced") + self.verticalLayout_3.addWidget(self.check_advanced) + self.horizontalLayout_2.addWidget(self.widget) + spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem9) + self.verticalLayout.addLayout(self.horizontalLayout_2) + spacerItem10 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem10) + self.recent_label = QtWidgets.QLabel(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.recent_label.sizePolicy().hasHeightForWidth()) + self.recent_label.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(True) + font.setItalic(True) + font.setWeight(75) + self.recent_label.setFont(font) + self.recent_label.setAlignment(QtCore.Qt.AlignCenter) + self.recent_label.setObjectName("recent_label") + self.verticalLayout.addWidget(self.recent_label) + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.scrollArea = QtWidgets.QScrollArea(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.scrollArea.sizePolicy().hasHeightForWidth()) + self.scrollArea.setSizePolicy(sizePolicy) + self.scrollArea.setMaximumSize(QtCore.QSize(16777215, 158)) + self.scrollArea.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored) + self.scrollArea.setWidgetResizable(True) + self.scrollArea.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.scrollArea.setObjectName("scrollArea") + self.scrollAreaWidgetContents = QtWidgets.QWidget() + self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 26, 587, 16)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.scrollAreaWidgetContents.sizePolicy().hasHeightForWidth()) + self.scrollAreaWidgetContents.setSizePolicy(sizePolicy) + self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") + self.scroll_layout = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents) + self.scroll_layout.setContentsMargins(0, 0, 0, 0) + self.scroll_layout.setObjectName("scroll_layout") + self.scrollArea.setWidget(self.scrollAreaWidgetContents) + self.horizontalLayout_3.addWidget(self.scrollArea) + self.verticalLayout.addLayout(self.horizontalLayout_3) + MainWindow.setCentralWidget(self.centralwidget) + + self.retranslateUi(MainWindow) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + self.version.setText(_translate("MainWindow", "Version 0.0.0")) + self.new_button.setText(_translate("MainWindow", "New/Open")) + self.button_about.setText(_translate("MainWindow", "About")) + self.check_intro.setText(_translate("MainWindow", "Don\'t show this window again.")) + self.check_advanced.setText(_translate("MainWindow", "Show the Advanced View at startup.")) + self.recent_label.setText(_translate("MainWindow", "Recent Packages:")) + diff --git a/designer/ui_templates/window_mainframe.py b/designer/ui_templates/window_mainframe.py new file mode 100644 index 0000000..ca8839d --- /dev/null +++ b/designer/ui_templates/window_mainframe.py @@ -0,0 +1,333 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/window_mainframe.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(1115, 659) + self.centralwidget = QtWidgets.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.centralwidget) + self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.splitter = QtWidgets.QSplitter(self.centralwidget) + self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setOpaqueResize(True) + self.splitter.setObjectName("splitter") + self.tabWidget = QtWidgets.QTabWidget(self.splitter) + self.tabWidget.setObjectName("tabWidget") + self.tabWidgetPage1 = QtWidgets.QWidget() + self.tabWidgetPage1.setObjectName("tabWidgetPage1") + self.layout_mo = QtWidgets.QHBoxLayout(self.tabWidgetPage1) + self.layout_mo.setObjectName("layout_mo") + self.tabWidget.addTab(self.tabWidgetPage1, "") + self.tabWidgetPage2 = QtWidgets.QWidget() + self.tabWidgetPage2.setObjectName("tabWidgetPage2") + self.verticalLayout = QtWidgets.QVBoxLayout(self.tabWidgetPage2) + self.verticalLayout.setObjectName("verticalLayout") + self.label = QtWidgets.QLabel(self.tabWidgetPage2) + self.label.setLineWidth(1) + self.label.setAlignment(QtCore.Qt.AlignCenter) + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + self.xml_code_browser = QtWidgets.QTextBrowser(self.tabWidgetPage2) + self.xml_code_browser.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) + self.xml_code_browser.setLineWrapMode(QtWidgets.QTextEdit.NoWrap) + self.xml_code_browser.setObjectName("xml_code_browser") + self.verticalLayout.addWidget(self.xml_code_browser) + self.tabWidget.addTab(self.tabWidgetPage2, "") + self.horizontalLayout_3.addWidget(self.splitter) + MainWindow.setCentralWidget(self.centralwidget) + self.statusbar = QtWidgets.QStatusBar(MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + self.property_editor = QtWidgets.QDockWidget(MainWindow) + self.property_editor.setMinimumSize(QtCore.QSize(250, 63)) + self.property_editor.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea|QtCore.Qt.RightDockWidgetArea) + self.property_editor.setObjectName("property_editor") + self.dockWidgetContents = QtWidgets.QWidget() + self.dockWidgetContents.setObjectName("dockWidgetContents") + self.layout_prop_editor = QtWidgets.QFormLayout(self.dockWidgetContents) + self.layout_prop_editor.setObjectName("layout_prop_editor") + self.property_editor.setWidget(self.dockWidgetContents) + MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.property_editor) + self.node_tree = QtWidgets.QDockWidget(MainWindow) + self.node_tree.setEnabled(True) + self.node_tree.setMinimumSize(QtCore.QSize(250, 222)) + self.node_tree.setFloating(False) + self.node_tree.setFeatures(QtWidgets.QDockWidget.AllDockWidgetFeatures) + self.node_tree.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea|QtCore.Qt.RightDockWidgetArea) + self.node_tree.setObjectName("node_tree") + self.dockWidgetContents_2 = QtWidgets.QWidget() + self.dockWidgetContents_2.setObjectName("dockWidgetContents_2") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.dockWidgetContents_2) + self.verticalLayout_2.setContentsMargins(5, 0, 5, 0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.button_wizard = QtWidgets.QPushButton(self.dockWidgetContents_2) + self.button_wizard.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.button_wizard.sizePolicy().hasHeightForWidth()) + self.button_wizard.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setPointSize(8) + self.button_wizard.setFont(font) + self.button_wizard.setCheckable(False) + self.button_wizard.setFlat(False) + self.button_wizard.setObjectName("button_wizard") + self.verticalLayout_2.addWidget(self.button_wizard) + self.node_tree_view = QtWidgets.QTreeView(self.dockWidgetContents_2) + self.node_tree_view.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(3) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.node_tree_view.sizePolicy().hasHeightForWidth()) + self.node_tree_view.setSizePolicy(sizePolicy) + self.node_tree_view.setMinimumSize(QtCore.QSize(151, 0)) + self.node_tree_view.setAcceptDrops(True) + self.node_tree_view.setDragEnabled(True) + self.node_tree_view.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove) + self.node_tree_view.setDefaultDropAction(QtCore.Qt.MoveAction) + self.node_tree_view.setAlternatingRowColors(True) + self.node_tree_view.setIndentation(10) + self.node_tree_view.setHeaderHidden(True) + self.node_tree_view.setObjectName("node_tree_view") + self.verticalLayout_2.addWidget(self.node_tree_view) + self.node_tree.setWidget(self.dockWidgetContents_2) + MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(1), self.node_tree) + self.children_box = QtWidgets.QDockWidget(MainWindow) + self.children_box.setMinimumSize(QtCore.QSize(250, 83)) + self.children_box.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea|QtCore.Qt.RightDockWidgetArea) + self.children_box.setObjectName("children_box") + self.dockWidgetContents_3 = QtWidgets.QWidget() + self.dockWidgetContents_3.setObjectName("dockWidgetContents_3") + self.layout_box = QtWidgets.QVBoxLayout(self.dockWidgetContents_3) + self.layout_box.setContentsMargins(3, 3, 3, 3) + self.layout_box.setSpacing(3) + self.layout_box.setObjectName("layout_box") + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.layout_box.addItem(spacerItem) + self.children_box.setWidget(self.dockWidgetContents_3) + MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.children_box) + self.menuBar = QtWidgets.QMenuBar(MainWindow) + self.menuBar.setGeometry(QtCore.QRect(0, 0, 1115, 21)) + self.menuBar.setObjectName("menuBar") + self.menu_File = QtWidgets.QMenu(self.menuBar) + self.menu_File.setObjectName("menu_File") + self.menu_Recent_Files = QtWidgets.QMenu(self.menu_File) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap("../logos/logo_recent.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.menu_Recent_Files.setIcon(icon) + self.menu_Recent_Files.setObjectName("menu_Recent_Files") + self.menu_Tools = QtWidgets.QMenu(self.menuBar) + self.menu_Tools.setObjectName("menu_Tools") + self.menu_View = QtWidgets.QMenu(self.menuBar) + self.menu_View.setObjectName("menu_View") + self.menu_Help = QtWidgets.QMenu(self.menuBar) + self.menu_Help.setObjectName("menu_Help") + MainWindow.setMenuBar(self.menuBar) + self.action_Open = QtWidgets.QAction(MainWindow) + self.action_Open.setEnabled(True) + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap("../logos/logo_open_file.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.action_Open.setIcon(icon1) + self.action_Open.setShortcutContext(QtCore.Qt.WindowShortcut) + self.action_Open.setAutoRepeat(True) + self.action_Open.setObjectName("action_Open") + self.action_Save = QtWidgets.QAction(MainWindow) + icon2 = QtGui.QIcon() + icon2.addPixmap(QtGui.QPixmap("../logos/logo_floppy_disk.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.action_Save.setIcon(icon2) + self.action_Save.setShortcutContext(QtCore.Qt.WindowShortcut) + self.action_Save.setObjectName("action_Save") + self.actionO_ptions = QtWidgets.QAction(MainWindow) + icon3 = QtGui.QIcon() + icon3.addPixmap(QtGui.QPixmap("../logos/logo_gear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.actionO_ptions.setIcon(icon3) + self.actionO_ptions.setShortcutContext(QtCore.Qt.WindowShortcut) + self.actionO_ptions.setObjectName("actionO_ptions") + self.action_Refresh = QtWidgets.QAction(MainWindow) + icon4 = QtGui.QIcon() + icon4.addPixmap(QtGui.QPixmap("../logos/logo_refresh.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.action_Refresh.setIcon(icon4) + self.action_Refresh.setShortcutContext(QtCore.Qt.WindowShortcut) + self.action_Refresh.setObjectName("action_Refresh") + self.action_Delete = QtWidgets.QAction(MainWindow) + self.action_Delete.setEnabled(False) + icon5 = QtGui.QIcon() + icon5.addPixmap(QtGui.QPixmap("../logos/logo_cross.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.action_Delete.setIcon(icon5) + self.action_Delete.setShortcutContext(QtCore.Qt.WindowShortcut) + self.action_Delete.setObjectName("action_Delete") + self.action_About = QtWidgets.QAction(MainWindow) + self.action_About.setEnabled(True) + icon6 = QtGui.QIcon() + icon6.addPixmap(QtGui.QPixmap("../logos/logo_notepad.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.action_About.setIcon(icon6) + self.action_About.setShortcutContext(QtCore.Qt.WindowShortcut) + self.action_About.setObjectName("action_About") + self.actionHe_lp = QtWidgets.QAction(MainWindow) + icon7 = QtGui.QIcon() + icon7.addPixmap(QtGui.QPixmap("../logos/logo_info.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.actionHe_lp.setIcon(icon7) + self.actionHe_lp.setShortcutContext(QtCore.Qt.WindowShortcut) + self.actionHe_lp.setObjectName("actionHe_lp") + self.action_Object_Tree = QtWidgets.QAction(MainWindow) + self.action_Object_Tree.setCheckable(True) + self.action_Object_Tree.setChecked(True) + self.action_Object_Tree.setObjectName("action_Object_Tree") + self.action_Property_Editor = QtWidgets.QAction(MainWindow) + self.action_Property_Editor.setCheckable(True) + self.action_Property_Editor.setChecked(True) + self.action_Property_Editor.setObjectName("action_Property_Editor") + self.actionObject_Box = QtWidgets.QAction(MainWindow) + self.actionObject_Box.setCheckable(True) + self.actionObject_Box.setChecked(True) + self.actionObject_Box.setObjectName("actionObject_Box") + self.actionClear = QtWidgets.QAction(MainWindow) + icon8 = QtGui.QIcon() + icon8.addPixmap(QtGui.QPixmap("../logos/logo_clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.actionClear.setIcon(icon8) + self.actionClear.setObjectName("actionClear") + self.actionCopy = QtWidgets.QAction(MainWindow) + icon9 = QtGui.QIcon() + icon9.addPixmap(QtGui.QPixmap("../logos/logo_copy.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.actionCopy.setIcon(icon9) + self.actionCopy.setObjectName("actionCopy") + self.actionPaste = QtWidgets.QAction(MainWindow) + self.actionPaste.setEnabled(False) + icon10 = QtGui.QIcon() + icon10.addPixmap(QtGui.QPixmap("../logos/logo_paste.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.actionPaste.setIcon(icon10) + self.actionPaste.setObjectName("actionPaste") + self.actionUndo = QtWidgets.QAction(MainWindow) + self.actionUndo.setEnabled(False) + icon11 = QtGui.QIcon() + icon11.addPixmap(QtGui.QPixmap("../logos/logo_undo.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.actionUndo.setIcon(icon11) + self.actionUndo.setShortcutContext(QtCore.Qt.WindowShortcut) + self.actionUndo.setObjectName("actionUndo") + self.actionRedo = QtWidgets.QAction(MainWindow) + self.actionRedo.setEnabled(False) + icon12 = QtGui.QIcon() + icon12.addPixmap(QtGui.QPixmap("../logos/logo_redo.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.actionRedo.setIcon(icon12) + self.actionRedo.setObjectName("actionRedo") + self.actionExpand_All = QtWidgets.QAction(MainWindow) + icon13 = QtGui.QIcon() + icon13.addPixmap(QtGui.QPixmap("../logos/logo_expand.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.actionExpand_All.setIcon(icon13) + self.actionExpand_All.setObjectName("actionExpand_All") + self.actionCollapse_All = QtWidgets.QAction(MainWindow) + icon14 = QtGui.QIcon() + icon14.addPixmap(QtGui.QPixmap("../logos/logo_collapse.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.actionCollapse_All.setIcon(icon14) + self.actionCollapse_All.setObjectName("actionCollapse_All") + self.menu_Recent_Files.addAction(self.actionClear) + self.menu_File.addAction(self.action_Open) + self.menu_File.addAction(self.action_Save) + self.menu_File.addSeparator() + self.menu_File.addAction(self.menu_Recent_Files.menuAction()) + self.menu_File.addSeparator() + self.menu_File.addAction(self.actionO_ptions) + self.menu_Tools.addAction(self.actionExpand_All) + self.menu_Tools.addAction(self.actionCollapse_All) + self.menu_Tools.addSeparator() + self.menu_Tools.addAction(self.action_Refresh) + self.menu_Tools.addSeparator() + self.menu_Tools.addAction(self.action_Delete) + self.menu_Tools.addSeparator() + self.menu_Tools.addAction(self.actionCopy) + self.menu_Tools.addAction(self.actionPaste) + self.menu_Tools.addSeparator() + self.menu_Tools.addAction(self.actionUndo) + self.menu_Tools.addAction(self.actionRedo) + self.menu_View.addAction(self.action_Object_Tree) + self.menu_View.addAction(self.action_Property_Editor) + self.menu_View.addAction(self.actionObject_Box) + self.menu_Help.addAction(self.action_About) + self.menu_Help.addAction(self.actionHe_lp) + self.menuBar.addAction(self.menu_File.menuAction()) + self.menuBar.addAction(self.menu_Tools.menuAction()) + self.menuBar.addAction(self.menu_View.menuAction()) + self.menuBar.addAction(self.menu_Help.menuAction()) + + self.retranslateUi(MainWindow) + self.tabWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "FOMOD Designer")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabWidgetPage1), _translate("MainWindow", "Preview")) + self.label.setText(_translate("MainWindow", "Generated XML Code")) + self.xml_code_browser.setPlaceholderText(_translate("MainWindow", "Click a node to see the generated XML code here.")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabWidgetPage2), _translate("MainWindow", "XML Preview")) + self.property_editor.setStatusTip(_translate("MainWindow", "A list of all the properties and the means to edit them.")) + self.property_editor.setWindowTitle(_translate("MainWindow", "Property Editor")) + self.node_tree.setStatusTip(_translate("MainWindow", "The tree containing all the existing nodes.")) + self.node_tree.setWindowTitle(_translate("MainWindow", "Node Tree")) + self.button_wizard.setText(_translate("MainWindow", "Start Wizard")) + self.children_box.setStatusTip(_translate("MainWindow", "A list with the possible nodes to add.")) + self.children_box.setWindowTitle(_translate("MainWindow", "Children Box")) + self.menu_File.setTitle(_translate("MainWindow", "&File")) + self.menu_Recent_Files.setStatusTip(_translate("MainWindow", "Your recent files in an easy-to-open list.")) + self.menu_Recent_Files.setTitle(_translate("MainWindow", "&Recent Files")) + self.menu_Tools.setTitle(_translate("MainWindow", "&Tools")) + self.menu_View.setTitle(_translate("MainWindow", "&View")) + self.menu_Help.setTitle(_translate("MainWindow", "&Help")) + self.action_Open.setText(_translate("MainWindow", "&New/&Open")) + self.action_Open.setToolTip(_translate("MainWindow", "New/Open")) + self.action_Open.setStatusTip(_translate("MainWindow", "Select a folder to open or create an installer there.")) + self.action_Open.setShortcut(_translate("MainWindow", "Ctrl+O")) + self.action_Save.setText(_translate("MainWindow", "&Save")) + self.action_Save.setStatusTip(_translate("MainWindow", "Save the current installer.")) + self.action_Save.setShortcut(_translate("MainWindow", "Ctrl+S")) + self.actionO_ptions.setText(_translate("MainWindow", "Settings")) + self.actionO_ptions.setIconText(_translate("MainWindow", "Settings")) + self.actionO_ptions.setToolTip(_translate("MainWindow", "Settings")) + self.actionO_ptions.setStatusTip(_translate("MainWindow", "Open up the settings menu")) + self.actionO_ptions.setShortcut(_translate("MainWindow", "Ctrl+P")) + self.action_Refresh.setText(_translate("MainWindow", "&Refresh")) + self.action_Refresh.setStatusTip(_translate("MainWindow", "Refresh the previews.")) + self.action_Refresh.setShortcut(_translate("MainWindow", "Ctrl+R")) + self.action_Delete.setText(_translate("MainWindow", "&Delete")) + self.action_Delete.setStatusTip(_translate("MainWindow", "Delete the currently selected node.")) + self.action_Delete.setShortcut(_translate("MainWindow", "Del")) + self.action_About.setText(_translate("MainWindow", "&About")) + self.action_About.setIconText(_translate("MainWindow", "About")) + self.action_About.setToolTip(_translate("MainWindow", "About")) + self.action_About.setStatusTip(_translate("MainWindow", "Who made this and license details.")) + self.action_About.setShortcut(_translate("MainWindow", "Ctrl+A")) + self.actionHe_lp.setText(_translate("MainWindow", "He&lp")) + self.actionHe_lp.setStatusTip(_translate("MainWindow", "Haaaaaalp!")) + self.actionHe_lp.setShortcut(_translate("MainWindow", "Ctrl+H")) + self.action_Object_Tree.setText(_translate("MainWindow", "Object &Tree")) + self.action_Object_Tree.setStatusTip(_translate("MainWindow", "Toggle the visibility of the Object Tree.")) + self.action_Property_Editor.setText(_translate("MainWindow", "&Property Editor")) + self.action_Property_Editor.setStatusTip(_translate("MainWindow", "Toggle the visibility of the Property Editor.")) + self.actionObject_Box.setText(_translate("MainWindow", "Object &Box")) + self.actionObject_Box.setStatusTip(_translate("MainWindow", "Toggle the visibility of the Object Box.")) + self.actionClear.setText(_translate("MainWindow", "Clear")) + self.actionClear.setStatusTip(_translate("MainWindow", "Clear all the recent files.")) + self.actionCopy.setText(_translate("MainWindow", "Copy")) + self.actionCopy.setShortcut(_translate("MainWindow", "Ctrl+C")) + self.actionPaste.setText(_translate("MainWindow", "Paste")) + self.actionPaste.setShortcut(_translate("MainWindow", "Ctrl+V")) + self.actionUndo.setText(_translate("MainWindow", "Undo")) + self.actionUndo.setShortcut(_translate("MainWindow", "Ctrl+Z")) + self.actionRedo.setText(_translate("MainWindow", "Redo")) + self.actionRedo.setShortcut(_translate("MainWindow", "Ctrl+Shift+Z")) + self.actionExpand_All.setText(_translate("MainWindow", "Expand All")) + self.actionExpand_All.setShortcut(_translate("MainWindow", "Ctrl+*")) + self.actionCollapse_All.setText(_translate("MainWindow", "Collapse All")) + self.actionCollapse_All.setShortcut(_translate("MainWindow", "Ctrl+.")) + diff --git a/designer/ui_templates/window_plaintexteditor.py b/designer/ui_templates/window_plaintexteditor.py new file mode 100644 index 0000000..48689d9 --- /dev/null +++ b/designer/ui_templates/window_plaintexteditor.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/window_plaintexteditor.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(247, 195) + self.verticalLayout = QtWidgets.QVBoxLayout(Dialog) + self.verticalLayout.setObjectName("verticalLayout") + self.edit_text = QtWidgets.QTextEdit(Dialog) + self.edit_text.setObjectName("edit_text") + self.verticalLayout.addWidget(self.edit_text) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setCenterButtons(True) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Text Editor")) + diff --git a/designer/ui_templates/window_settings.py b/designer/ui_templates/window_settings.py new file mode 100644 index 0000000..db2f4a6 --- /dev/null +++ b/designer/ui_templates/window_settings.py @@ -0,0 +1,804 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/window_settings.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.setWindowModality(QtCore.Qt.NonModal) + Dialog.setEnabled(True) + Dialog.resize(565, 396) + Dialog.setFocusPolicy(QtCore.Qt.StrongFocus) + Dialog.setContextMenuPolicy(QtCore.Qt.NoContextMenu) + Dialog.setModal(False) + self.verticalLayout_8 = QtWidgets.QVBoxLayout(Dialog) + self.verticalLayout_8.setObjectName("verticalLayout_8") + self.tabWidget = QtWidgets.QTabWidget(Dialog) + self.tabWidget.setTabPosition(QtWidgets.QTabWidget.North) + self.tabWidget.setTabShape(QtWidgets.QTabWidget.Rounded) + self.tabWidget.setElideMode(QtCore.Qt.ElideNone) + self.tabWidget.setTabBarAutoHide(False) + self.tabWidget.setObjectName("tabWidget") + self.tab = QtWidgets.QWidget() + self.tab.setObjectName("tab") + self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.tab) + self.verticalLayout_7.setObjectName("verticalLayout_7") + self.check_intro = QtWidgets.QCheckBox(self.tab) + self.check_intro.setObjectName("check_intro") + self.verticalLayout_7.addWidget(self.check_intro) + self.line = QtWidgets.QFrame(self.tab) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.verticalLayout_7.addWidget(self.line) + self.check_advanced = QtWidgets.QCheckBox(self.tab) + self.check_advanced.setEnabled(False) + self.check_advanced.setObjectName("check_advanced") + self.verticalLayout_7.addWidget(self.check_advanced) + self.line_10 = QtWidgets.QFrame(self.tab) + self.line_10.setFrameShape(QtWidgets.QFrame.HLine) + self.line_10.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_10.setObjectName("line_10") + self.verticalLayout_7.addWidget(self.line_10) + self.check_tutorial = QtWidgets.QCheckBox(self.tab) + self.check_tutorial.setObjectName("check_tutorial") + self.verticalLayout_7.addWidget(self.check_tutorial) + self.line_2 = QtWidgets.QFrame(self.tab) + self.line_2.setFrameShape(QtWidgets.QFrame.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.verticalLayout_7.addWidget(self.line_2) + self.horizontalLayout_6 = QtWidgets.QHBoxLayout() + self.horizontalLayout_6.setObjectName("horizontalLayout_6") + self.label = QtWidgets.QLabel(self.tab) + self.label.setObjectName("label") + self.horizontalLayout_6.addWidget(self.label) + self.combo_code_refresh = QtWidgets.QComboBox(self.tab) + self.combo_code_refresh.setObjectName("combo_code_refresh") + self.combo_code_refresh.addItem("") + self.combo_code_refresh.addItem("") + self.combo_code_refresh.addItem("") + self.combo_code_refresh.addItem("") + self.horizontalLayout_6.addWidget(self.combo_code_refresh) + self.verticalLayout_7.addLayout(self.horizontalLayout_6) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_7.addItem(spacerItem) + self.check_intro.raise_() + self.check_advanced.raise_() + self.line.raise_() + self.line_2.raise_() + self.check_tutorial.raise_() + self.line_10.raise_() + self.tabWidget.addTab(self.tab, "") + self.tab_5 = QtWidgets.QWidget() + self.tab_5.setObjectName("tab_5") + self.verticalLayout_10 = QtWidgets.QVBoxLayout(self.tab_5) + self.verticalLayout_10.setObjectName("verticalLayout_10") + self.label_9 = QtWidgets.QLabel(self.tab_5) + font = QtGui.QFont() + font.setPointSize(10) + font.setBold(True) + font.setWeight(75) + self.label_9.setFont(font) + self.label_9.setObjectName("label_9") + self.verticalLayout_10.addWidget(self.label_9) + self.horizontalLayout_7 = QtWidgets.QHBoxLayout() + self.horizontalLayout_7.setObjectName("horizontalLayout_7") + self.label_10 = QtWidgets.QLabel(self.tab_5) + self.label_10.setObjectName("label_10") + self.horizontalLayout_7.addWidget(self.label_10) + self.button_colour_required = QtWidgets.QPushButton(self.tab_5) + self.button_colour_required.setMaximumSize(QtCore.QSize(40, 16777215)) + self.button_colour_required.setText("") + self.button_colour_required.setObjectName("button_colour_required") + self.horizontalLayout_7.addWidget(self.button_colour_required) + self.button_colour_reset_required = QtWidgets.QPushButton(self.tab_5) + self.button_colour_reset_required.setObjectName("button_colour_reset_required") + self.horizontalLayout_7.addWidget(self.button_colour_reset_required) + self.verticalLayout_10.addLayout(self.horizontalLayout_7) + self.horizontalLayout_8 = QtWidgets.QHBoxLayout() + self.horizontalLayout_8.setObjectName("horizontalLayout_8") + self.label_11 = QtWidgets.QLabel(self.tab_5) + self.label_11.setObjectName("label_11") + self.horizontalLayout_8.addWidget(self.label_11) + self.button_colour_atleastone = QtWidgets.QPushButton(self.tab_5) + self.button_colour_atleastone.setMaximumSize(QtCore.QSize(40, 16777215)) + self.button_colour_atleastone.setText("") + self.button_colour_atleastone.setObjectName("button_colour_atleastone") + self.horizontalLayout_8.addWidget(self.button_colour_atleastone) + self.button_colour_reset_atleastone = QtWidgets.QPushButton(self.tab_5) + self.button_colour_reset_atleastone.setObjectName("button_colour_reset_atleastone") + self.horizontalLayout_8.addWidget(self.button_colour_reset_atleastone) + self.verticalLayout_10.addLayout(self.horizontalLayout_8) + self.horizontalLayout_9 = QtWidgets.QHBoxLayout() + self.horizontalLayout_9.setObjectName("horizontalLayout_9") + self.label_12 = QtWidgets.QLabel(self.tab_5) + self.label_12.setObjectName("label_12") + self.horizontalLayout_9.addWidget(self.label_12) + self.button_colour_either = QtWidgets.QPushButton(self.tab_5) + self.button_colour_either.setMaximumSize(QtCore.QSize(40, 16777215)) + self.button_colour_either.setText("") + self.button_colour_either.setObjectName("button_colour_either") + self.horizontalLayout_9.addWidget(self.button_colour_either) + self.button_colour_reset_either = QtWidgets.QPushButton(self.tab_5) + self.button_colour_reset_either.setObjectName("button_colour_reset_either") + self.horizontalLayout_9.addWidget(self.button_colour_reset_either) + self.verticalLayout_10.addLayout(self.horizontalLayout_9) + self.line_9 = QtWidgets.QFrame(self.tab_5) + self.line_9.setMidLineWidth(0) + self.line_9.setFrameShape(QtWidgets.QFrame.HLine) + self.line_9.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_9.setObjectName("line_9") + self.verticalLayout_10.addWidget(self.line_9) + self.horizontalLayout_14 = QtWidgets.QHBoxLayout() + self.horizontalLayout_14.setObjectName("horizontalLayout_14") + self.label_14 = QtWidgets.QLabel(self.tab_5) + self.label_14.setMidLineWidth(0) + self.label_14.setObjectName("label_14") + self.horizontalLayout_14.addWidget(self.label_14) + self.combo_style = QtWidgets.QComboBox(self.tab_5) + self.combo_style.setObjectName("combo_style") + self.combo_style.addItem("") + self.combo_style.addItem("") + self.combo_style.addItem("") + self.horizontalLayout_14.addWidget(self.combo_style) + self.verticalLayout_10.addLayout(self.horizontalLayout_14) + self.widget_warning_style = QtWidgets.QWidget(self.tab_5) + self.widget_warning_style.setObjectName("widget_warning_style") + self.horizontalLayout_16 = QtWidgets.QHBoxLayout(self.widget_warning_style) + self.horizontalLayout_16.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_16.setObjectName("horizontalLayout_16") + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_16.addItem(spacerItem1) + self.label_warning_style = QtWidgets.QLabel(self.widget_warning_style) + self.label_warning_style.setMaximumSize(QtCore.QSize(20, 20)) + self.label_warning_style.setText("") + self.label_warning_style.setPixmap(QtGui.QPixmap("../logos/logo_danger.png")) + self.label_warning_style.setScaledContents(True) + self.label_warning_style.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_warning_style.setWordWrap(False) + self.label_warning_style.setObjectName("label_warning_style") + self.horizontalLayout_16.addWidget(self.label_warning_style) + self.label_13 = QtWidgets.QLabel(self.widget_warning_style) + self.label_13.setScaledContents(True) + self.label_13.setObjectName("label_13") + self.horizontalLayout_16.addWidget(self.label_13) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_16.addItem(spacerItem2) + self.verticalLayout_10.addWidget(self.widget_warning_style) + self.line_15 = QtWidgets.QFrame(self.tab_5) + self.line_15.setMidLineWidth(0) + self.line_15.setFrameShape(QtWidgets.QFrame.HLine) + self.line_15.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_15.setObjectName("line_15") + self.verticalLayout_10.addWidget(self.line_15) + self.horizontalLayout_15 = QtWidgets.QHBoxLayout() + self.horizontalLayout_15.setObjectName("horizontalLayout_15") + self.label_16 = QtWidgets.QLabel(self.tab_5) + self.label_16.setObjectName("label_16") + self.horizontalLayout_15.addWidget(self.label_16) + self.combo_palette = QtWidgets.QComboBox(self.tab_5) + self.combo_palette.setObjectName("combo_palette") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.combo_palette.addItem("") + self.horizontalLayout_15.addWidget(self.combo_palette) + self.verticalLayout_10.addLayout(self.horizontalLayout_15) + self.widget_warning_palette = QtWidgets.QWidget(self.tab_5) + self.widget_warning_palette.setObjectName("widget_warning_palette") + self.horizontalLayout_17 = QtWidgets.QHBoxLayout(self.widget_warning_palette) + self.horizontalLayout_17.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_17.setObjectName("horizontalLayout_17") + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_17.addItem(spacerItem3) + self.label_warning_palette = QtWidgets.QLabel(self.widget_warning_palette) + self.label_warning_palette.setMaximumSize(QtCore.QSize(20, 20)) + self.label_warning_palette.setText("") + self.label_warning_palette.setPixmap(QtGui.QPixmap("../logos/logo_danger.png")) + self.label_warning_palette.setScaledContents(True) + self.label_warning_palette.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_warning_palette.setWordWrap(False) + self.label_warning_palette.setObjectName("label_warning_palette") + self.horizontalLayout_17.addWidget(self.label_warning_palette) + self.label_15 = QtWidgets.QLabel(self.widget_warning_palette) + self.label_15.setScaledContents(True) + self.label_15.setObjectName("label_15") + self.horizontalLayout_17.addWidget(self.label_15) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_17.addItem(spacerItem4) + self.verticalLayout_10.addWidget(self.widget_warning_palette) + spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_10.addItem(spacerItem5) + self.tabWidget.addTab(self.tab_5, "") + self.tab_3 = QtWidgets.QWidget() + self.tab_3.setObjectName("tab_3") + self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.tab_3) + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.check_valid_load = QtWidgets.QCheckBox(self.tab_3) + self.check_valid_load.setChecked(True) + self.check_valid_load.setObjectName("check_valid_load") + self.verticalLayout.addWidget(self.check_valid_load) + self.horizontalLayout_5 = QtWidgets.QHBoxLayout() + self.horizontalLayout_5.setObjectName("horizontalLayout_5") + spacerItem6 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_5.addItem(spacerItem6) + self.check_valid_load_ignore = QtWidgets.QCheckBox(self.tab_3) + self.check_valid_load_ignore.setEnabled(True) + self.check_valid_load_ignore.setObjectName("check_valid_load_ignore") + self.horizontalLayout_5.addWidget(self.check_valid_load_ignore) + self.horizontalLayout_5.setStretch(1, 9) + self.verticalLayout.addLayout(self.horizontalLayout_5) + self.verticalLayout_6.addLayout(self.verticalLayout) + self.line_7 = QtWidgets.QFrame(self.tab_3) + self.line_7.setFrameShape(QtWidgets.QFrame.HLine) + self.line_7.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_7.setObjectName("line_7") + self.verticalLayout_6.addWidget(self.line_7) + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.check_warn_load = QtWidgets.QCheckBox(self.tab_3) + self.check_warn_load.setChecked(True) + self.check_warn_load.setObjectName("check_warn_load") + self.verticalLayout_2.addWidget(self.check_warn_load) + self.horizontalLayout_4 = QtWidgets.QHBoxLayout() + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + spacerItem7 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_4.addItem(spacerItem7) + self.check_warn_load_ignore = QtWidgets.QCheckBox(self.tab_3) + self.check_warn_load_ignore.setEnabled(True) + self.check_warn_load_ignore.setObjectName("check_warn_load_ignore") + self.horizontalLayout_4.addWidget(self.check_warn_load_ignore) + self.horizontalLayout_4.setStretch(1, 9) + self.verticalLayout_2.addLayout(self.horizontalLayout_4) + self.verticalLayout_6.addLayout(self.verticalLayout_2) + spacerItem8 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_6.addItem(spacerItem8) + self.tabWidget.addTab(self.tab_3, "") + self.tab_4 = QtWidgets.QWidget() + self.tab_4.setObjectName("tab_4") + self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.tab_4) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.verticalLayout_4 = QtWidgets.QVBoxLayout() + self.verticalLayout_4.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.check_valid_save = QtWidgets.QCheckBox(self.tab_4) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.check_valid_save.sizePolicy().hasHeightForWidth()) + self.check_valid_save.setSizePolicy(sizePolicy) + self.check_valid_save.setChecked(True) + self.check_valid_save.setObjectName("check_valid_save") + self.verticalLayout_4.addWidget(self.check_valid_save) + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize) + self.horizontalLayout_3.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout_3.setSpacing(6) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + spacerItem9 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_3.addItem(spacerItem9) + self.check_valid_save_ignore = QtWidgets.QCheckBox(self.tab_4) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.check_valid_save_ignore.sizePolicy().hasHeightForWidth()) + self.check_valid_save_ignore.setSizePolicy(sizePolicy) + self.check_valid_save_ignore.setObjectName("check_valid_save_ignore") + self.horizontalLayout_3.addWidget(self.check_valid_save_ignore) + self.horizontalLayout_3.setStretch(1, 9) + self.verticalLayout_4.addLayout(self.horizontalLayout_3) + self.verticalLayout_5.addLayout(self.verticalLayout_4) + self.line_8 = QtWidgets.QFrame(self.tab_4) + self.line_8.setFrameShape(QtWidgets.QFrame.HLine) + self.line_8.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_8.setObjectName("line_8") + self.verticalLayout_5.addWidget(self.line_8) + self.verticalLayout_3 = QtWidgets.QVBoxLayout() + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.check_warn_save = QtWidgets.QCheckBox(self.tab_4) + self.check_warn_save.setChecked(True) + self.check_warn_save.setObjectName("check_warn_save") + self.verticalLayout_3.addWidget(self.check_warn_save) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + spacerItem10 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem10) + self.check_warn_save_ignore = QtWidgets.QCheckBox(self.tab_4) + self.check_warn_save_ignore.setEnabled(True) + self.check_warn_save_ignore.setObjectName("check_warn_save_ignore") + self.horizontalLayout_2.addWidget(self.check_warn_save_ignore) + self.horizontalLayout_2.setStretch(1, 9) + self.verticalLayout_3.addLayout(self.horizontalLayout_2) + self.verticalLayout_5.addLayout(self.verticalLayout_3) + spacerItem11 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_5.addItem(spacerItem11) + self.tabWidget.addTab(self.tab_4, "") + self.tab_2 = QtWidgets.QWidget() + self.tab_2.setObjectName("tab_2") + self.verticalLayout_9 = QtWidgets.QVBoxLayout(self.tab_2) + self.verticalLayout_9.setObjectName("verticalLayout_9") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.label_4 = QtWidgets.QLabel(self.tab_2) + font = QtGui.QFont() + font.setPointSize(10) + font.setBold(True) + font.setWeight(75) + self.label_4.setFont(font) + self.label_4.setObjectName("label_4") + self.horizontalLayout.addWidget(self.label_4) + self.label_3 = QtWidgets.QLabel(self.tab_2) + font = QtGui.QFont() + font.setPointSize(10) + font.setBold(True) + font.setWeight(75) + self.label_3.setFont(font) + self.label_3.setObjectName("label_3") + self.horizontalLayout.addWidget(self.label_3) + self.label_5 = QtWidgets.QLabel(self.tab_2) + font = QtGui.QFont() + font.setPointSize(10) + font.setBold(True) + font.setWeight(75) + self.label_5.setFont(font) + self.label_5.setObjectName("label_5") + self.horizontalLayout.addWidget(self.label_5) + self.verticalLayout_9.addLayout(self.horizontalLayout) + self.line_3 = QtWidgets.QFrame(self.tab_2) + self.line_3.setLineWidth(1) + self.line_3.setMidLineWidth(1) + self.line_3.setFrameShape(QtWidgets.QFrame.HLine) + self.line_3.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_3.setObjectName("line_3") + self.verticalLayout_9.addWidget(self.line_3) + self.horizontalLayout_10 = QtWidgets.QHBoxLayout() + self.horizontalLayout_10.setObjectName("horizontalLayout_10") + self.check_installSteps = QtWidgets.QCheckBox(self.tab_2) + self.check_installSteps.setChecked(True) + self.check_installSteps.setObjectName("check_installSteps") + self.horizontalLayout_10.addWidget(self.check_installSteps) + self.label_2 = QtWidgets.QLabel(self.tab_2) + self.label_2.setObjectName("label_2") + self.horizontalLayout_10.addWidget(self.label_2) + self.combo_installSteps = QtWidgets.QComboBox(self.tab_2) + self.combo_installSteps.setObjectName("combo_installSteps") + self.combo_installSteps.addItem("") + self.combo_installSteps.addItem("") + self.combo_installSteps.addItem("") + self.horizontalLayout_10.addWidget(self.combo_installSteps) + self.verticalLayout_9.addLayout(self.horizontalLayout_10) + self.line_4 = QtWidgets.QFrame(self.tab_2) + self.line_4.setFrameShape(QtWidgets.QFrame.HLine) + self.line_4.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_4.setObjectName("line_4") + self.verticalLayout_9.addWidget(self.line_4) + self.horizontalLayout_11 = QtWidgets.QHBoxLayout() + self.horizontalLayout_11.setObjectName("horizontalLayout_11") + self.check_optionalFileGroups = QtWidgets.QCheckBox(self.tab_2) + self.check_optionalFileGroups.setChecked(True) + self.check_optionalFileGroups.setObjectName("check_optionalFileGroups") + self.horizontalLayout_11.addWidget(self.check_optionalFileGroups) + self.label_6 = QtWidgets.QLabel(self.tab_2) + self.label_6.setObjectName("label_6") + self.horizontalLayout_11.addWidget(self.label_6) + self.combo_optionalFileGroups = QtWidgets.QComboBox(self.tab_2) + self.combo_optionalFileGroups.setObjectName("combo_optionalFileGroups") + self.combo_optionalFileGroups.addItem("") + self.combo_optionalFileGroups.addItem("") + self.combo_optionalFileGroups.addItem("") + self.horizontalLayout_11.addWidget(self.combo_optionalFileGroups) + self.verticalLayout_9.addLayout(self.horizontalLayout_11) + self.line_5 = QtWidgets.QFrame(self.tab_2) + self.line_5.setFrameShape(QtWidgets.QFrame.HLine) + self.line_5.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_5.setObjectName("line_5") + self.verticalLayout_9.addWidget(self.line_5) + self.horizontalLayout_12 = QtWidgets.QHBoxLayout() + self.horizontalLayout_12.setObjectName("horizontalLayout_12") + self.check_type = QtWidgets.QCheckBox(self.tab_2) + self.check_type.setChecked(True) + self.check_type.setObjectName("check_type") + self.horizontalLayout_12.addWidget(self.check_type) + self.label_7 = QtWidgets.QLabel(self.tab_2) + self.label_7.setObjectName("label_7") + self.horizontalLayout_12.addWidget(self.label_7) + self.combo_type = QtWidgets.QComboBox(self.tab_2) + self.combo_type.setObjectName("combo_type") + self.combo_type.addItem("") + self.combo_type.addItem("") + self.combo_type.addItem("") + self.combo_type.addItem("") + self.combo_type.addItem("") + self.horizontalLayout_12.addWidget(self.combo_type) + self.verticalLayout_9.addLayout(self.horizontalLayout_12) + self.line_6 = QtWidgets.QFrame(self.tab_2) + self.line_6.setFrameShape(QtWidgets.QFrame.HLine) + self.line_6.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_6.setObjectName("line_6") + self.verticalLayout_9.addWidget(self.line_6) + self.horizontalLayout_13 = QtWidgets.QHBoxLayout() + self.horizontalLayout_13.setObjectName("horizontalLayout_13") + self.check_defaultType = QtWidgets.QCheckBox(self.tab_2) + self.check_defaultType.setChecked(True) + self.check_defaultType.setObjectName("check_defaultType") + self.horizontalLayout_13.addWidget(self.check_defaultType) + self.label_8 = QtWidgets.QLabel(self.tab_2) + self.label_8.setObjectName("label_8") + self.horizontalLayout_13.addWidget(self.label_8) + self.combo_defaultType = QtWidgets.QComboBox(self.tab_2) + self.combo_defaultType.setObjectName("combo_defaultType") + self.combo_defaultType.addItem("") + self.combo_defaultType.addItem("") + self.combo_defaultType.addItem("") + self.combo_defaultType.addItem("") + self.combo_defaultType.addItem("") + self.horizontalLayout_13.addWidget(self.combo_defaultType) + self.verticalLayout_9.addLayout(self.horizontalLayout_13) + spacerItem12 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_9.addItem(spacerItem12) + self.tabWidget.addTab(self.tab_2, "") + self.verticalLayout_8.addWidget(self.tabWidget) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout_8.addWidget(self.buttonBox) + + self.retranslateUi(Dialog) + self.tabWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Settings")) + self.check_intro.setText(_translate("Dialog", "Show intro window at statup.")) + self.check_advanced.setText(_translate("Dialog", "Show the Advanced View at startup.")) + self.check_tutorial.setText(_translate("Dialog", "Show tutorial at startup.")) + self.label.setText(_translate("Dialog", "Preview Refresh Rate")) + self.combo_code_refresh.setItemText(0, _translate("Dialog", "Never")) + self.combo_code_refresh.setItemText(1, _translate("Dialog", "On Refresh")) + self.combo_code_refresh.setItemText(2, _translate("Dialog", "On Node Select")) + self.combo_code_refresh.setItemText(3, _translate("Dialog", "On Property Editing")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("Dialog", "General")) + self.label_9.setText(_translate("Dialog", "Special Button Colours")) + self.label_10.setText(_translate("Dialog", "Required")) + self.button_colour_reset_required.setText(_translate("Dialog", "Reset to Default")) + self.label_11.setText(_translate("Dialog", "At Least One")) + self.button_colour_reset_atleastone.setText(_translate("Dialog", "Reset to Default")) + self.label_12.setText(_translate("Dialog", "Either")) + self.button_colour_reset_either.setText(_translate("Dialog", "Reset to Default")) + self.label_14.setText(_translate("Dialog", "Style")) + self.combo_style.setItemText(0, _translate("Dialog", "Default")) + self.combo_style.setItemText(1, _translate("Dialog", "Windows")) + self.combo_style.setItemText(2, _translate("Dialog", "Fusion")) + self.label_13.setText(_translate("Dialog", "This setting requires a restart to take effect.")) + self.label_16.setText(_translate("Dialog", "Palette")) + self.combo_palette.setItemText(0, _translate("Dialog", "Default")) + self.combo_palette.setItemText(1, _translate("Dialog", "aliceblue")) + self.combo_palette.setItemText(2, _translate("Dialog", "antiquewhite")) + self.combo_palette.setItemText(3, _translate("Dialog", "aqua")) + self.combo_palette.setItemText(4, _translate("Dialog", "aquamarine")) + self.combo_palette.setItemText(5, _translate("Dialog", "azure")) + self.combo_palette.setItemText(6, _translate("Dialog", "beige")) + self.combo_palette.setItemText(7, _translate("Dialog", "bisque")) + self.combo_palette.setItemText(8, _translate("Dialog", "black")) + self.combo_palette.setItemText(9, _translate("Dialog", "blanchedalmond")) + self.combo_palette.setItemText(10, _translate("Dialog", "blue")) + self.combo_palette.setItemText(11, _translate("Dialog", "blueviolet")) + self.combo_palette.setItemText(12, _translate("Dialog", "brown")) + self.combo_palette.setItemText(13, _translate("Dialog", "burlywood")) + self.combo_palette.setItemText(14, _translate("Dialog", "cadetblue")) + self.combo_palette.setItemText(15, _translate("Dialog", "chartreuse")) + self.combo_palette.setItemText(16, _translate("Dialog", "chocolate")) + self.combo_palette.setItemText(17, _translate("Dialog", "coral")) + self.combo_palette.setItemText(18, _translate("Dialog", "cornflowerblue")) + self.combo_palette.setItemText(19, _translate("Dialog", "cornsilk")) + self.combo_palette.setItemText(20, _translate("Dialog", "crimson")) + self.combo_palette.setItemText(21, _translate("Dialog", "cyan")) + self.combo_palette.setItemText(22, _translate("Dialog", "darkblue")) + self.combo_palette.setItemText(23, _translate("Dialog", "darkcyan")) + self.combo_palette.setItemText(24, _translate("Dialog", "darkgoldenrod")) + self.combo_palette.setItemText(25, _translate("Dialog", "darkgray")) + self.combo_palette.setItemText(26, _translate("Dialog", "darkgreen")) + self.combo_palette.setItemText(27, _translate("Dialog", "darkgrey")) + self.combo_palette.setItemText(28, _translate("Dialog", "darkkhaki")) + self.combo_palette.setItemText(29, _translate("Dialog", "darkmagenta")) + self.combo_palette.setItemText(30, _translate("Dialog", "darkolivegreen")) + self.combo_palette.setItemText(31, _translate("Dialog", "darkorange")) + self.combo_palette.setItemText(32, _translate("Dialog", "darkorchid")) + self.combo_palette.setItemText(33, _translate("Dialog", "darkred")) + self.combo_palette.setItemText(34, _translate("Dialog", "darksalmon")) + self.combo_palette.setItemText(35, _translate("Dialog", "darkseagreen")) + self.combo_palette.setItemText(36, _translate("Dialog", "darkslateblue")) + self.combo_palette.setItemText(37, _translate("Dialog", "darkslategray")) + self.combo_palette.setItemText(38, _translate("Dialog", "darkturquoise")) + self.combo_palette.setItemText(39, _translate("Dialog", "darkviolet")) + self.combo_palette.setItemText(40, _translate("Dialog", "deeppink")) + self.combo_palette.setItemText(41, _translate("Dialog", "deepskyblue")) + self.combo_palette.setItemText(42, _translate("Dialog", "dimgray")) + self.combo_palette.setItemText(43, _translate("Dialog", "dodgerblue")) + self.combo_palette.setItemText(44, _translate("Dialog", "firebrick")) + self.combo_palette.setItemText(45, _translate("Dialog", "floralwhite")) + self.combo_palette.setItemText(46, _translate("Dialog", "forestgreen")) + self.combo_palette.setItemText(47, _translate("Dialog", "fuchsia")) + self.combo_palette.setItemText(48, _translate("Dialog", "gainsboro")) + self.combo_palette.setItemText(49, _translate("Dialog", "ghostwhite")) + self.combo_palette.setItemText(50, _translate("Dialog", "gold")) + self.combo_palette.setItemText(51, _translate("Dialog", "goldenrod")) + self.combo_palette.setItemText(52, _translate("Dialog", "gray")) + self.combo_palette.setItemText(53, _translate("Dialog", "green")) + self.combo_palette.setItemText(54, _translate("Dialog", "greenyellow")) + self.combo_palette.setItemText(55, _translate("Dialog", "honeydew")) + self.combo_palette.setItemText(56, _translate("Dialog", "hotpink")) + self.combo_palette.setItemText(57, _translate("Dialog", "indianred")) + self.combo_palette.setItemText(58, _translate("Dialog", "indigo")) + self.combo_palette.setItemText(59, _translate("Dialog", "ivory")) + self.combo_palette.setItemText(60, _translate("Dialog", "khaki")) + self.combo_palette.setItemText(61, _translate("Dialog", "lavender")) + self.combo_palette.setItemText(62, _translate("Dialog", "lavenderblush")) + self.combo_palette.setItemText(63, _translate("Dialog", "lawngreen")) + self.combo_palette.setItemText(64, _translate("Dialog", "lemonchiffon")) + self.combo_palette.setItemText(65, _translate("Dialog", "lightblue")) + self.combo_palette.setItemText(66, _translate("Dialog", "lightcoral")) + self.combo_palette.setItemText(67, _translate("Dialog", "lightcyan")) + self.combo_palette.setItemText(68, _translate("Dialog", "lightgoldenrodyellow")) + self.combo_palette.setItemText(69, _translate("Dialog", "lightgray")) + self.combo_palette.setItemText(70, _translate("Dialog", "lightgreen")) + self.combo_palette.setItemText(71, _translate("Dialog", "lightpink")) + self.combo_palette.setItemText(72, _translate("Dialog", "lightsalmon")) + self.combo_palette.setItemText(73, _translate("Dialog", "lightseagreen")) + self.combo_palette.setItemText(74, _translate("Dialog", "lightskyblue")) + self.combo_palette.setItemText(75, _translate("Dialog", "lightslategray")) + self.combo_palette.setItemText(76, _translate("Dialog", "lightsteelblue")) + self.combo_palette.setItemText(77, _translate("Dialog", "lightyellow")) + self.combo_palette.setItemText(78, _translate("Dialog", "lime")) + self.combo_palette.setItemText(79, _translate("Dialog", "limegreen")) + self.combo_palette.setItemText(80, _translate("Dialog", "linen")) + self.combo_palette.setItemText(81, _translate("Dialog", "magenta")) + self.combo_palette.setItemText(82, _translate("Dialog", "maroon")) + self.combo_palette.setItemText(83, _translate("Dialog", "mediumaquamarine")) + self.combo_palette.setItemText(84, _translate("Dialog", "mediumblue")) + self.combo_palette.setItemText(85, _translate("Dialog", "mediumorchid")) + self.combo_palette.setItemText(86, _translate("Dialog", "mediumpurple")) + self.combo_palette.setItemText(87, _translate("Dialog", "mediumseagreen")) + self.combo_palette.setItemText(88, _translate("Dialog", "mediumslateblue")) + self.combo_palette.setItemText(89, _translate("Dialog", "mediumspringgreen")) + self.combo_palette.setItemText(90, _translate("Dialog", "mediumturquoise")) + self.combo_palette.setItemText(91, _translate("Dialog", "mediumvioletred")) + self.combo_palette.setItemText(92, _translate("Dialog", "midnightblue")) + self.combo_palette.setItemText(93, _translate("Dialog", "mintcream")) + self.combo_palette.setItemText(94, _translate("Dialog", "mistyrose")) + self.combo_palette.setItemText(95, _translate("Dialog", "moccasin")) + self.combo_palette.setItemText(96, _translate("Dialog", "navajowhite")) + self.combo_palette.setItemText(97, _translate("Dialog", "navy")) + self.combo_palette.setItemText(98, _translate("Dialog", "oldlace")) + self.combo_palette.setItemText(99, _translate("Dialog", "olive")) + self.combo_palette.setItemText(100, _translate("Dialog", "olivedrab")) + self.combo_palette.setItemText(101, _translate("Dialog", "orange")) + self.combo_palette.setItemText(102, _translate("Dialog", "orangered")) + self.combo_palette.setItemText(103, _translate("Dialog", "orchid")) + self.combo_palette.setItemText(104, _translate("Dialog", "palegoldenrod")) + self.combo_palette.setItemText(105, _translate("Dialog", "palegreen")) + self.combo_palette.setItemText(106, _translate("Dialog", "paleturquoise")) + self.combo_palette.setItemText(107, _translate("Dialog", "palevioletred")) + self.combo_palette.setItemText(108, _translate("Dialog", "papayawhip")) + self.combo_palette.setItemText(109, _translate("Dialog", "peachpuff")) + self.combo_palette.setItemText(110, _translate("Dialog", "peru")) + self.combo_palette.setItemText(111, _translate("Dialog", "pink")) + self.combo_palette.setItemText(112, _translate("Dialog", "plum")) + self.combo_palette.setItemText(113, _translate("Dialog", "powderblue")) + self.combo_palette.setItemText(114, _translate("Dialog", "purple")) + self.combo_palette.setItemText(115, _translate("Dialog", "red")) + self.combo_palette.setItemText(116, _translate("Dialog", "rosybrown")) + self.combo_palette.setItemText(117, _translate("Dialog", "royalblue")) + self.combo_palette.setItemText(118, _translate("Dialog", "saddlebrown")) + self.combo_palette.setItemText(119, _translate("Dialog", "salmon")) + self.combo_palette.setItemText(120, _translate("Dialog", "sandybrown")) + self.combo_palette.setItemText(121, _translate("Dialog", "seagreen")) + self.combo_palette.setItemText(122, _translate("Dialog", "seashell")) + self.combo_palette.setItemText(123, _translate("Dialog", "sienna")) + self.combo_palette.setItemText(124, _translate("Dialog", "silver")) + self.combo_palette.setItemText(125, _translate("Dialog", "skyblue")) + self.combo_palette.setItemText(126, _translate("Dialog", "slateblue")) + self.combo_palette.setItemText(127, _translate("Dialog", "slategray")) + self.combo_palette.setItemText(128, _translate("Dialog", "snow")) + self.combo_palette.setItemText(129, _translate("Dialog", "springgreen")) + self.combo_palette.setItemText(130, _translate("Dialog", "steelblue")) + self.combo_palette.setItemText(131, _translate("Dialog", "tan")) + self.combo_palette.setItemText(132, _translate("Dialog", "teal")) + self.combo_palette.setItemText(133, _translate("Dialog", "thistle")) + self.combo_palette.setItemText(134, _translate("Dialog", "tomato")) + self.combo_palette.setItemText(135, _translate("Dialog", "turquoise")) + self.combo_palette.setItemText(136, _translate("Dialog", "violet")) + self.combo_palette.setItemText(137, _translate("Dialog", "wheat")) + self.combo_palette.setItemText(138, _translate("Dialog", "white")) + self.combo_palette.setItemText(139, _translate("Dialog", "whitesmoke")) + self.combo_palette.setItemText(140, _translate("Dialog", "yellow")) + self.combo_palette.setItemText(141, _translate("Dialog", "yellowgreen")) + self.label_15.setText(_translate("Dialog", "This setting requires a restart to take effect.")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_5), _translate("Dialog", "Appearance")) + self.check_valid_load.setText(_translate("Dialog", "Validate installer.")) + self.check_valid_load_ignore.setText(_translate("Dialog", "Ignore errors and continue loading.")) + self.check_warn_load.setText(_translate("Dialog", "Check installer for common errors.")) + self.check_warn_load_ignore.setText(_translate("Dialog", "Ignore errors and continue loading.")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("Dialog", "Loading")) + self.check_valid_save.setText(_translate("Dialog", "Validate installer.")) + self.check_valid_save_ignore.setText(_translate("Dialog", "Ignore errors and continue saving.")) + self.check_warn_save.setText(_translate("Dialog", "Check installer for common errors.")) + self.check_warn_save_ignore.setText(_translate("Dialog", "Ignore errors and continue saving.")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_4), _translate("Dialog", "Saving")) + self.label_4.setText(_translate("Dialog", "Node Name")) + self.label_3.setText(_translate("Dialog", "Property Name")) + self.label_5.setText(_translate("Dialog", "Default Value")) + self.check_installSteps.setText(_translate("Dialog", "Installation Steps")) + self.label_2.setText(_translate("Dialog", "Order")) + self.combo_installSteps.setItemText(0, _translate("Dialog", "Explicit")) + self.combo_installSteps.setItemText(1, _translate("Dialog", "Ascending")) + self.combo_installSteps.setItemText(2, _translate("Dialog", "Descending")) + self.check_optionalFileGroups.setText(_translate("Dialog", "Option Group")) + self.label_6.setText(_translate("Dialog", "Order")) + self.combo_optionalFileGroups.setItemText(0, _translate("Dialog", "Explicit")) + self.combo_optionalFileGroups.setItemText(1, _translate("Dialog", "Ascending")) + self.combo_optionalFileGroups.setItemText(2, _translate("Dialog", "Descending")) + self.check_type.setText(_translate("Dialog", "Type")) + self.label_7.setText(_translate("Dialog", "Type")) + self.combo_type.setItemText(0, _translate("Dialog", "Optional")) + self.combo_type.setItemText(1, _translate("Dialog", "Required")) + self.combo_type.setItemText(2, _translate("Dialog", "Recommended")) + self.combo_type.setItemText(3, _translate("Dialog", "CouldBeUsable")) + self.combo_type.setItemText(4, _translate("Dialog", "NotUsable")) + self.check_defaultType.setText(_translate("Dialog", "Default Type")) + self.label_8.setText(_translate("Dialog", "Type")) + self.combo_defaultType.setItemText(0, _translate("Dialog", "Optional")) + self.combo_defaultType.setItemText(1, _translate("Dialog", "Required")) + self.combo_defaultType.setItemText(2, _translate("Dialog", "Recommended")) + self.combo_defaultType.setItemText(3, _translate("Dialog", "CouldBeUsable")) + self.combo_defaultType.setItemText(4, _translate("Dialog", "NotUsable")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("Dialog", "Defaults")) + diff --git a/designer/ui_templates/window_texteditor.py b/designer/ui_templates/window_texteditor.py new file mode 100644 index 0000000..d205b82 --- /dev/null +++ b/designer/ui_templates/window_texteditor.py @@ -0,0 +1,145 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/window_texteditor.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(235, 219) + self.verticalLayout = QtWidgets.QVBoxLayout(Dialog) + self.verticalLayout.setObjectName("verticalLayout") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.label = QtWidgets.QLabel(Dialog) + self.label.setObjectName("label") + self.horizontalLayout_2.addWidget(self.label) + self.radio_plain = QtWidgets.QRadioButton(Dialog) + self.radio_plain.setChecked(True) + self.radio_plain.setObjectName("radio_plain") + self.horizontalLayout_2.addWidget(self.radio_plain) + self.radio_html = QtWidgets.QRadioButton(Dialog) + self.radio_html.setObjectName("radio_html") + self.horizontalLayout_2.addWidget(self.radio_html) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem) + self.verticalLayout.addLayout(self.horizontalLayout_2) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setSpacing(0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.button_colour = QtWidgets.QPushButton(Dialog) + self.button_colour.setMaximumSize(QtCore.QSize(48, 16777215)) + self.button_colour.setText("") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap("../logos/logo_font_colour.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_colour.setIcon(icon) + self.button_colour.setObjectName("button_colour") + self.horizontalLayout.addWidget(self.button_colour) + self.button_bold = QtWidgets.QPushButton(Dialog) + self.button_bold.setMaximumSize(QtCore.QSize(48, 16777215)) + self.button_bold.setText("") + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap("../logos/logo_font_bold.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_bold.setIcon(icon1) + self.button_bold.setObjectName("button_bold") + self.horizontalLayout.addWidget(self.button_bold) + self.button_italic = QtWidgets.QPushButton(Dialog) + self.button_italic.setMaximumSize(QtCore.QSize(48, 16777215)) + self.button_italic.setText("") + icon2 = QtGui.QIcon() + icon2.addPixmap(QtGui.QPixmap("../logos/logo_font_italic.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_italic.setIcon(icon2) + self.button_italic.setObjectName("button_italic") + self.horizontalLayout.addWidget(self.button_italic) + self.button_underline = QtWidgets.QPushButton(Dialog) + self.button_underline.setMaximumSize(QtCore.QSize(48, 16777215)) + self.button_underline.setText("") + icon3 = QtGui.QIcon() + icon3.addPixmap(QtGui.QPixmap("../logos/logo_font_underline.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_underline.setIcon(icon3) + self.button_underline.setObjectName("button_underline") + self.horizontalLayout.addWidget(self.button_underline) + self.button_align_left = QtWidgets.QPushButton(Dialog) + self.button_align_left.setMaximumSize(QtCore.QSize(48, 16777215)) + self.button_align_left.setText("") + icon4 = QtGui.QIcon() + icon4.addPixmap(QtGui.QPixmap("../logos/logo_font_align_left.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_align_left.setIcon(icon4) + self.button_align_left.setObjectName("button_align_left") + self.horizontalLayout.addWidget(self.button_align_left) + self.button_align_center = QtWidgets.QPushButton(Dialog) + self.button_align_center.setMaximumSize(QtCore.QSize(48, 16777215)) + self.button_align_center.setText("") + icon5 = QtGui.QIcon() + icon5.addPixmap(QtGui.QPixmap("../logos/logo_font_align_center.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_align_center.setIcon(icon5) + self.button_align_center.setObjectName("button_align_center") + self.horizontalLayout.addWidget(self.button_align_center) + self.button_align_right = QtWidgets.QPushButton(Dialog) + self.button_align_right.setMaximumSize(QtCore.QSize(48, 16777215)) + self.button_align_right.setText("") + icon6 = QtGui.QIcon() + icon6.addPixmap(QtGui.QPixmap("../logos/logo_font_align_right.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_align_right.setIcon(icon6) + self.button_align_right.setObjectName("button_align_right") + self.horizontalLayout.addWidget(self.button_align_right) + self.button_align_justify = QtWidgets.QPushButton(Dialog) + self.button_align_justify.setMaximumSize(QtCore.QSize(48, 16777215)) + self.button_align_justify.setText("") + icon7 = QtGui.QIcon() + icon7.addPixmap(QtGui.QPixmap("../logos/logo_font_align_justify.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_align_justify.setIcon(icon7) + self.button_align_justify.setObjectName("button_align_justify") + self.horizontalLayout.addWidget(self.button_align_justify) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem1) + self.verticalLayout.addLayout(self.horizontalLayout) + self.edit_text = QtWidgets.QTextEdit(Dialog) + self.edit_text.setObjectName("edit_text") + self.verticalLayout.addWidget(self.edit_text) + self.widget_warning = QtWidgets.QWidget(Dialog) + self.widget_warning.setObjectName("widget_warning") + self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.widget_warning) + self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_3.setSpacing(3) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_3.addItem(spacerItem2) + self.label_warning = QtWidgets.QLabel(self.widget_warning) + self.label_warning.setMaximumSize(QtCore.QSize(20, 20)) + self.label_warning.setText("") + self.label_warning.setPixmap(QtGui.QPixmap("../logos/logo_danger.png")) + self.label_warning.setScaledContents(True) + self.label_warning.setObjectName("label_warning") + self.horizontalLayout_3.addWidget(self.label_warning) + self.label_2 = QtWidgets.QLabel(self.widget_warning) + self.label_2.setObjectName("label_2") + self.horizontalLayout_3.addWidget(self.label_2) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_3.addItem(spacerItem3) + self.verticalLayout.addWidget(self.widget_warning) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setCenterButtons(True) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Text Editor")) + self.label.setText(_translate("Dialog", "Output:")) + self.radio_plain.setText(_translate("Dialog", "To Plain Text")) + self.radio_html.setText(_translate("Dialog", "To HTML")) + self.label_2.setText(_translate("Dialog", "This may not work in all mod managers.")) + diff --git a/designer/ui_templates/wizard_depend_01.py b/designer/ui_templates/wizard_depend_01.py new file mode 100644 index 0000000..a54c04a --- /dev/null +++ b/designer/ui_templates/wizard_depend_01.py @@ -0,0 +1,175 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/wizard_depend_01.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(470, 560) + self.verticalLayout = QtWidgets.QVBoxLayout(Form) + self.verticalLayout.setObjectName("verticalLayout") + self.label_4 = QtWidgets.QLabel(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth()) + self.label_4.setSizePolicy(sizePolicy) + self.label_4.setMinimumSize(QtCore.QSize(0, 40)) + font = QtGui.QFont() + font.setPointSize(14) + font.setBold(True) + font.setWeight(75) + self.label_4.setFont(font) + self.label_4.setAlignment(QtCore.Qt.AlignCenter) + self.label_4.setObjectName("label_4") + self.verticalLayout.addWidget(self.label_4) + self.label = QtWidgets.QLabel(Form) + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + self.formLayout = QtWidgets.QFormLayout() + self.formLayout.setObjectName("formLayout") + self.typeLabel = QtWidgets.QLabel(Form) + self.typeLabel.setObjectName("typeLabel") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.typeLabel) + self.typeComboBox = QtWidgets.QComboBox(Form) + self.typeComboBox.setObjectName("typeComboBox") + self.typeComboBox.addItem("") + self.typeComboBox.addItem("") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.typeComboBox) + self.gameVersionLabel = QtWidgets.QLabel(Form) + self.gameVersionLabel.setObjectName("gameVersionLabel") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.gameVersionLabel) + self.gameVersionLineEdit = QtWidgets.QLineEdit(Form) + self.gameVersionLineEdit.setObjectName("gameVersionLineEdit") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.gameVersionLineEdit) + self.verticalLayout.addLayout(self.formLayout) + self.label_2 = QtWidgets.QLabel(Form) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label_2.setFont(font) + self.label_2.setAlignment(QtCore.Qt.AlignCenter) + self.label_2.setObjectName("label_2") + self.verticalLayout.addWidget(self.label_2) + self.button_file = QtWidgets.QPushButton(Form) + self.button_file.setObjectName("button_file") + self.verticalLayout.addWidget(self.button_file) + self.scrollArea_2 = QtWidgets.QScrollArea(Form) + self.scrollArea_2.setFrameShadow(QtWidgets.QFrame.Plain) + self.scrollArea_2.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) + self.scrollArea_2.setWidgetResizable(True) + self.scrollArea_2.setObjectName("scrollArea_2") + self.scrollAreaWidgetContents_2 = QtWidgets.QWidget() + self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 433, 68)) + self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2") + self.layout_file = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents_2) + self.layout_file.setContentsMargins(0, 0, 0, 0) + self.layout_file.setObjectName("layout_file") + spacerItem = QtWidgets.QSpacerItem(20, 58, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.layout_file.addItem(spacerItem) + self.scrollArea_2.setWidget(self.scrollAreaWidgetContents_2) + self.verticalLayout.addWidget(self.scrollArea_2) + self.label_5 = QtWidgets.QLabel(Form) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label_5.setFont(font) + self.label_5.setAlignment(QtCore.Qt.AlignCenter) + self.label_5.setObjectName("label_5") + self.verticalLayout.addWidget(self.label_5) + self.button_flag = QtWidgets.QPushButton(Form) + self.button_flag.setObjectName("button_flag") + self.verticalLayout.addWidget(self.button_flag) + self.scrollArea = QtWidgets.QScrollArea(Form) + self.scrollArea.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.scrollArea.setFrameShadow(QtWidgets.QFrame.Plain) + self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) + self.scrollArea.setWidgetResizable(True) + self.scrollArea.setObjectName("scrollArea") + self.scrollAreaWidgetContents = QtWidgets.QWidget() + self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 433, 68)) + self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") + self.layout_flag = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents) + self.layout_flag.setContentsMargins(0, 0, 0, 0) + self.layout_flag.setObjectName("layout_flag") + spacerItem1 = QtWidgets.QSpacerItem(20, 58, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.layout_flag.addItem(spacerItem1) + self.scrollArea.setWidget(self.scrollAreaWidgetContents) + self.verticalLayout.addWidget(self.scrollArea) + self.label_3 = QtWidgets.QLabel(Form) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label_3.setFont(font) + self.label_3.setAlignment(QtCore.Qt.AlignCenter) + self.label_3.setObjectName("label_3") + self.verticalLayout.addWidget(self.label_3) + self.button_sub = QtWidgets.QPushButton(Form) + self.button_sub.setObjectName("button_sub") + self.verticalLayout.addWidget(self.button_sub) + self.scrollArea_3 = QtWidgets.QScrollArea(Form) + self.scrollArea_3.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.scrollArea_3.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) + self.scrollArea_3.setWidgetResizable(True) + self.scrollArea_3.setObjectName("scrollArea_3") + self.scrollAreaWidgetContents_3 = QtWidgets.QWidget() + self.scrollAreaWidgetContents_3.setGeometry(QtCore.QRect(0, 0, 433, 68)) + self.scrollAreaWidgetContents_3.setObjectName("scrollAreaWidgetContents_3") + self.layout_depend = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents_3) + self.layout_depend.setContentsMargins(0, 0, 0, 0) + self.layout_depend.setObjectName("layout_depend") + spacerItem2 = QtWidgets.QSpacerItem(20, 60, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.layout_depend.addItem(spacerItem2) + self.scrollArea_3.setWidget(self.scrollAreaWidgetContents_3) + self.verticalLayout.addWidget(self.scrollArea_3) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem3) + self.finish_button = QtWidgets.QPushButton(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.finish_button.sizePolicy().hasHeightForWidth()) + self.finish_button.setSizePolicy(sizePolicy) + self.finish_button.setObjectName("finish_button") + self.horizontalLayout.addWidget(self.finish_button) + self.cancel_button = QtWidgets.QPushButton(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.cancel_button.sizePolicy().hasHeightForWidth()) + self.cancel_button.setSizePolicy(sizePolicy) + self.cancel_button.setObjectName("cancel_button") + self.horizontalLayout.addWidget(self.cancel_button) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem4) + self.verticalLayout.addLayout(self.horizontalLayout) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label_4.setText(_translate("Form", "Dependencies Wizard")) + self.label.setText(_translate("Form", "

TODO

See the Help for more information.

")) + self.typeLabel.setText(_translate("Form", "Type")) + self.typeComboBox.setItemText(0, _translate("Form", "And")) + self.typeComboBox.setItemText(1, _translate("Form", "Or")) + self.gameVersionLabel.setText(_translate("Form", "Game Version")) + self.label_2.setText(_translate("Form", "File Dependencies")) + self.button_file.setText(_translate("Form", "Add File")) + self.label_5.setText(_translate("Form", "Flag Dependencies")) + self.button_flag.setText(_translate("Form", "Add Flag")) + self.label_3.setText(_translate("Form", "Sub-Dependencies")) + self.button_sub.setText(_translate("Form", "Add Sub")) + self.finish_button.setText(_translate("Form", "Finish")) + self.cancel_button.setText(_translate("Form", "Cancel")) + diff --git a/designer/ui_templates/wizard_depend_depend.py b/designer/ui_templates/wizard_depend_depend.py new file mode 100644 index 0000000..db0a9db --- /dev/null +++ b/designer/ui_templates/wizard_depend_depend.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/wizard_depend_depend.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(550, 130) + self.verticalLayout_2 = QtWidgets.QVBoxLayout(Form) + self.verticalLayout_2.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(Form) + self.label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.label_type = QtWidgets.QLabel(Form) + self.label_type.setText("") + self.label_type.setObjectName("label_type") + self.horizontalLayout.addWidget(self.label_type) + self.button_more = QtWidgets.QPushButton(Form) + self.button_more.setObjectName("button_more") + self.horizontalLayout.addWidget(self.button_more) + self.button_less = QtWidgets.QPushButton(Form) + self.button_less.setObjectName("button_less") + self.horizontalLayout.addWidget(self.button_less) + self.button_edit = QtWidgets.QPushButton(Form) + self.button_edit.setObjectName("button_edit") + self.horizontalLayout.addWidget(self.button_edit) + self.button_delete = QtWidgets.QPushButton(Form) + self.button_delete.setMaximumSize(QtCore.QSize(30, 16777215)) + self.button_delete.setText("") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap("../logos/logo_cross.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_delete.setIcon(icon) + self.button_delete.setObjectName("button_delete") + self.horizontalLayout.addWidget(self.button_delete) + self.verticalLayout_2.addLayout(self.horizontalLayout) + self.line = QtWidgets.QFrame(Form) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.verticalLayout_2.addWidget(self.line) + self.scrollArea = QtWidgets.QScrollArea(Form) + self.scrollArea.setWidgetResizable(True) + self.scrollArea.setObjectName("scrollArea") + self.scroll_widget = QtWidgets.QWidget() + self.scroll_widget.setGeometry(QtCore.QRect(0, 0, 542, 81)) + self.scroll_widget.setObjectName("scroll_widget") + self.layout_depend_depend = QtWidgets.QVBoxLayout(self.scroll_widget) + self.layout_depend_depend.setContentsMargins(0, 0, 0, 0) + self.layout_depend_depend.setSpacing(6) + self.layout_depend_depend.setObjectName("layout_depend_depend") + spacerItem = QtWidgets.QSpacerItem(20, 265, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.layout_depend_depend.addItem(spacerItem) + self.scrollArea.setWidget(self.scroll_widget) + self.verticalLayout_2.addWidget(self.scrollArea) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label.setText(_translate("Form", "Type:")) + self.button_more.setText(_translate("Form", "More...")) + self.button_less.setText(_translate("Form", "Less...")) + self.button_edit.setText(_translate("Form", "Edit")) + diff --git a/designer/ui_templates/wizard_depend_depend_depend.py b/designer/ui_templates/wizard_depend_depend_depend.py new file mode 100644 index 0000000..8981a51 --- /dev/null +++ b/designer/ui_templates/wizard_depend_depend_depend.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/wizard_depend_depend_depend.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(345, 30) + self.horizontalLayout = QtWidgets.QHBoxLayout(Form) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label_number = QtWidgets.QLabel(Form) + self.label_number.setText("") + self.label_number.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_number.setObjectName("label_number") + self.horizontalLayout.addWidget(self.label_number) + self.label_depend = QtWidgets.QLabel(Form) + self.label_depend.setObjectName("label_depend") + self.horizontalLayout.addWidget(self.label_depend) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label_depend.setText(_translate("Form", "Sub-Dependency")) + diff --git a/designer/ui_templates/wizard_depend_depend_file.py b/designer/ui_templates/wizard_depend_depend_file.py new file mode 100644 index 0000000..dcdd6da --- /dev/null +++ b/designer/ui_templates/wizard_depend_depend_file.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/wizard_depend_depend_file.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(345, 30) + self.horizontalLayout = QtWidgets.QHBoxLayout(Form) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(Form) + self.label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.label_file = QtWidgets.QLabel(Form) + self.label_file.setText("") + self.label_file.setObjectName("label_file") + self.horizontalLayout.addWidget(self.label_file) + self.label_2 = QtWidgets.QLabel(Form) + self.label_2.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_2.setObjectName("label_2") + self.horizontalLayout.addWidget(self.label_2) + self.label_type = QtWidgets.QLabel(Form) + self.label_type.setText("") + self.label_type.setObjectName("label_type") + self.horizontalLayout.addWidget(self.label_type) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label.setText(_translate("Form", "File:")) + self.label_2.setText(_translate("Form", "Type:")) + diff --git a/designer/ui_templates/wizard_depend_depend_flag.py b/designer/ui_templates/wizard_depend_depend_flag.py new file mode 100644 index 0000000..0c95b74 --- /dev/null +++ b/designer/ui_templates/wizard_depend_depend_flag.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/wizard_depend_depend_flag.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(345, 30) + self.horizontalLayout = QtWidgets.QHBoxLayout(Form) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(Form) + self.label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.label_flag = QtWidgets.QLabel(Form) + self.label_flag.setText("") + self.label_flag.setObjectName("label_flag") + self.horizontalLayout.addWidget(self.label_flag) + self.label_2 = QtWidgets.QLabel(Form) + self.label_2.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_2.setObjectName("label_2") + self.horizontalLayout.addWidget(self.label_2) + self.label_value = QtWidgets.QLabel(Form) + self.label_value.setText("") + self.label_value.setObjectName("label_value") + self.horizontalLayout.addWidget(self.label_value) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label.setText(_translate("Form", "Flag:")) + self.label_2.setText(_translate("Form", "Value:")) + diff --git a/designer/ui_templates/wizard_depend_depend_version.py b/designer/ui_templates/wizard_depend_depend_version.py new file mode 100644 index 0000000..2380742 --- /dev/null +++ b/designer/ui_templates/wizard_depend_depend_version.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/wizard_depend_depend_version.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(345, 30) + self.horizontalLayout = QtWidgets.QHBoxLayout(Form) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(Form) + self.label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.label_version = QtWidgets.QLabel(Form) + self.label_version.setText("") + self.label_version.setObjectName("label_version") + self.horizontalLayout.addWidget(self.label_version) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label.setText(_translate("Form", "Version:")) + diff --git a/designer/ui_templates/wizard_depend_file.py b/designer/ui_templates/wizard_depend_file.py new file mode 100644 index 0000000..d4d8db0 --- /dev/null +++ b/designer/ui_templates/wizard_depend_file.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/wizard_depend_file.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(345, 30) + self.horizontalLayout = QtWidgets.QHBoxLayout(Form) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(Form) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.edit_file = QtWidgets.QLineEdit(Form) + self.edit_file.setObjectName("edit_file") + self.horizontalLayout.addWidget(self.edit_file) + self.label_2 = QtWidgets.QLabel(Form) + self.label_2.setObjectName("label_2") + self.horizontalLayout.addWidget(self.label_2) + self.combo_type = QtWidgets.QComboBox(Form) + self.combo_type.setObjectName("combo_type") + self.combo_type.addItem("") + self.combo_type.addItem("") + self.combo_type.addItem("") + self.horizontalLayout.addWidget(self.combo_type) + self.button_delete = QtWidgets.QPushButton(Form) + self.button_delete.setMaximumSize(QtCore.QSize(30, 16777215)) + self.button_delete.setText("") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap("../logos/logo_cross.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_delete.setIcon(icon) + self.button_delete.setObjectName("button_delete") + self.horizontalLayout.addWidget(self.button_delete) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label.setText(_translate("Form", "File:")) + self.label_2.setText(_translate("Form", "Type:")) + self.combo_type.setItemText(0, _translate("Form", "Missing")) + self.combo_type.setItemText(1, _translate("Form", "Inactive")) + self.combo_type.setItemText(2, _translate("Form", "Active")) + diff --git a/designer/ui_templates/wizard_depend_flag.py b/designer/ui_templates/wizard_depend_flag.py new file mode 100644 index 0000000..4d33b65 --- /dev/null +++ b/designer/ui_templates/wizard_depend_flag.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/wizard_depend_flag.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(320, 31) + self.horizontalLayout = QtWidgets.QHBoxLayout(Form) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(Form) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.edit_flag = QtWidgets.QLineEdit(Form) + self.edit_flag.setObjectName("edit_flag") + self.horizontalLayout.addWidget(self.edit_flag) + self.label_2 = QtWidgets.QLabel(Form) + self.label_2.setObjectName("label_2") + self.horizontalLayout.addWidget(self.label_2) + self.edit_value = QtWidgets.QLineEdit(Form) + self.edit_value.setObjectName("edit_value") + self.horizontalLayout.addWidget(self.edit_value) + self.button_delete = QtWidgets.QPushButton(Form) + self.button_delete.setMaximumSize(QtCore.QSize(30, 16777215)) + self.button_delete.setText("") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap("../logos/logo_cross.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_delete.setIcon(icon) + self.button_delete.setObjectName("button_delete") + self.horizontalLayout.addWidget(self.button_delete) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label.setText(_translate("Form", "Flag:")) + self.label_2.setText(_translate("Form", "Value:")) + diff --git a/designer/ui_templates/wizard_files_01.py b/designer/ui_templates/wizard_files_01.py new file mode 100644 index 0000000..a3e32dc --- /dev/null +++ b/designer/ui_templates/wizard_files_01.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/wizard_files_01.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(470, 539) + self.verticalLayout_2 = QtWidgets.QVBoxLayout(Form) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.label_4 = QtWidgets.QLabel(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth()) + self.label_4.setSizePolicy(sizePolicy) + self.label_4.setMinimumSize(QtCore.QSize(0, 40)) + font = QtGui.QFont() + font.setPointSize(14) + font.setBold(True) + font.setWeight(75) + self.label_4.setFont(font) + self.label_4.setAlignment(QtCore.Qt.AlignCenter) + self.label_4.setObjectName("label_4") + self.verticalLayout.addWidget(self.label_4) + self.label = QtWidgets.QLabel(Form) + self.label.setTextFormat(QtCore.Qt.AutoText) + self.label.setScaledContents(False) + self.label.setWordWrap(True) + self.label.setIndent(-1) + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + self.label_2 = QtWidgets.QLabel(Form) + font = QtGui.QFont() + font.setBold(True) + font.setItalic(True) + font.setWeight(75) + self.label_2.setFont(font) + self.label_2.setAlignment(QtCore.Qt.AlignCenter) + self.label_2.setObjectName("label_2") + self.verticalLayout.addWidget(self.label_2) + self.button_add_file = QtWidgets.QPushButton(Form) + self.button_add_file.setObjectName("button_add_file") + self.verticalLayout.addWidget(self.button_add_file) + self.scrollarea_file = QtWidgets.QScrollArea(Form) + self.scrollarea_file.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) + self.scrollarea_file.setWidgetResizable(True) + self.scrollarea_file.setObjectName("scrollarea_file") + self.scroll_file = QtWidgets.QWidget() + self.scroll_file.setGeometry(QtCore.QRect(0, 0, 431, 125)) + self.scroll_file.setObjectName("scroll_file") + self.layout_file = QtWidgets.QVBoxLayout(self.scroll_file) + self.layout_file.setContentsMargins(3, 0, 3, 0) + self.layout_file.setObjectName("layout_file") + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.layout_file.addItem(spacerItem) + self.scrollarea_file.setWidget(self.scroll_file) + self.verticalLayout.addWidget(self.scrollarea_file) + self.label_3 = QtWidgets.QLabel(Form) + font = QtGui.QFont() + font.setBold(True) + font.setItalic(True) + font.setWeight(75) + self.label_3.setFont(font) + self.label_3.setAlignment(QtCore.Qt.AlignCenter) + self.label_3.setObjectName("label_3") + self.verticalLayout.addWidget(self.label_3) + self.button_add_folder = QtWidgets.QPushButton(Form) + self.button_add_folder.setObjectName("button_add_folder") + self.verticalLayout.addWidget(self.button_add_folder) + self.scrollarea_folder = QtWidgets.QScrollArea(Form) + self.scrollarea_folder.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) + self.scrollarea_folder.setWidgetResizable(True) + self.scrollarea_folder.setObjectName("scrollarea_folder") + self.scroll_folder = QtWidgets.QWidget() + self.scroll_folder.setGeometry(QtCore.QRect(0, 0, 431, 125)) + self.scroll_folder.setObjectName("scroll_folder") + self.layout_folder = QtWidgets.QVBoxLayout(self.scroll_folder) + self.layout_folder.setContentsMargins(3, 0, 3, 0) + self.layout_folder.setObjectName("layout_folder") + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.layout_folder.addItem(spacerItem1) + self.scrollarea_folder.setWidget(self.scroll_folder) + self.verticalLayout.addWidget(self.scrollarea_folder) + self.verticalLayout_2.addLayout(self.verticalLayout) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem2) + self.finish_button = QtWidgets.QPushButton(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.finish_button.sizePolicy().hasHeightForWidth()) + self.finish_button.setSizePolicy(sizePolicy) + self.finish_button.setObjectName("finish_button") + self.horizontalLayout.addWidget(self.finish_button) + self.cancel_button = QtWidgets.QPushButton(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.cancel_button.sizePolicy().hasHeightForWidth()) + self.cancel_button.setSizePolicy(sizePolicy) + self.cancel_button.setObjectName("cancel_button") + self.horizontalLayout.addWidget(self.cancel_button) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem3) + self.verticalLayout_2.addLayout(self.horizontalLayout) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label_4.setText(_translate("Form", "Files and Folders Wizard")) + self.label.setText(_translate("Form", "

Select the files and folders to be installed. The "Source" fields are used to select the file/folder to be installed. The "Destination" fields are used to select where the item will be installed to - a blank fields corresponds to the Data folder itself.

See the Help for more information.

")) + self.label_2.setText(_translate("Form", "Files To Be Installed:")) + self.button_add_file.setText(_translate("Form", "Add File")) + self.label_3.setText(_translate("Form", "Folders To Be Installed:")) + self.button_add_folder.setText(_translate("Form", "Add Folder")) + self.finish_button.setText(_translate("Form", "Finish")) + self.cancel_button.setText(_translate("Form", "Cancel")) + diff --git a/designer/ui_templates/wizard_files_item.py b/designer/ui_templates/wizard_files_item.py new file mode 100644 index 0000000..1d2631e --- /dev/null +++ b/designer/ui_templates/wizard_files_item.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/templates/wizard_files_item.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_base(object): + def setupUi(self, base): + base.setObjectName("base") + base.resize(396, 24) + self.layout_main = QtWidgets.QHBoxLayout(base) + self.layout_main.setContentsMargins(0, 0, 0, 0) + self.layout_main.setObjectName("layout_main") + self.label_source = QtWidgets.QLabel(base) + self.label_source.setObjectName("label_source") + self.layout_main.addWidget(self.label_source) + self.edit_source = QtWidgets.QLineEdit(base) + self.edit_source.setObjectName("edit_source") + self.layout_main.addWidget(self.edit_source) + self.button_source = QtWidgets.QPushButton(base) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.button_source.sizePolicy().hasHeightForWidth()) + self.button_source.setSizePolicy(sizePolicy) + self.button_source.setMaximumSize(QtCore.QSize(50, 16777215)) + self.button_source.setObjectName("button_source") + self.layout_main.addWidget(self.button_source) + self.label_dest = QtWidgets.QLabel(base) + self.label_dest.setObjectName("label_dest") + self.layout_main.addWidget(self.label_dest) + self.edit_dest = QtWidgets.QLineEdit(base) + self.edit_dest.setObjectName("edit_dest") + self.layout_main.addWidget(self.edit_dest) + self.button_delete = QtWidgets.QPushButton(base) + self.button_delete.setText("") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap("../logos/logo_cross.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_delete.setIcon(icon) + self.button_delete.setObjectName("button_delete") + self.layout_main.addWidget(self.button_delete) + + self.retranslateUi(base) + QtCore.QMetaObject.connectSlotsByName(base) + + def retranslateUi(self, base): + _translate = QtCore.QCoreApplication.translate + base.setWindowTitle(_translate("base", "Form")) + self.label_source.setText(_translate("base", "Source:")) + self.button_source.setText(_translate("base", "...")) + self.label_dest.setText(_translate("base", "Destination:")) + diff --git a/designer/wizards.py b/designer/wizards.py index 8d2854f..4f510ae 100644 --- a/designer/wizards.py +++ b/designer/wizards.py @@ -17,13 +17,15 @@ from abc import ABCMeta, abstractmethod from copy import deepcopy from os.path import join, relpath -from PyQt5.QtWidgets import QStackedWidget, QFileDialog +from PyQt5.QtWidgets import QStackedWidget, QFileDialog, QWidget from PyQt5.QtGui import QIcon from PyQt5.QtCore import pyqtSignal -from PyQt5.uic import loadUi from . import cur_folder from .io import elem_factory from .exceptions import BaseInstanceException +from .ui_templates import (wizard_files_01, wizard_files_item, wizard_depend_01, wizard_depend_depend, + wizard_depend_depend_depend, wizard_depend_depend_file, wizard_depend_depend_flag, + wizard_depend_depend_version, wizard_depend_file, wizard_depend_flag) class _WizardBase(QStackedWidget): @@ -32,10 +34,11 @@ class _WizardBase(QStackedWidget): """ __metaclass__ = ABCMeta + code_changed = pyqtSignal([object]) cancelled = pyqtSignal() - finished = pyqtSignal() + finished = pyqtSignal([object]) - def __init__(self, parent, element, main_window): + def __init__(self, parent, element, code_signal, **kwargs): """ :param parent: The parent widget. :param element: The element this wizard corresponds. @@ -47,7 +50,8 @@ def __init__(self, parent, element, main_window): self.element = element self.parent = parent - self.main_window = main_window + self.kwargs = kwargs + self.code_changed.connect(code_signal.emit) self._setup_pages() @abstractmethod @@ -69,15 +73,10 @@ def _setup_pages(self): class WizardFiles(_WizardBase): """ - Wizard fo the "files" tag. + Wizard for the "files" tag. """ def _process_results(self, result): - self.element.getparent().replace(self.element, result) - item_parent = self.element.model_item.parent() - row = self.element.model_item.row() - item_parent.removeRow(row) - item_parent.insertRow(row, result.model_item) - self.finished.emit() + self.finished.emit(result) def _setup_pages(self): def add_elem(element_, layout): @@ -91,32 +90,35 @@ def add_elem(element_, layout): element_result.add_child(child) spacer = layout.takeAt(layout.count() - 1) item = self._create_field(child) - item.edit_source.setText(child.properties["source"].value) - item.edit_dest.setText(child.properties["destination"].value) layout.addWidget(item) layout.addSpacerItem(spacer) - self.main_window.xml_code_changed.emit(element_result) + self.code_changed.emit(element_result) element_result = deepcopy(self.element) - page = loadUi(join(cur_folder, "resources/templates/wizard_files_01.ui")) + page = QWidget() + page_ui = wizard_files_01.Ui_Form() + page_ui.setupUi(page) file_list = [elem for elem in element_result if elem.tag == "file"] for element in file_list: element_result.remove_child(element) - add_elem(element, page.layout_file) + add_elem(element, page_ui.layout_file) folder_list = [elem for elem in element_result if elem.tag == "folder"] for element in folder_list: element_result.remove_child(element) - add_elem(element, page.layout_folder) + add_elem(element, page_ui.layout_folder) # finish with connections - page.button_add_file.clicked.connect(lambda: add_elem(elem_factory("file", element_result), page.layout_file)) - page.button_add_folder.clicked.connect( - lambda: add_elem(elem_factory("folder", element_result), page.layout_folder)) - page.finish_button.clicked.connect(lambda: self._process_results(element_result)) - page.cancel_button.clicked.connect(self.cancelled.emit) + page_ui.button_add_file.clicked.connect( + lambda: add_elem(elem_factory("file", element_result), page_ui.layout_file) + ) + page_ui.button_add_folder.clicked.connect( + lambda: add_elem(elem_factory("folder", element_result), page_ui.layout_folder) + ) + page_ui.finish_button.clicked.connect(lambda: self._process_results(element_result)) + page_ui.cancel_button.clicked.connect(self.cancelled.emit) self.addWidget(page) @@ -128,31 +130,320 @@ def _create_field(self, element): def button_clicked(): open_dialog = QFileDialog() if element.tag == "file": - file_path = open_dialog.getOpenFileName(self, "Select File:", self.main_window.package_path) + file_path = open_dialog.getOpenFileName(self, "Select File:", self.kwargs["package_path"]) if file_path[0]: - item.edit_source.setText(relpath(file_path[0], self.main_window.package_path)) + item_ui.edit_source.setText(relpath(file_path[0], self.kwargs["package_path"])) elif element.tag == "folder": - folder_path = open_dialog.getExistingDirectory(self, "Select folder:", self.main_window.package_path) + folder_path = open_dialog.getExistingDirectory(self, "Select folder:", self.kwargs["package_path"]) if folder_path: - item.edit_source.setText(relpath(folder_path, self.main_window.package_path)) + item_ui.edit_source.setText(relpath(folder_path, self.kwargs["package_path"])) parent_element = element.getparent() - item = loadUi(join(cur_folder, "resources/templates/wizard_files_item.ui")) + item = QWidget() + item_ui = wizard_files_item.Ui_base() + item_ui.setupUi(item) - # the delete self button - item.button_delete.setIcon(QIcon(join(cur_folder, "resources/logos/logo_cross.png"))) + # set initial values + item_ui.edit_source.setText(element.properties["source"].value) + item_ui.edit_dest.setText(element.properties["destination"].value) + item_ui.button_delete.setIcon(QIcon(join(cur_folder, "resources/logos/logo_cross.png"))) # connect the signals - item.edit_source.textChanged.connect(element.properties["source"].set_value) - item.edit_source.textChanged.connect(element.write_attribs) - item.edit_source.textChanged.connect(lambda: self.main_window.xml_code_changed.emit(parent_element)) - item.edit_dest.textChanged.connect(element.properties["destination"].set_value) - item.edit_dest.textChanged.connect(element.write_attribs) - item.edit_dest.textChanged.connect(lambda: self.main_window.xml_code_changed.emit(parent_element)) - item.button_source.clicked.connect(button_clicked) - item.button_delete.clicked.connect(item.deleteLater) - item.button_delete.clicked.connect(lambda x: parent_element.remove_child(element)) - item.button_delete.clicked.connect(lambda: self.main_window.xml_code_changed.emit(parent_element)) + item_ui.edit_source.textChanged.connect(element.properties["source"].set_value) + item_ui.edit_source.textChanged.connect(element.write_attribs) + item_ui.edit_source.textChanged.connect(lambda: self.code_changed.emit(parent_element)) + item_ui.edit_dest.textChanged.connect(element.properties["destination"].set_value) + item_ui.edit_dest.textChanged.connect(element.write_attribs) + item_ui.edit_dest.textChanged.connect(lambda: self.code_changed.emit(parent_element)) + item_ui.button_source.clicked.connect(button_clicked) + item_ui.button_delete.clicked.connect(item.deleteLater) + item_ui.button_delete.clicked.connect(lambda _: parent_element.remove_child(element)) + item_ui.button_delete.clicked.connect(lambda: self.code_changed.emit(parent_element)) return item + + +class WizardDepend(_WizardBase): + """ + Wizard for the "dependencies" tag. + """ + def _process_results(self, result): + self.finished.emit(result) + + def _setup_pages(self): + """ + NodeConfigVisible and NodeConfigRoot are used as simple placeholders for the factory. They serve no purpose + other than giving the factory a parent to help parsing. + """ + from .nodes import NodeConfigVisible, NodeConfigRoot + + def copy_depend(element_): + if element_.getparent().tag == "dependencies" or \ + element_.getparent().tag == "moduleDependencies" or \ + element_.getparent().tag == "visible": + result = elem_factory(element_.tag, NodeConfigVisible()) + elif element_.tag == "moduleDependencies": + result = elem_factory(element_.tag, NodeConfigVisible()) + elif element_.tag == "visible": + result = elem_factory(element_.tag, NodeConfigVisible()) + else: + result = elem_factory(element_.tag, NodeConfigRoot()) + + element_.write_attribs() + for key in element_.keys(): + result.set(key, element_.get(key)) + result.parse_attribs() + + for child in element_: + if child.tag == "dependencies": + result.add_child(copy_depend(child)) + continue + new_child = deepcopy(child) + for key in child.keys(): + new_child.set(key, child.get(key)) + new_child.parse_attribs() + result.add_child(new_child) + + return result + + element_result = copy_depend(self.element) + self.code_changed.emit(element_result) + + page = QWidget() + page_ui = wizard_depend_01.Ui_Form() + page_ui.setupUi(page) + + page_ui.typeComboBox.setCurrentText(element_result.get("operator")) + + for element in [elem for elem in element_result if elem.tag == "fileDependency"]: + self.add_elem(element_result, page_ui.layout_file, element_=element) + + for element in [elem for elem in element_result if elem.tag == "flagDependency"]: + self.add_elem(element_result, page_ui.layout_flag, element_=element) + + for element in [elem for elem in element_result if elem.tag == "dependencies"]: + self.add_elem(element_result, page_ui.layout_depend, element_=element) + + for elem in element_result: + if elem.tag == "gameDependency": + page_ui.gameVersionLineEdit.setText(elem.get("version")) + + # finish with connections + page_ui.typeComboBox.currentTextChanged.connect(element_result.properties["operator"].set_value) + page_ui.typeComboBox.currentTextChanged.connect(element_result.write_attribs) + page_ui.typeComboBox.currentTextChanged.connect(lambda: self.code_changed.emit(element_result)) + + page_ui.gameVersionLineEdit.textChanged.connect( + lambda value, element_=element_result: self._update_version(value, element_)) + + page_ui.button_file.clicked.connect( + lambda: self.add_elem(element_result, page_ui.layout_file, tag="fileDependency")) + + page_ui.button_flag.clicked.connect( + lambda: self.add_elem(element_result, page_ui.layout_flag, tag="flagDependency")) + + page_ui.button_sub.clicked.connect( + lambda: self.add_elem(element_result, page_ui.layout_depend, tag="dependencies")) + + page_ui.finish_button.clicked.connect(lambda: self._process_results(element_result)) + page_ui.cancel_button.clicked.connect(self.cancelled.emit) + + self.addWidget(page) + + def add_elem(self, parent_elem, layout, tag="", element_=None): + """ + :param parent_elem: The parent element - the element the wizard is being applied on. + :param tag: The tag of the element to be created + :param element_: The element to be used + :param layout: The layout into which to insert the newly copied element + """ + from .nodes import NodeConfigVisible + + if element_ is None and tag: + child = elem_factory(tag, NodeConfigVisible()) + parent_elem.add_child(child) + else: + if element_ is None: + return + child = element_ + tag = child.tag + spacer = layout.takeAt(layout.count() - 1) + item = None + if tag == "fileDependency": + item = self._create_file(child) + elif tag == "flagDependency": + item = self._create_flag(child) + elif tag == "dependencies": + item = self._create_depend(child, layout) + layout.addWidget(item) + layout.addSpacerItem(spacer) + self.code_changed.emit(parent_elem) + + def _update_version(self, value, element): + elem = None + for ele in element: + if ele.tag == "gameDependency": + elem = ele + + if elem is not None: + if not value: + element.remove_child(elem) + else: + elem.properties["version"].set_value(value) + elem.write_attribs() + else: + if value: + elem = elem_factory("gameDependency", element) + element.add_child(elem) + elem.properties["version"].set_value(value) + elem.write_attribs() + + self.code_changed.emit(element) + + def _create_file(self, element): + parent_element = element.getparent() + + item = QWidget() + item_ui = wizard_depend_file.Ui_Form() + item_ui.setupUi(item) + + # set initial values + item_ui.edit_file.setText(element.properties["file"].value) + item_ui.combo_type.setCurrentText(element.properties["state"].value) + item_ui.button_delete.setIcon(QIcon(join(cur_folder, "resources/logos/logo_cross.png"))) + + # connect the signals + item_ui.edit_file.textChanged.connect(element.properties["file"].set_value) + item_ui.edit_file.textChanged.connect(element.write_attribs) + item_ui.edit_file.textChanged.connect(lambda: self.code_changed.emit(parent_element)) + + item_ui.combo_type.currentTextChanged.connect(element.properties["state"].set_value) + item_ui.combo_type.currentTextChanged.connect(element.write_attribs) + item_ui.combo_type.currentTextChanged.connect(lambda: self.code_changed.emit(parent_element)) + + item_ui.button_delete.clicked.connect(item.deleteLater) + item_ui.button_delete.clicked.connect(lambda _: parent_element.remove_child(element)) + item_ui.button_delete.clicked.connect(lambda: self.code_changed.emit(parent_element)) + + return item + + def _create_flag(self, element): + parent_element = element.getparent() + + item = QWidget() + item_ui = wizard_depend_flag.Ui_Form() + item_ui.setupUi(item) + + # set initial values + item_ui.edit_flag.setText(element.properties["flag"].value) + item_ui.edit_value.setText(element.properties["value"].value) + item_ui.button_delete.setIcon(QIcon(join(cur_folder, "resources/logos/logo_cross.png"))) + + # connect the signals + item_ui.edit_flag.textChanged.connect(element.properties["flag"].set_value) + item_ui.edit_flag.textChanged.connect(element.write_attribs) + item_ui.edit_flag.textChanged.connect(lambda: self.code_changed.emit(parent_element)) + + item_ui.edit_value.textChanged.connect(element.properties["value"].set_value) + item_ui.edit_value.textChanged.connect(element.write_attribs) + item_ui.edit_value.textChanged.connect(lambda: self.code_changed.emit(parent_element)) + + item_ui.button_delete.clicked.connect(item.deleteLater) + item_ui.button_delete.clicked.connect(lambda _: parent_element.remove_child(element)) + item_ui.button_delete.clicked.connect(lambda: self.code_changed.emit(parent_element)) + + return item + + def _create_depend(self, element, depend_layout): + parent_element = element.getparent() + + item = QWidget() + item_ui = wizard_depend_depend.Ui_Form() + item_ui.setupUi(item) + + file = QWidget() + file_ui = wizard_depend_depend_file.Ui_Form() + file_ui.setupUi(file) + + flag = QWidget() + flag_ui = wizard_depend_depend_flag.Ui_Form() + flag_ui.setupUi(flag) + + version = QWidget() + version_ui = wizard_depend_depend_version.Ui_Form() + version_ui.setupUi(version) + + depend = QWidget() + depend_ui = wizard_depend_depend_depend.Ui_Form() + depend_ui.setupUi(depend) + + item_ui.label_type.setText(element.properties["operator"].value) + item_ui.button_less.hide() + item_ui.line.hide() + item_ui.scrollArea.hide() + item_ui.button_delete.setIcon(QIcon(join(cur_folder, "resources/logos/logo_cross.png"))) + + spacer = item_ui.layout_depend_depend.takeAt(item_ui.layout_depend_depend.count() - 1) + + for element_ in [elem for elem in element if elem.tag == "fileDependency"]: + file_ui.label_file.setText(element_.properties["file"].value) + file_ui.label_type.setText(element_.properties["state"].value) + item_ui.layout_depend_depend.addWidget(file) + + for element_ in [elem for elem in element if elem.tag == "flagDependency"]: + flag_ui.label_flag.setText(element_.properties["flag"].value) + flag_ui.label_value.setText(element_.properties["value"].value) + item_ui.layout_depend_depend.addWidget(flag) + + sub_dependencies_sum = sum(1 for elem in element if elem.tag == "dependencies") + if sub_dependencies_sum: + depend_ui.label_number.setText(str(sub_dependencies_sum)) + if sub_dependencies_sum > 1: + depend_ui.label_depend.setText("Sub-Dependencies") + item_ui.layout_depend_depend.addWidget(depend) + + for element_ in [elem for elem in element if elem.tag == "gameDependency"]: + version_ui.label_version.setText(element_.get("version")) + item_ui.layout_depend_depend.addWidget(version) + + item_ui.layout_depend_depend.addSpacerItem(spacer) + + item_ui.button_more.clicked.connect(lambda: item_ui.button_more.hide()) + item_ui.button_more.clicked.connect(lambda: item_ui.button_less.show()) + item_ui.button_more.clicked.connect(lambda: item_ui.line.show()) + item_ui.button_more.clicked.connect(lambda: item_ui.scrollArea.show()) + + item_ui.button_less.clicked.connect(lambda: item_ui.button_less.hide()) + item_ui.button_less.clicked.connect(lambda: item_ui.button_more.show()) + item_ui.button_less.clicked.connect(lambda: item_ui.line.hide()) + item_ui.button_less.clicked.connect(lambda: item_ui.scrollArea.hide()) + + item_ui.button_edit.clicked.connect(lambda _, element__=element: self._nested_wizard(element__, depend_layout)) + + item_ui.button_delete.clicked.connect(item.deleteLater) + item_ui.button_delete.clicked.connect(lambda _: parent_element.remove_child(element)) + item_ui.button_delete.clicked.connect(lambda: self.code_changed.emit(parent_element)) + + return item + + def _nested_wizard(self, element, depend_layout): + nested_wiz = WizardDepend(self, element, self.code_changed, **self.kwargs) + self.addWidget(nested_wiz) + self.setCurrentWidget(nested_wiz) + + nested_wiz.cancelled.connect(lambda: nested_wiz.deleteLater()) + nested_wiz.cancelled.connect(lambda parent=element.getparent(): self.code_changed.emit(parent)) + + nested_wiz.finished.connect(lambda: nested_wiz.deleteLater()) + nested_wiz.finished.connect(lambda parent=element.getparent(): self._update_depends(parent, depend_layout)) + nested_wiz.finished.connect(lambda parent=element.getparent(): self.code_changed.emit(parent)) + + def _update_depends(self, main_elem, depend_layout): + for index in reversed(range(depend_layout.count())): + if depend_layout.itemAt(index).widget(): + widget = depend_layout.takeAt(index).widget() + if widget is not None: + widget.deleteLater() + + [self.add_elem(main_elem, depend_layout, element_=elem) for elem in main_elem if elem.tag == "dependencies"] diff --git a/dev/appveyor-bootstrap.bat b/dev/appveyor-bootstrap.bat index 9bff0e2..4c4691c 100644 --- a/dev/appveyor-bootstrap.bat +++ b/dev/appveyor-bootstrap.bat @@ -1,6 +1,6 @@ @echo off -set PATH=C:\Miniconda-x64;C:\Miniconda-x64\Scripts;%PATH% +set PATH=C:\Miniconda-x64;C:\Miniconda-x64\Scripts; conda create -y -n fomod-designer^ -c https://conda.anaconda.org/mmcauliffe^ diff --git a/dev/reqs.txt b/dev/reqs.txt index 8641d69..3793503 100644 --- a/dev/reqs.txt +++ b/dev/reqs.txt @@ -1,6 +1,8 @@ bumpversion==0.5.3 -fomod-validator==1.3.0 +fomod-validator==1.5.2 invoke==0.12.2 +jsonpickle==0.9.3 lxml==3.5.0 Pygments==2.1.3 PyInstaller==3.1.1 +requests==2.10.0 diff --git a/dev/travis-bootstrap.sh b/dev/travis-bootstrap.sh index 112207e..ce27042 100644 --- a/dev/travis-bootstrap.sh +++ b/dev/travis-bootstrap.sh @@ -16,9 +16,9 @@ # get pyenv - I hate messing with system python on ubuntu -git clone https://github.com/yyuu/pyenv.git $HOME/.pyenv +git clone https://github.com/yyuu/pyenv.git $HOME/.pyenv-custom -export PYENV_ROOT="$HOME/.pyenv" +export PYENV_ROOT="$HOME/.pyenv-custom" export PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init -)" @@ -26,7 +26,7 @@ eval "$(pyenv init -)" # get pyenv-virtualenv instead of plain old virtualenv git clone https://github.com/yyuu/pyenv-virtualenv.git \ - $HOME/.pyenv/plugins/pyenv-virtualenv + $HOME/.pyenv-custom/plugins/pyenv-virtualenv eval "$(pyenv virtualenv-init -)" diff --git a/dev/travis-build.sh b/dev/travis-build.sh index 79a782c..2ec7910 100644 --- a/dev/travis-build.sh +++ b/dev/travis-build.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -export PYENV_ROOT="$HOME/.pyenv" +export PYENV_ROOT="$HOME/.pyenv-custom" export PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init -)" eval "$(pyenv virtualenv-init -)" diff --git a/resources/logos/logo_cd_disk.png b/resources/logos/logo_cd_disk.png deleted file mode 100644 index 417f3e7..0000000 Binary files a/resources/logos/logo_cd_disk.png and /dev/null differ diff --git a/resources/logos/logo_clear.png b/resources/logos/logo_clear.png new file mode 100644 index 0000000..dd7ac09 Binary files /dev/null and b/resources/logos/logo_clear.png differ diff --git a/resources/logos/logo_collapse.png b/resources/logos/logo_collapse.png new file mode 100644 index 0000000..63de16f Binary files /dev/null and b/resources/logos/logo_collapse.png differ diff --git a/resources/logos/logo_copy.png b/resources/logos/logo_copy.png new file mode 100644 index 0000000..f515eec Binary files /dev/null and b/resources/logos/logo_copy.png differ diff --git a/resources/logos/logo_cross.png b/resources/logos/logo_cross.png index 7cc2ace..964a0b9 100644 Binary files a/resources/logos/logo_cross.png and b/resources/logos/logo_cross.png differ diff --git a/resources/logos/logo_danger.png b/resources/logos/logo_danger.png index 15f573d..b06c61f 100644 Binary files a/resources/logos/logo_danger.png and b/resources/logos/logo_danger.png differ diff --git a/resources/logos/logo_enter.png b/resources/logos/logo_enter.png new file mode 100644 index 0000000..cf70472 Binary files /dev/null and b/resources/logos/logo_enter.png differ diff --git a/resources/logos/logo_expand.png b/resources/logos/logo_expand.png new file mode 100644 index 0000000..a595941 Binary files /dev/null and b/resources/logos/logo_expand.png differ diff --git a/resources/logos/logo_file.png b/resources/logos/logo_file.png new file mode 100644 index 0000000..af7316e Binary files /dev/null and b/resources/logos/logo_file.png differ diff --git a/resources/logos/logo_floppy_disk.png b/resources/logos/logo_floppy_disk.png index 4cf1009..e4edbdc 100644 Binary files a/resources/logos/logo_floppy_disk.png and b/resources/logos/logo_floppy_disk.png differ diff --git a/resources/logos/logo_folder.png b/resources/logos/logo_folder.png new file mode 100644 index 0000000..2e002e5 Binary files /dev/null and b/resources/logos/logo_folder.png differ diff --git a/resources/logos/logo_font_align_center.png b/resources/logos/logo_font_align_center.png new file mode 100644 index 0000000..1dee52f Binary files /dev/null and b/resources/logos/logo_font_align_center.png differ diff --git a/resources/logos/logo_font_align_justify.png b/resources/logos/logo_font_align_justify.png new file mode 100644 index 0000000..1450bba Binary files /dev/null and b/resources/logos/logo_font_align_justify.png differ diff --git a/resources/logos/logo_font_align_left.png b/resources/logos/logo_font_align_left.png new file mode 100644 index 0000000..ea877f4 Binary files /dev/null and b/resources/logos/logo_font_align_left.png differ diff --git a/resources/logos/logo_font_align_right.png b/resources/logos/logo_font_align_right.png new file mode 100644 index 0000000..84cacf3 Binary files /dev/null and b/resources/logos/logo_font_align_right.png differ diff --git a/resources/logos/logo_font_bold.png b/resources/logos/logo_font_bold.png new file mode 100644 index 0000000..1364978 Binary files /dev/null and b/resources/logos/logo_font_bold.png differ diff --git a/resources/logos/logo_font_colour.png b/resources/logos/logo_font_colour.png new file mode 100644 index 0000000..2292d96 Binary files /dev/null and b/resources/logos/logo_font_colour.png differ diff --git a/resources/logos/logo_font_italic.png b/resources/logos/logo_font_italic.png new file mode 100644 index 0000000..90b3750 Binary files /dev/null and b/resources/logos/logo_font_italic.png differ diff --git a/resources/logos/logo_font_underline.png b/resources/logos/logo_font_underline.png new file mode 100644 index 0000000..00d3dc4 Binary files /dev/null and b/resources/logos/logo_font_underline.png differ diff --git a/resources/logos/logo_gear.png b/resources/logos/logo_gear.png index 61a7c06..9b67a66 100644 Binary files a/resources/logos/logo_gear.png and b/resources/logos/logo_gear.png differ diff --git a/resources/logos/logo_info.png b/resources/logos/logo_info.png index b94a2c9..55fef89 100644 Binary files a/resources/logos/logo_info.png and b/resources/logos/logo_info.png differ diff --git a/resources/logos/logo_less.png b/resources/logos/logo_less.png new file mode 100644 index 0000000..d00123c Binary files /dev/null and b/resources/logos/logo_less.png differ diff --git a/resources/logos/logo_more.png b/resources/logos/logo_more.png new file mode 100644 index 0000000..1f70f85 Binary files /dev/null and b/resources/logos/logo_more.png differ diff --git a/resources/logos/logo_notepad.png b/resources/logos/logo_notepad.png index 81dbfb3..42ce193 100644 Binary files a/resources/logos/logo_notepad.png and b/resources/logos/logo_notepad.png differ diff --git a/resources/logos/logo_open_file.png b/resources/logos/logo_open_file.png index 3b6e742..5385e88 100644 Binary files a/resources/logos/logo_open_file.png and b/resources/logos/logo_open_file.png differ diff --git a/resources/logos/logo_paste.png b/resources/logos/logo_paste.png new file mode 100644 index 0000000..f16065c Binary files /dev/null and b/resources/logos/logo_paste.png differ diff --git a/resources/logos/logo_plus.png b/resources/logos/logo_plus.png deleted file mode 100644 index 521566d..0000000 Binary files a/resources/logos/logo_plus.png and /dev/null differ diff --git a/resources/logos/logo_recent.png b/resources/logos/logo_recent.png new file mode 100644 index 0000000..1b3bacc Binary files /dev/null and b/resources/logos/logo_recent.png differ diff --git a/resources/logos/logo_redo.png b/resources/logos/logo_redo.png new file mode 100644 index 0000000..4c0af94 Binary files /dev/null and b/resources/logos/logo_redo.png differ diff --git a/resources/logos/logo_refresh.png b/resources/logos/logo_refresh.png index e2aaa72..1b586f2 100644 Binary files a/resources/logos/logo_refresh.png and b/resources/logos/logo_refresh.png differ diff --git a/resources/logos/logo_undo.png b/resources/logos/logo_undo.png new file mode 100644 index 0000000..6748bad Binary files /dev/null and b/resources/logos/logo_undo.png differ diff --git a/resources/templates/preview_mo.ui b/resources/templates/preview_mo.ui new file mode 100644 index 0000000..4606e17 --- /dev/null +++ b/resources/templates/preview_mo.ui @@ -0,0 +1,529 @@ + + + Form + + + + 0 + 0 + 627 + 581 + + + + Form + + + + 3 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 16777215 + 23 + + + + + 14 + 75 + true + + + + Step Preview + + + + + + + + 24 + 16777215 + + + + + + + + ../logos/logo_more.png../logos/logo_more.png + + + true + + + + + + + + 24 + 16777215 + + + + + + + + ../logos/logo_less.png../logos/logo_less.png + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 3 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QLayout::SetDefaultConstraint + + + QFormLayout::FieldsStayAtSizeHint + + + + + Name + + + + + + + + + + + + + + Author + + + + + + + + + + + + + + Version + + + + + + + + + + + + + + Website + + + + + + + + + + + + + + + + Qt::Horizontal + + + false + + + + Qt::Vertical + + + false + + + + + 0 + 1 + + + + + + + + 0 + 0 + + + + + 3 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + 1 + + + Qt::Horizontal + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 16777215 + 23 + + + + + 14 + 75 + false + true + + + + Page Results + + + Qt::AlignCenter + + + + + + + + 24 + 16777215 + + + + + + + + ../logos/logo_more.png../logos/logo_more.png + + + true + + + + + + + + 24 + 16777215 + + + + + + + + ../logos/logo_less.png../logos/logo_less.png + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 3 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 16777215 + 21 + + + + + 75 + true + true + + + + Files Installed + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + QAbstractItemView::NoEditTriggers + + + 10 + + + true + + + false + + + 150 + + + 100 + + + + + + + + 0 + 0 + + + + + 16777215 + 21 + + + + + 75 + true + true + + + + Flags Set + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + QAbstractItemView::NoEditTriggers + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + false + + + + 0 + 0 + + + + Start Full Preview + + + + + + + + diff --git a/resources/templates/settings.ui b/resources/templates/settings.ui deleted file mode 100644 index ed7867a..0000000 --- a/resources/templates/settings.ui +++ /dev/null @@ -1,493 +0,0 @@ - - - Dialog - - - Qt::NonModal - - - true - - - - 0 - 0 - 565 - 261 - - - - Qt::StrongFocus - - - Qt::NoContextMenu - - - Settings - - - false - - - - - - General - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - false - - - false - - - - - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 20 - 20 - - - - - - - - Show intro window at statup. - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 20 - 20 - - - - - - - - false - - - Show the Advanced View at startup. - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 20 - 20 - - - - - - - - Preview Refresh Rate - - - - - - - - Never - - - - - On Refresh - - - - - On Node Select - - - - - On Property Editing - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - At Loading - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Validate installer. - - - false - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - true - - - Ignore errors and continue loading. - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Check installer for common errors. - - - false - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - true - - - Ignore errors and continue loading. - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - At Saving - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - QLayout::SetMinimumSize - - - - - - 0 - 0 - - - - Validate installer. - - - false - - - - - - - 6 - - - QLayout::SetMinimumSize - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - Ignore errors and continue saving. - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Check installer for common errors. - - - false - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - true - - - Ignore errors and continue saving. - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - diff --git a/resources/templates/tutorial_advanced.ui b/resources/templates/tutorial_advanced.ui new file mode 100644 index 0000000..778f78f --- /dev/null +++ b/resources/templates/tutorial_advanced.ui @@ -0,0 +1,159 @@ + + + Dialog + + + + 0 + 0 + 1115 + 659 + + + + + 0 + 0 + + + + Dialog + + + + + 20 + 210 + 241 + 121 + + + + QFrame::NoFrame + + + QFrame::Sunken + + + + + + <html><head/><body><p align="center"><span style=" font-size:14pt; color:#0c10da;">This is the Node Tree.</span></p><p align="center"><span style=" font-size:14pt; color:#0c10da;">Here you'll find the nodes that make up your installer.</span></p><p align="center"><span style=" font-size:14pt; color:#0c10da;">You can navigate the tree with the little arrows on the left side of each node.</span></p></body></html> + + + Qt::AlignCenter + + + true + + + + + + + + + 270 + 230 + 551 + 251 + + + + QFrame::NoFrame + + + QFrame::Sunken + + + + + + QFrame::Sunken + + + <html><head/><body><p align="center"><span style=" font-size:14pt; color:#0c10da;">These are the Preview Tabs.</span></p><p align="center"><span style=" font-size:14pt; color:#0c10da;">Here you can preview what your installer looks like and what the XML code will be once you save.</span></p></body></html> + + + Qt::AlignCenter + + + true + + + + + + + Continue + + + + + + + + + 850 + 10 + 241 + 271 + + + + QFrame::NoFrame + + + QFrame::Sunken + + + + + + <html><head/><body><p align="center"><span style=" font-size:14pt; color:#0c10da;">This is the Property Editor.</span></p><p align="center"><span style=" font-size:14pt; color:#0c10da;">Here you can edit the individual properties each node has.</span></p></body></html> + + + Qt::AlignCenter + + + true + + + + + + + + + 850 + 320 + 241 + 271 + + + + QFrame::NoFrame + + + QFrame::Sunken + + + + + + <html><head/><body><p align="center"><span style=" font-size:14pt; color:#0c10da;">This is the Children Box.</span></p><p align="center"><span style=" font-size:14pt; color:#0c10da;">Here you can view which children nodes are available to the currently selected node and add them if possible.</span></p><p align="center"><span style=" font-size:14pt; color:#0c10da;">You can only have one of some children while others are available infinitely.</span></p></body></html> + + + Qt::AlignCenter + + + true + + + + + + + + + diff --git a/resources/templates/about.ui b/resources/templates/window_about.ui similarity index 93% rename from resources/templates/about.ui rename to resources/templates/window_about.ui index 5291e58..13b3c9a 100644 --- a/resources/templates/about.ui +++ b/resources/templates/window_about.ui @@ -9,7 +9,7 @@ 0 0 - 334 + 340 355 @@ -21,13 +21,13 @@ - 334 + 340 355 - 334 + 340 355 @@ -101,7 +101,7 @@ - Special Thanks to Hishutup. + <html><head/><body><p>Special Thanks to <a href="http://forum.step-project.com/user/3928-hishutup/"><span style=" text-decoration: underline; color:#0000ff;">Hishutup</span></a>.</p></body></html> Qt::AlignCenter diff --git a/resources/templates/intro.ui b/resources/templates/window_intro.ui similarity index 100% rename from resources/templates/intro.ui rename to resources/templates/window_intro.ui diff --git a/resources/templates/mainframe.ui b/resources/templates/window_mainframe.ui similarity index 76% rename from resources/templates/mainframe.ui rename to resources/templates/window_mainframe.ui index b92641c..46aa641 100644 --- a/resources/templates/mainframe.ui +++ b/resources/templates/window_mainframe.ui @@ -6,8 +6,8 @@ 0 0 - 800 - 563 + 1115 + 659 @@ -43,25 +43,11 @@ Preview - - - - - <html><head/><body><p>The preview is not ready yet!</p><p>Meanwhile, try to install your mod using NMM or MO to check if everything is ok.</p></body></html> - - - Qt::AlignCenter - - - true - - - - + - XML Code + XML Preview @@ -102,7 +88,7 @@ 250 - 59 + 63 @@ -118,73 +104,17 @@ 2 - - - 5 - - - 0 - - - 5 - - - 0 - - - - - - - - true - - - - 0 - 0 - - - - - 8 - - - - Start Wizard - - - false - - - false - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - + - + true 250 - 93 + 222 @@ -200,13 +130,13 @@ Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea - Object Tree + Node Tree 1 - + 5 @@ -220,7 +150,34 @@ 0 - + + + true + + + + 0 + 0 + + + + + 8 + + + + Start Wizard + + + false + + + false + + + + + true @@ -236,12 +193,33 @@ 0 + + true + + + true + + + QAbstractItemView::InternalMove + + + Qt::MoveAction + + + true + + + 10 + + + true + - + 250 @@ -255,7 +233,7 @@ Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea - Object Box + Children Box 2 @@ -298,7 +276,7 @@ 0 0 - 800 + 1115 21 @@ -313,10 +291,15 @@ &Recent Files + + + ../logos/logo_recent.png../logos/logo_recent.png + + @@ -325,8 +308,18 @@ &Tools + + + + + + + + + + @@ -399,7 +392,7 @@ ../logos/logo_gear.png../logos/logo_gear.png - O&ptions + Settings Settings @@ -436,6 +429,9 @@ + + false + ../logos/logo_cross.png../logos/logo_cross.png @@ -447,7 +443,7 @@ Delete the currently selected node. - Ctrl+D + Del Qt::WindowShortcut @@ -540,12 +536,11 @@ Toggle the visibility of the Object Box. - - - 1 - - + + + ../logos/logo_clear.png../logos/logo_clear.png + Clear @@ -553,6 +548,90 @@ Clear all the recent files. + + + + ../logos/logo_copy.png../logos/logo_copy.png + + + Copy + + + Ctrl+C + + + + + false + + + + ../logos/logo_paste.png../logos/logo_paste.png + + + Paste + + + Ctrl+V + + + + + false + + + + ../logos/logo_undo.png../logos/logo_undo.png + + + Undo + + + Ctrl+Z + + + Qt::WindowShortcut + + + + + false + + + + ../logos/logo_redo.png../logos/logo_redo.png + + + Redo + + + Ctrl+Shift+Z + + + + + + ../logos/logo_expand.png../logos/logo_expand.png + + + Expand All + + + Ctrl+* + + + + + + ../logos/logo_collapse.png../logos/logo_collapse.png + + + Collapse All + + + Ctrl+. + + diff --git a/resources/templates/window_plaintexteditor.ui b/resources/templates/window_plaintexteditor.ui new file mode 100644 index 0000000..1649cfe --- /dev/null +++ b/resources/templates/window_plaintexteditor.ui @@ -0,0 +1,70 @@ + + + Dialog + + + + 0 + 0 + 247 + 195 + + + + Text Editor + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + true + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/resources/templates/window_settings.ui b/resources/templates/window_settings.ui new file mode 100644 index 0000000..8a15b64 --- /dev/null +++ b/resources/templates/window_settings.ui @@ -0,0 +1,1763 @@ + + + Dialog + + + Qt::NonModal + + + true + + + + 0 + 0 + 565 + 396 + + + + Qt::StrongFocus + + + Qt::NoContextMenu + + + Settings + + + false + + + + + + QTabWidget::North + + + QTabWidget::Rounded + + + 0 + + + Qt::ElideNone + + + false + + + + General + + + + + + Show intro window at statup. + + + + + + + Qt::Horizontal + + + + + + + false + + + Show the Advanced View at startup. + + + + + + + Qt::Horizontal + + + + + + + Show tutorial at startup. + + + + + + + Qt::Horizontal + + + + + + + + + Preview Refresh Rate + + + + + + + + Never + + + + + On Refresh + + + + + On Node Select + + + + + On Property Editing + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + check_intro + check_advanced + verticalSpacer_7 + line + line_2 + check_tutorial + line_10 + + + + Appearance + + + + + + + 10 + 75 + true + + + + Special Button Colours + + + + + + + + + Required + + + + + + + + 40 + 16777215 + + + + + + + + + + + Reset to Default + + + + + + + + + + + At Least One + + + + + + + + 40 + 16777215 + + + + + + + + + + + Reset to Default + + + + + + + + + + + Either + + + + + + + + 40 + 16777215 + + + + + + + + + + + Reset to Default + + + + + + + + + 0 + + + Qt::Horizontal + + + + + + + + + 0 + + + Style + + + + + + + + Default + + + + + Windows + + + + + Fusion + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 20 + 20 + + + + + + + ../logos/logo_danger.png + + + true + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + This setting requires a restart to take effect. + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + + + Qt::Horizontal + + + + + + + + + Palette + + + + + + + + Default + + + + + aliceblue + + + + + antiquewhite + + + + + aqua + + + + + aquamarine + + + + + azure + + + + + beige + + + + + bisque + + + + + black + + + + + blanchedalmond + + + + + blue + + + + + blueviolet + + + + + brown + + + + + burlywood + + + + + cadetblue + + + + + chartreuse + + + + + chocolate + + + + + coral + + + + + cornflowerblue + + + + + cornsilk + + + + + crimson + + + + + cyan + + + + + darkblue + + + + + darkcyan + + + + + darkgoldenrod + + + + + darkgray + + + + + darkgreen + + + + + darkgrey + + + + + darkkhaki + + + + + darkmagenta + + + + + darkolivegreen + + + + + darkorange + + + + + darkorchid + + + + + darkred + + + + + darksalmon + + + + + darkseagreen + + + + + darkslateblue + + + + + darkslategray + + + + + darkturquoise + + + + + darkviolet + + + + + deeppink + + + + + deepskyblue + + + + + dimgray + + + + + dodgerblue + + + + + firebrick + + + + + floralwhite + + + + + forestgreen + + + + + fuchsia + + + + + gainsboro + + + + + ghostwhite + + + + + gold + + + + + goldenrod + + + + + gray + + + + + green + + + + + greenyellow + + + + + honeydew + + + + + hotpink + + + + + indianred + + + + + indigo + + + + + ivory + + + + + khaki + + + + + lavender + + + + + lavenderblush + + + + + lawngreen + + + + + lemonchiffon + + + + + lightblue + + + + + lightcoral + + + + + lightcyan + + + + + lightgoldenrodyellow + + + + + lightgray + + + + + lightgreen + + + + + lightpink + + + + + lightsalmon + + + + + lightseagreen + + + + + lightskyblue + + + + + lightslategray + + + + + lightsteelblue + + + + + lightyellow + + + + + lime + + + + + limegreen + + + + + linen + + + + + magenta + + + + + maroon + + + + + mediumaquamarine + + + + + mediumblue + + + + + mediumorchid + + + + + mediumpurple + + + + + mediumseagreen + + + + + mediumslateblue + + + + + mediumspringgreen + + + + + mediumturquoise + + + + + mediumvioletred + + + + + midnightblue + + + + + mintcream + + + + + mistyrose + + + + + moccasin + + + + + navajowhite + + + + + navy + + + + + oldlace + + + + + olive + + + + + olivedrab + + + + + orange + + + + + orangered + + + + + orchid + + + + + palegoldenrod + + + + + palegreen + + + + + paleturquoise + + + + + palevioletred + + + + + papayawhip + + + + + peachpuff + + + + + peru + + + + + pink + + + + + plum + + + + + powderblue + + + + + purple + + + + + red + + + + + rosybrown + + + + + royalblue + + + + + saddlebrown + + + + + salmon + + + + + sandybrown + + + + + seagreen + + + + + seashell + + + + + sienna + + + + + silver + + + + + skyblue + + + + + slateblue + + + + + slategray + + + + + snow + + + + + springgreen + + + + + steelblue + + + + + tan + + + + + teal + + + + + thistle + + + + + tomato + + + + + turquoise + + + + + violet + + + + + wheat + + + + + white + + + + + whitesmoke + + + + + yellow + + + + + yellowgreen + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 20 + 20 + + + + + + + ../logos/logo_danger.png + + + true + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + This setting requires a restart to take effect. + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Loading + + + + + + + + Validate installer. + + + true + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 20 + 20 + + + + + + + + true + + + Ignore errors and continue loading. + + + + + + + + + + + Qt::Horizontal + + + + + + + + + Check installer for common errors. + + + true + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 20 + 20 + + + + + + + + true + + + Ignore errors and continue loading. + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Saving + + + + + + QLayout::SetMinimumSize + + + + + + 0 + 0 + + + + Validate installer. + + + true + + + + + + + 6 + + + QLayout::SetMinimumSize + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + Ignore errors and continue saving. + + + + + + + + + + + Qt::Horizontal + + + + + + + + + Check installer for common errors. + + + true + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 20 + 20 + + + + + + + + true + + + Ignore errors and continue saving. + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Defaults + + + + + + + + + 10 + 75 + true + + + + Node Name + + + + + + + + 10 + 75 + true + + + + Property Name + + + + + + + + 10 + 75 + true + + + + Default Value + + + + + + + + + 1 + + + 1 + + + Qt::Horizontal + + + + + + + + + Installation Steps + + + true + + + + + + + Order + + + + + + + + Explicit + + + + + Ascending + + + + + Descending + + + + + + + + + + Qt::Horizontal + + + + + + + + + Option Group + + + true + + + + + + + Order + + + + + + + + Explicit + + + + + Ascending + + + + + Descending + + + + + + + + + + Qt::Horizontal + + + + + + + + + Type + + + true + + + + + + + Type + + + + + + + + Optional + + + + + Required + + + + + Recommended + + + + + CouldBeUsable + + + + + NotUsable + + + + + + + + + + Qt::Horizontal + + + + + + + + + Default Type + + + true + + + + + + + Type + + + + + + + + Optional + + + + + Required + + + + + Recommended + + + + + CouldBeUsable + + + + + NotUsable + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + diff --git a/resources/templates/window_texteditor.ui b/resources/templates/window_texteditor.ui new file mode 100644 index 0000000..5274cde --- /dev/null +++ b/resources/templates/window_texteditor.ui @@ -0,0 +1,340 @@ + + + Dialog + + + + 0 + 0 + 235 + 219 + + + + Text Editor + + + + + + + + Output: + + + + + + + To Plain Text + + + true + + + + + + + To HTML + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + + + + + + 48 + 16777215 + + + + + + + + ../logos/logo_font_colour.png../logos/logo_font_colour.png + + + + + + + + 48 + 16777215 + + + + + + + + ../logos/logo_font_bold.png../logos/logo_font_bold.png + + + + + + + + 48 + 16777215 + + + + + + + + ../logos/logo_font_italic.png../logos/logo_font_italic.png + + + + + + + + 48 + 16777215 + + + + + + + + ../logos/logo_font_underline.png../logos/logo_font_underline.png + + + + + + + + 48 + 16777215 + + + + + + + + ../logos/logo_font_align_left.png../logos/logo_font_align_left.png + + + + + + + + 48 + 16777215 + + + + + + + + ../logos/logo_font_align_center.png../logos/logo_font_align_center.png + + + + + + + + 48 + 16777215 + + + + + + + + ../logos/logo_font_align_right.png../logos/logo_font_align_right.png + + + + + + + + 48 + 16777215 + + + + + + + + ../logos/logo_font_align_justify.png../logos/logo_font_align_justify.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + 3 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 20 + 20 + + + + + + + ../logos/logo_danger.png + + + true + + + + + + + This may not work in all mod managers. + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + true + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/resources/templates/wizard_depend_01.ui b/resources/templates/wizard_depend_01.ui new file mode 100644 index 0000000..e9acfa9 --- /dev/null +++ b/resources/templates/wizard_depend_01.ui @@ -0,0 +1,370 @@ + + + Form + + + + 0 + 0 + 470 + 560 + + + + Form + + + + + + + 0 + 0 + + + + + 0 + 40 + + + + + 14 + 75 + true + + + + Dependencies Wizard + + + Qt::AlignCenter + + + + + + + <html><head/><body><p>TODO</p><p>See the <span style=" text-decoration: underline;">Help</span> for more information.</p></body></html> + + + + + + + + + Type + + + + + + + + And + + + + + Or + + + + + + + + Game Version + + + + + + + + + + + + + 75 + true + + + + File Dependencies + + + Qt::AlignCenter + + + + + + + Add File + + + + + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOn + + + true + + + + + 0 + 0 + 433 + 68 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 58 + + + + + + + + + + + + + 75 + true + + + + Flag Dependencies + + + Qt::AlignCenter + + + + + + + Add Flag + + + + + + + QFrame::StyledPanel + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOn + + + true + + + + + 0 + 0 + 433 + 68 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 58 + + + + + + + + + + + + + 75 + true + + + + Sub-Dependencies + + + Qt::AlignCenter + + + + + + + Add Sub + + + + + + + QFrame::StyledPanel + + + Qt::ScrollBarAlwaysOn + + + true + + + + + 0 + 0 + 433 + 68 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 60 + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Finish + + + + + + + + 0 + 0 + + + + Cancel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + diff --git a/resources/templates/wizard_depend_depend.ui b/resources/templates/wizard_depend_depend.ui new file mode 100644 index 0000000..af17a72 --- /dev/null +++ b/resources/templates/wizard_depend_depend.ui @@ -0,0 +1,146 @@ + + + Form + + + + 0 + 0 + 550 + 130 + + + + Form + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + + Type: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + More... + + + + + + + Less... + + + + + + + Edit + + + + + + + + 30 + 16777215 + + + + + + + + ../logos/logo_cross.png../logos/logo_cross.png + + + + + + + + + Qt::Horizontal + + + + + + + true + + + + + 0 + 0 + 542 + 81 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 265 + + + + + + + + + + + + + diff --git a/resources/templates/wizard_depend_depend_depend.ui b/resources/templates/wizard_depend_depend_depend.ui new file mode 100644 index 0000000..fd1e444 --- /dev/null +++ b/resources/templates/wizard_depend_depend_depend.ui @@ -0,0 +1,50 @@ + + + Form + + + + 0 + 0 + 345 + 30 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Sub-Dependency + + + + + + + + diff --git a/resources/templates/wizard_depend_depend_file.ui b/resources/templates/wizard_depend_depend_file.ui new file mode 100644 index 0000000..bd0b642 --- /dev/null +++ b/resources/templates/wizard_depend_depend_file.ui @@ -0,0 +1,67 @@ + + + Form + + + + 0 + 0 + 345 + 30 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + File: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + Type: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + diff --git a/resources/templates/wizard_depend_depend_flag.ui b/resources/templates/wizard_depend_depend_flag.ui new file mode 100644 index 0000000..3c8d661 --- /dev/null +++ b/resources/templates/wizard_depend_depend_flag.ui @@ -0,0 +1,67 @@ + + + Form + + + + 0 + 0 + 345 + 30 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Flag: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + Value: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + diff --git a/resources/templates/wizard_depend_depend_version.ui b/resources/templates/wizard_depend_depend_version.ui new file mode 100644 index 0000000..bee8892 --- /dev/null +++ b/resources/templates/wizard_depend_depend_version.ui @@ -0,0 +1,50 @@ + + + Form + + + + 0 + 0 + 345 + 30 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Version: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + diff --git a/resources/templates/wizard_depend_file.ui b/resources/templates/wizard_depend_file.ui new file mode 100644 index 0000000..bb3c2a8 --- /dev/null +++ b/resources/templates/wizard_depend_file.ui @@ -0,0 +1,86 @@ + + + Form + + + + 0 + 0 + 345 + 30 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + File: + + + + + + + + + + Type: + + + + + + + + Missing + + + + + Inactive + + + + + Active + + + + + + + + + 30 + 16777215 + + + + + + + + ../logos/logo_cross.png../logos/logo_cross.png + + + + + + + + diff --git a/resources/templates/wizard_depend_flag.ui b/resources/templates/wizard_depend_flag.ui new file mode 100644 index 0000000..6e2c426 --- /dev/null +++ b/resources/templates/wizard_depend_flag.ui @@ -0,0 +1,70 @@ + + + Form + + + + 0 + 0 + 320 + 31 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Flag: + + + + + + + + + + Value: + + + + + + + + + + + 30 + 16777215 + + + + + + + + ../logos/logo_cross.png../logos/logo_cross.png + + + + + + + + diff --git a/setup.cfg b/setup.cfg index 11ef423..5daa5b5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.6.0 +current_version = 0.7.0 current_build = 0 [bdist_wheel] diff --git a/tasks.py b/tasks.py index 01d5843..f07c362 100644 --- a/tasks.py +++ b/tasks.py @@ -34,6 +34,20 @@ def enter(): @task +def gen_ui(): + from os import listdir, remove + from os.path import join, isfile + from PyQt5.uic import compileUiDir + + target_dir = "designer/ui_templates" + init_fname = "__init__.py" + for item in listdir(target_dir): + if item != init_fname and isfile(join(target_dir, item)): + remove(join(target_dir, item)) + compileUiDir("resources/templates", map=lambda dir, fname: (target_dir, fname), from_imports=True) + + +@task(gen_ui) def preview(): run("python dev/pyinstaller-bootstrap.py") @@ -47,7 +61,7 @@ def clean(): print("Build caches cleaned.") -@task(clean) +@task(clean, ) def build(): from platform import system, architecture from shutil import copy