diff --git a/soitool/main_window.py b/soitool/main_window.py index 1adeebd03878548824c404683c4d025bd41f8c33..7167a07ece55c83d5a7eceee40e5aeb06437ba3b 100644 --- a/soitool/main_window.py +++ b/soitool/main_window.py @@ -122,20 +122,19 @@ class SOIWorkspaceWidget(QWidget): self.button_new_module.setShortcut("Ctrl+m") self.button_new_module.setStatusTip("Legg til en ny modul") self.button_setup = QPushButton("Oppsett") - self.list_modules = QListWidget() + module_names = self.soi.get_module_names(True) + attachment_names = self.soi.get_module_names(False) + self.list_modules = ModuleList(module_names, True, self) + self.list_attachments = ModuleList(attachment_names, False, self) self.view = InlineEditableSOIView(self.soi) self.widget_sidebar = QWidget() self.widget_sidebar.setFixedWidth(200) - # prepare module list - self.setup_list_modules() - self.fill_list_modules() - # build layouts self.layout_sidebar.addWidget(QLabel("Moduler:")) self.layout_sidebar.addWidget(self.list_modules, 5) self.layout_sidebar.addWidget(QLabel("Vedlegg:")) - self.layout_sidebar.addWidget(QListWidget(), 1) + self.layout_sidebar.addWidget(self.list_attachments, 1) self.layout_sidebar.addWidget(self.button_new_module) self.layout_sidebar.addWidget(self.button_setup) self.widget_sidebar.setLayout(self.layout_sidebar) @@ -144,35 +143,6 @@ class SOIWorkspaceWidget(QWidget): self.setLayout(self.layout_wrapper) - def setup_list_modules(self): - """Prepare module list. - - The list contains modules that are drag-and-droppable. - """ - # enable drag-and-drop - self.list_modules.setDragEnabled(True) - self.list_modules.viewport().setAcceptDrops(True) - self.list_modules.viewport().setAcceptDrops(True) - self.list_modules.setDragDropMode(QAbstractItemView.InternalMove) - - # source: https://www.qtcentre.org/threads/32500-Horizontal-Scrolling-QListWidget - self.list_modules.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - - def fill_list_modules(self): - """Fill module list with some items to manually test with. - - This function will be removed when we can fill the list properly. - """ - # hardcode some items - items = [ - QListWidgetItem("Frekvenstabell"), - QListWidgetItem("Sambandsdiagram"), - QListWidgetItem("Autentifiseringstavle"), - QListWidgetItem("Subtraktorkoder"), - ] - for i, item in enumerate(items): - self.list_modules.insertItem(i, item) - class SOI(): """Temporary representation of SOI. @@ -204,7 +174,8 @@ class SOI(): "meta": { "x": 0, "y": 0, - "page": 1 + "page": 1, + "name": 'Tabell1' } }, { @@ -212,7 +183,8 @@ class SOI(): "meta": { "x": 0, "y": 0, - "page": 1 + "page": 1, + "name": 'Tabell2' } }, { @@ -220,7 +192,22 @@ class SOI(): "meta": { "x": 0, "y": 0, - "page": 2 + "page": 2, + "name": 'Tabell3' + } + } + ] + + # NOTE + # test attachments, just to have something show up on screen + self.attachments = [ + { + "widget": TableModule(), + "meta": { + "x": 0, + "y": 0, + "page": 2, + "name": 'Tabell1' } } ] @@ -287,6 +274,53 @@ class SOI(): widget_width, _ = module["widget"].get_size() x = x + self.MODULE_PADDING + widget_width + def get_module_names(self, is_modules): + """Return the names of all modules or attachment-modules. + + Parameters + ---------- + is_modules : bool + Return module-names if True, attachment-names if False. + """ + if is_modules: + return(module["meta"]["name"] for module in self.modules) + + return(attachm["meta"]["name"] for attachm in self.attachments) + + def update_module_name(self, is_modules, index, name): + """Update name of a module or attachment-module. + + Parameters + ---------- + is_modules : bool + Update module-name if True, attachment-name if False. + index : int + Index of module/attachment in list. + name : string + New name of module/attachment. + """ + if is_modules: + self.modules[index]["meta"]["name"] = name + else: + self.attachments[index]["meta"]["name"] = name + + def update_module_priority(self, is_modules, from_index, to_index): + """Update priority (order) of module or attachment-module. + + Parameters + ---------- + is_modules : bool + Change module-priority if True, attachment-priority if False. + from_index : int + What index the module/attachment is to be moved from. + to_index : int + What index the module/attachment is to be moved to. + """ + if is_modules: + self.modules.insert(to_index, self.modules.pop(from_index)) + else: + self.attachments.insert(to_index, self.attachments.pop(from_index)) + class InlineEditableSOIView(QScrollArea): """Widget som kan byttes ut med view, edit etc.""" @@ -481,6 +515,139 @@ class InlineEditableSOIView(QScrollArea): self.view.translate(delta.x(), delta.y()) +class ModuleList(QListWidget): + """Contains module-names from soitool.SOI. + + List elements are names of modules or attachment-modules from soitool.SOI. + List elements are editable, drag-and-droppable and unique (no duplicates). + Notifies soitool.SOI about changes through its parent-variable. + + Parameters + ---------- + names : List of strings + Names of modules or attachment-modules from soitool.SOI + is_modules : bool + Determines whether names are from modules or attachment-modules. + Is used to tell parent what list to update on changes. + True if names are module-names, False if names are attachment-names. + parent : soitool.SOIWorkspaceWidget + Reference to parent, which is used to notify about changes. + """ + + def __init__(self, names, is_modules, parent): + super().__init__() + + if not isinstance(parent, SOIWorkspaceWidget): + raise RuntimeError('Only soitool.SOIWorkspaceWidget is ' + 'acceptable type for parent-variable ' + 'in class Module_list.') + + self.is_modules = is_modules + self.parent = parent + self.original_element_name = None + self.original_element_index = None + + self.setup_list() + self.fill_list(names) + + def setup_list(self): + """Prepare list. + + Make list drag-and-droppable and remove horizontal scrollbar. + """ + # Enable drag-and-drop + self.setDragEnabled(True) + self.viewport().setAcceptDrops(True) + self.viewport().setAcceptDrops(True) + self.setDragDropMode(QAbstractItemView.InternalMove) + + # Remove horizontal scrollbar + self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + + def fill_list(self, names): + """Fill list with elements. + + Parameters + ---------- + names : List of strings + Elements to be added. + """ + for i, name in enumerate(names): + item = QListWidgetItem(name) + item.setFlags(item.flags() | Qt.ItemIsEditable) + self.insertItem(i, item) + + def currentChanged(self, current, previous): + """Save name and index of an element when it is selected. + + Function is needed to remember original: + 1: index of an element in case it's' drag-and-dropped (notify parent). + 2: name of an element in case it's name changes (avoid duplicates). + + https://doc.qt.io/qt-5/qlistview.html#currentChanged. + + Parameters + ---------- + current : QModelIndex + Used to get index of element, is sent to super(). + previous : QModelIndex + Is sent to super(). + """ + super().currentChanged(current, previous) + self.original_element_name = self.item(current.row()).text() + self.original_element_index = current.row() + + def dataChanged(self, index1, index2, roles): + """Check for duplicate name and notify parent when an element changes. + + https://doc.qt.io/qt-5/qabstractitemview.html#dataChanged. + + Parameters + ---------- + index1 : QModelIndex + Used to get index of element, is sent to super(). + index2 : QModelIndex + Is sent to super(). + roles : QVector + Is sent to super(). + """ + index = index1.row() + # Get all names and new name + names = [self.item(i).text() for i in range(self.count())] + new_name = names[index] + + # Count occurances of new name + occurances = names.count(new_name) + + # If new name already exists, replace with original name + if occurances > 1: + self.item(index).setText(self.original_element_name) + # Name does not already exist, update list in soi + else: + name = self.item(index).text() + self.parent.soi.update_module_name(self.is_modules, index, name) + + super().dataChanged(index1, index2, roles) + + def dropEvent(self, event): + """Notify parent when an element is drag-and-dropped. + + https://doc.qt.io/qt-5/qabstractitemview.html#dropEvent. + + Parameters + ---------- + event : QDropEvent + Is sent to super(). + """ + super().dropEvent(event) + + orig = self.original_element_index + dest = self.currentRow() + + self.parent.soi.update_module_priority(self.is_modules, orig, dest) + self.original_element_index = self.currentRow() + + if __name__ == "__main__": app = QApplication(sys.argv) WINDOW = MainWindow()