399 lines
19 KiB
Python
399 lines
19 KiB
Python
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QCheckBox, QToolTip, QTreeWidget, QTreeWidgetItem, QHBoxLayout, QLabel, QScrollArea
|
|
from PyQt5.QtCore import Qt
|
|
from PyQt5.QtGui import QColor
|
|
import logging
|
|
from logline_leviathan.database.database_manager import EntitiesTable, DistinctEntitiesTable, EntityTypesTable, FileMetadata, session_scope
|
|
|
|
class CustomCheckBox(QCheckBox):
|
|
def __init__(self, *args, **kwargs):
|
|
super(CustomCheckBox, self).__init__(*args, **kwargs)
|
|
self.setMouseTracking(True) # Enable mouse tracking
|
|
self.setStyleSheet("QCheckBox { color: white; }")
|
|
|
|
def mouseMoveEvent(self, event):
|
|
QToolTip.showText(event.globalPos(), self.toolTip()) # Show tooltip at mouse position
|
|
super(CustomCheckBox, self).mouseMoveEvent(event)
|
|
|
|
class FileCheckboxItem(QWidget):
|
|
def __init__(self, text, parent=None):
|
|
super(FileCheckboxItem, self).__init__(parent)
|
|
layout = QHBoxLayout(self)
|
|
|
|
self.checkBox = QCheckBox()
|
|
self.checkBox.setChecked(True)
|
|
self.label = QLabel(text)
|
|
self.label.setStyleSheet("QLabel { color: white; }") # Set text color
|
|
|
|
layout.addWidget(self.checkBox)
|
|
layout.addWidget(self.label)
|
|
layout.addStretch(1) # Add stretch factor to push content to the left
|
|
|
|
self.setLayout(layout)
|
|
|
|
class CheckboxPanel(QWidget):
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
layout = QVBoxLayout(self)
|
|
|
|
self.treeWidget = QTreeWidget()
|
|
self.treeWidget.setHeaderHidden(True)
|
|
self.treeWidget.setStyleSheet("""
|
|
QTreeWidget::branch {color: white; /* White color for branches */
|
|
}
|
|
""")
|
|
layout.addWidget(self.treeWidget)
|
|
|
|
def _addChildren(self, parentItem, parent_entity_type, db_session, used_ids, depth=0):
|
|
try:
|
|
# Log the depth of recursion
|
|
#logging.debug(f"Adding children at depth: {depth}, parent entity type: {parent_entity_type}")
|
|
|
|
child_entity_types = db_session.query(EntityTypesTable).filter(EntityTypesTable.parent_type == parent_entity_type).all()
|
|
for child_entity_type in child_entity_types:
|
|
count = db_session.query(EntitiesTable).filter(EntitiesTable.entity_types_id == child_entity_type.entity_type_id).count()
|
|
text = f"{child_entity_type.gui_name}"
|
|
childItem = QTreeWidgetItem(parentItem)
|
|
|
|
isCheckable = not child_entity_type.entity_type.startswith("category_")
|
|
childItem.setFlags(childItem.flags() | Qt.ItemIsUserCheckable) if isCheckable else None
|
|
childItem.setCheckState(0, Qt.Unchecked) if isCheckable else None
|
|
text += f" ({count} Erwähnungen)" if isCheckable else ""
|
|
childItem.setText(0, text)
|
|
childItem.setToolTip(0, child_entity_type.gui_tooltip)
|
|
childItem.entity_type_id = child_entity_type.entity_type_id
|
|
childItem.entity_type = child_entity_type.entity_type
|
|
if child_entity_type.entity_type_id in used_ids and not child_entity_type.parser_enabled == False:
|
|
color = QColor('green')
|
|
elif not child_entity_type.entity_type.startswith("category_") and not child_entity_type.parser_enabled == True:
|
|
color = QColor('red')
|
|
else:
|
|
color = QColor('white')
|
|
childItem.setForeground(0, color)
|
|
|
|
# Recursive call with increased depth
|
|
depth = depth + 1
|
|
self._addChildren(childItem, child_entity_type.entity_type, db_session, used_ids, depth)
|
|
except Exception as e:
|
|
logging.error(f"Error adding children: {e}")
|
|
|
|
|
|
|
|
def updateCheckboxes(self, db_session):
|
|
#logging.info("Updating checkboxes with database content")
|
|
with session_scope() as db_session:
|
|
try:
|
|
# Query database for entity types
|
|
entity_types = db_session.query(EntityTypesTable).all()
|
|
used_ids = {d.entity_types_id for d in db_session.query(DistinctEntitiesTable.entity_types_id).distinct()}
|
|
#logging.debug(f"Used IDs: {used_ids}")
|
|
# Clear existing items
|
|
self.treeWidget.clear()
|
|
rootItems = {}
|
|
|
|
# Construct hierarchical tree structure
|
|
for entity_type in entity_types:
|
|
if entity_type.parent_type != 'root': # Skip non-root items
|
|
continue
|
|
|
|
count = db_session.query(EntitiesTable).filter(EntitiesTable.entity_types_id == entity_type.entity_type_id).count()
|
|
text = f"{entity_type.gui_name}"
|
|
treeItem = QTreeWidgetItem()
|
|
treeItem.setToolTip(0, entity_type.gui_tooltip)
|
|
treeItem.entity_type_id = entity_type.entity_type_id
|
|
treeItem.entity_type = entity_type.entity_type
|
|
if not entity_type.entity_type.startswith("category_"):
|
|
treeItem.setFlags(treeItem.flags() | Qt.ItemIsUserCheckable)
|
|
treeItem.setCheckState(0, Qt.Unchecked)
|
|
text = f"{entity_type.gui_name} ({count} Erwähnungen)"
|
|
treeItem.setText(0, text)
|
|
# Add item to tree widget
|
|
self.treeWidget.addTopLevelItem(treeItem)
|
|
rootItems[entity_type.entity_type_id] = treeItem
|
|
|
|
# Call recursive function to add children
|
|
self._addChildren(treeItem, entity_type.entity_type, db_session, used_ids)
|
|
# Optionally expand all tree items
|
|
self.treeWidget.expandAll()
|
|
|
|
except Exception as e:
|
|
logging.error("Error updating checkboxes", exc_info=True)
|
|
|
|
def filterCheckboxes(self, filter_text):
|
|
def filterTreeItem(treeItem):
|
|
# Check if the current item or any of its properties match the filter text
|
|
try:
|
|
match = filter_text.lower() in treeItem.text(0).lower() or filter_text.lower() in treeItem.toolTip(0).lower()
|
|
except Exception as e:
|
|
logging.error(f"Error checking filter match for tree item: {e}")
|
|
match = False
|
|
|
|
# Recursively check child items and set 'childMatch' if any child matches
|
|
childMatch = False
|
|
for j in range(treeItem.childCount()):
|
|
if filterTreeItem(treeItem.child(j)):
|
|
childMatch = True
|
|
|
|
# Unhide the item and its parents if there's a match in the item or its children
|
|
if match or childMatch:
|
|
treeItem.setHidden(False)
|
|
parent = treeItem.parent()
|
|
while parent:
|
|
parent.setHidden(False)
|
|
parent = parent.parent()
|
|
return True
|
|
else:
|
|
treeItem.setHidden(True)
|
|
return False
|
|
|
|
# Filter all top-level items
|
|
for i in range(self.treeWidget.topLevelItemCount()):
|
|
filterTreeItem(self.treeWidget.topLevelItem(i))
|
|
|
|
|
|
def checkAllVisible(self):
|
|
with session_scope() as db_session:
|
|
used_ids = self.getUsedIds(db_session)
|
|
self._setCheckStateForVisibleItems(Qt.Checked, used_ids)
|
|
|
|
def uncheckAllVisible(self):
|
|
with session_scope() as db_session:
|
|
used_ids = self.getUsedIds(db_session)
|
|
self._setCheckStateForVisibleItems(Qt.Unchecked, used_ids)
|
|
|
|
|
|
|
|
def _setCheckStateForVisibleItems(self, state, used_ids):
|
|
def setCheckState(item):
|
|
try:
|
|
if (item.flags() & Qt.ItemIsUserCheckable) and not item.isHidden(): # and item.parent():
|
|
# Check if entity_type_id is in used_ids
|
|
if hasattr(item, 'entity_type_id') and item.entity_type_id in used_ids:
|
|
item.setCheckState(0, state)
|
|
#logging.debug(f"Set check state for item with entity_type_id: {item.entity_type_id}")
|
|
#else:
|
|
#logging.debug(f"Item with entity_type_id: {getattr(item, 'entity_type_id', 'N/A')} skipped")
|
|
|
|
for i in range(item.childCount()):
|
|
childItem = item.child(i)
|
|
setCheckState(childItem)
|
|
except Exception as e:
|
|
logging.error(f"Error in setCheckState: {e}")
|
|
|
|
try:
|
|
for i in range(self.treeWidget.topLevelItemCount()):
|
|
topItem = self.treeWidget.topLevelItem(i)
|
|
setCheckState(topItem)
|
|
except Exception as e:
|
|
logging.error(f"Error in _setCheckStateForVisibleItems: {e}")
|
|
|
|
|
|
|
|
def getUsedIds(self, db_session):
|
|
# Assuming db_session is your database session object
|
|
try:
|
|
used_ids = {d.entity_types_id for d in db_session.query(DistinctEntitiesTable.entity_types_id).distinct()}
|
|
return used_ids
|
|
except Exception as e:
|
|
logging.error(f"Error in getUsedIds: {e}")
|
|
return set()
|
|
|
|
def expandAllTreeItems(self):
|
|
for i in range(self.treeWidget.topLevelItemCount()):
|
|
self._expandCollapseRecursive(self.treeWidget.topLevelItem(i), True)
|
|
|
|
def collapseAllTreeItems(self):
|
|
for i in range(self.treeWidget.topLevelItemCount()):
|
|
self._expandCollapseRecursive(self.treeWidget.topLevelItem(i), False)
|
|
|
|
def _expandCollapseRecursive(self, treeItem, expand=True):
|
|
if treeItem is not None:
|
|
treeItem.setExpanded(expand)
|
|
for j in range(treeItem.childCount()):
|
|
self._expandCollapseRecursive(treeItem.child(j), expand)
|
|
|
|
class DatabasePanel(QWidget):
|
|
def __init__(self):
|
|
super().__init__()
|
|
layout = QVBoxLayout(self)
|
|
self.treeWidget = QTreeWidget()
|
|
self.treeWidget.setHeaderHidden(True) # Hide the header
|
|
self.treeWidget.setStyleSheet("""QTreeWidget::branch {color: white; /* White color for branches */}""")
|
|
layout.addWidget(self.treeWidget)
|
|
|
|
|
|
def _getTotalCountForChildren(self, entity_type, db_session):
|
|
# Recursive function to get total count
|
|
total_count = db_session.query(EntitiesTable).filter(EntitiesTable.entity_types_id == entity_type.entity_type_id).count()
|
|
child_entity_types = db_session.query(EntityTypesTable).filter(EntityTypesTable.parent_type == entity_type.entity_type).all()
|
|
for child_entity_type in child_entity_types:
|
|
total_count += self._getTotalCountForChildren(child_entity_type, db_session)
|
|
return total_count
|
|
|
|
def _addChildren(self, parentItem, parent_entity_type, db_session, used_ids, depth=0):
|
|
try:
|
|
# Log the depth of recursion
|
|
#logging.debug(f"Adding children at depth: {depth}, parent entity type: {parent_entity_type}")
|
|
|
|
child_entity_types = db_session.query(EntityTypesTable).filter(EntityTypesTable.parent_type == parent_entity_type).all()
|
|
for child_entity_type in child_entity_types:
|
|
if not child_entity_type.entity_type.startswith("category_"):
|
|
count = db_session.query(EntitiesTable).filter(EntitiesTable.entity_types_id == child_entity_type.entity_type_id).count()
|
|
text = f" {count} - {child_entity_type.gui_name} ({child_entity_type.entity_type})"
|
|
else:
|
|
# Use the new method to get the total count for this category
|
|
total_count = self._getTotalCountForChildren(child_entity_type, db_session)
|
|
text = f" {total_count} - {child_entity_type.gui_name} (Total)"
|
|
|
|
childItem = QTreeWidgetItem(parentItem)
|
|
childItem.setText(0, text)
|
|
childItem.setToolTip(0, child_entity_type.gui_tooltip)
|
|
childItem.entity_type_id = child_entity_type.entity_type_id
|
|
childItem.entity_type = child_entity_type.entity_type
|
|
if child_entity_type.entity_type_id in used_ids and child_entity_type.parser_enabled:
|
|
color = QColor('green')
|
|
elif not child_entity_type.entity_type.startswith("category_") and not child_entity_type.parser_enabled:
|
|
color = QColor('red')
|
|
else:
|
|
color = QColor('white')
|
|
childItem.setForeground(0, color)
|
|
|
|
# Recursive call with increased depth
|
|
depth = depth + 1
|
|
self._addChildren(childItem, child_entity_type.entity_type, db_session, used_ids, depth)
|
|
except Exception as e:
|
|
logging.error(f"Error in _addChildren: {e}")
|
|
|
|
|
|
|
|
def updateTree(self, db_session):
|
|
#logging.info("Updating checkboxes with database content")
|
|
with session_scope() as db_session:
|
|
try:
|
|
# Query database for entity types
|
|
entity_types = db_session.query(EntityTypesTable).all()
|
|
used_ids = {d.entity_types_id for d in db_session.query(DistinctEntitiesTable.entity_types_id).distinct()}
|
|
#logging.debug(f"Used IDs: {used_ids}")
|
|
# Clear existing items
|
|
self.treeWidget.clear()
|
|
rootItems = {}
|
|
|
|
# Construct hierarchical tree structure
|
|
for entity_type in entity_types:
|
|
if entity_type.parent_type != 'root': # Skip non-root items
|
|
continue
|
|
|
|
if not entity_type.entity_type.startswith("category_"):
|
|
count = db_session.query(EntitiesTable).filter(EntitiesTable.entity_types_id == entity_type.entity_type_id).count()
|
|
text = f"{count} - {entity_type.gui_name} {entity_type.entity_type}"
|
|
else:
|
|
# Use the new method to get the total count for this category
|
|
total_count = self._getTotalCountForChildren(entity_type, db_session)
|
|
text = f"{total_count} - {entity_type.gui_name} (Total)"
|
|
|
|
treeItem = QTreeWidgetItem()
|
|
treeItem.setText(0, text)
|
|
treeItem.setToolTip(0, entity_type.gui_tooltip)
|
|
treeItem.entity_type_id = entity_type.entity_type_id
|
|
treeItem.entity_type = entity_type.entity_type
|
|
if entity_type.entity_type_id in used_ids and entity_type.parser_enabled:
|
|
color = QColor('green')
|
|
elif not entity_type.entity_type.startswith("category_") and not entity_type.parser_enabled:
|
|
color = QColor('red')
|
|
else:
|
|
color = QColor('white')
|
|
treeItem.setForeground(0, color)
|
|
self.treeWidget.addTopLevelItem(treeItem)
|
|
|
|
# Call recursive function to add children
|
|
self._addChildren(treeItem, entity_type.entity_type, db_session, used_ids)
|
|
# Optionally expand all tree items
|
|
self.treeWidget.expandAll()
|
|
|
|
except Exception as e:
|
|
logging.error("Error updating database tree", exc_info=True)
|
|
|
|
def expandAllTreeItems(self):
|
|
for i in range(self.treeWidget.topLevelItemCount()):
|
|
self._expandCollapseRecursive(self.treeWidget.topLevelItem(i), True)
|
|
|
|
def collapseAllTreeItems(self):
|
|
for i in range(self.treeWidget.topLevelItemCount()):
|
|
self._expandCollapseRecursive(self.treeWidget.topLevelItem(i), False)
|
|
|
|
def _expandCollapseRecursive(self, treeItem, expand=True):
|
|
if treeItem is not None:
|
|
treeItem.setExpanded(expand)
|
|
for j in range(treeItem.childCount()):
|
|
self._expandCollapseRecursive(treeItem.child(j), expand)
|
|
|
|
class FileCheckboxPanel(QWidget):
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
self.mainLayout = QVBoxLayout(self)
|
|
self.scrollArea = QScrollArea(self)
|
|
self.scrollArea.setWidgetResizable(True)
|
|
self.scrollAreaContents = QWidget()
|
|
self.scrollLayout = QVBoxLayout(self.scrollAreaContents)
|
|
self.scrollArea.setWidget(self.scrollAreaContents)
|
|
|
|
self.mainLayout.addWidget(self.scrollArea)
|
|
self.items = [] # Keep track of the custom widgets
|
|
|
|
def updateCheckboxes(self, db_session):
|
|
try:
|
|
# Clear existing items
|
|
for item in self.items:
|
|
item.deleteLater()
|
|
self.items.clear()
|
|
with session_scope() as db_session:
|
|
try:
|
|
file_metadata = db_session.query(FileMetadata).all()
|
|
for file in file_metadata:
|
|
entity_count = db_session.query(EntitiesTable).filter(EntitiesTable.file_id == file.file_id).count()
|
|
|
|
item_text = f"{file.file_name} ({entity_count})"
|
|
|
|
custom_widget = FileCheckboxItem(item_text)
|
|
self.scrollLayout.addWidget(custom_widget)
|
|
self.items.append(custom_widget)
|
|
|
|
# Add a stretch to push everything up
|
|
self.scrollLayout.addStretch(1)
|
|
except Exception as e:
|
|
logging.error("Error updating file checkboxes", exc_info=True)
|
|
except Exception as e:
|
|
logging.error("Error updating file checkboxes", exc_info=True)
|
|
|
|
def filterCheckboxes(self, filter_text):
|
|
for item in self.items:
|
|
if filter_text.lower() in item.label.text().lower():
|
|
item.show()
|
|
else:
|
|
item.hide()
|
|
|
|
def checkAllVisible(self):
|
|
for item in self.items:
|
|
if not item.isHidden():
|
|
item.checkBox.setChecked(True)
|
|
|
|
def uncheckAllVisible(self):
|
|
for item in self.items:
|
|
if not item.isHidden():
|
|
item.checkBox.setChecked(False)
|
|
|
|
def getCheckedFiles(self):
|
|
checked_files = []
|
|
for custom_widget in self.items:
|
|
if custom_widget.checkBox.isChecked():
|
|
# Extract the file name from the item text
|
|
file_name = custom_widget.label.text().split(" (")[0]
|
|
checked_files.append(file_name)
|
|
return checked_files
|
|
|
|
def _setCheckStateForVisibleItems(self, state):
|
|
for custom_widget in self.items:
|
|
if not custom_widget.isHidden():
|
|
custom_widget.checkBox.setChecked(state)
|