improving Search functionality
This commit is contained in:
parent
b5314497da
commit
bee297bf19
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ __pycache__/
|
|||||||
anime_tracker.log
|
anime_tracker.log
|
||||||
todo.txt
|
todo.txt
|
||||||
*.csv
|
*.csv
|
||||||
|
anime_backlog.db.bk
|
||||||
|
41
backend.py
41
backend.py
@ -30,28 +30,10 @@ class AnimeBackend:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Error creating table: {e}")
|
logging.error(f"Error creating table: {e}")
|
||||||
|
|
||||||
def get_pre_2010_entries(self, status_filter=None, type_filter=None, search=None, year_filter=None):
|
def get_pre_2010_entries(self):
|
||||||
try:
|
try:
|
||||||
cursor = self.db.cursor()
|
cursor = self.db.cursor()
|
||||||
sql = "SELECT * FROM anime WHERE year < 2010"
|
cursor.execute("SELECT * FROM anime WHERE year < 2010 ORDER BY year DESC, name")
|
||||||
add_where = []
|
|
||||||
params = []
|
|
||||||
if year_filter is not None:
|
|
||||||
add_where.append("year = ?")
|
|
||||||
params.append(year_filter)
|
|
||||||
if status_filter is not None:
|
|
||||||
add_where.append("status = ?")
|
|
||||||
params.append(status_filter)
|
|
||||||
if type_filter is not None:
|
|
||||||
add_where.append("type = ?")
|
|
||||||
params.append(type_filter)
|
|
||||||
if search is not None:
|
|
||||||
add_where.append("(name LIKE ? OR comment LIKE ?)")
|
|
||||||
params.append(f"%{search}%")
|
|
||||||
params.append(f"%{search}%")
|
|
||||||
where_clause = " AND " + " AND ".join(add_where) if add_where else ""
|
|
||||||
sql += where_clause + " ORDER BY year DESC, name"
|
|
||||||
cursor.execute(sql, params)
|
|
||||||
return cursor.fetchall()
|
return cursor.fetchall()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Error getting pre-2010 entries: {e}")
|
logging.error(f"Error getting pre-2010 entries: {e}")
|
||||||
@ -66,25 +48,10 @@ class AnimeBackend:
|
|||||||
logging.error(f"Error getting years: {e}")
|
logging.error(f"Error getting years: {e}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def get_entries_for_season(self, year, season, status_filter=None, type_filter=None, search=None):
|
def get_entries_for_season(self, year, season):
|
||||||
try:
|
try:
|
||||||
cursor = self.db.cursor()
|
cursor = self.db.cursor()
|
||||||
sql = "SELECT * FROM anime WHERE year = ? AND season = ?"
|
cursor.execute("SELECT * FROM anime WHERE year = ? AND season = ? ORDER BY name", (year, season))
|
||||||
params = [year, season]
|
|
||||||
add_where = []
|
|
||||||
if status_filter is not None:
|
|
||||||
add_where.append("status = ?")
|
|
||||||
params.append(status_filter)
|
|
||||||
if type_filter is not None:
|
|
||||||
add_where.append("type = ?")
|
|
||||||
params.append(type_filter)
|
|
||||||
if search is not None:
|
|
||||||
add_where.append("(name LIKE ? OR comment LIKE ?)")
|
|
||||||
params.append(f"%{search}%")
|
|
||||||
params.append(f"%{search}%")
|
|
||||||
where_clause = " AND " + " AND ".join(add_where) if add_where else ""
|
|
||||||
sql += where_clause + " ORDER BY name"
|
|
||||||
cursor.execute(sql, params)
|
|
||||||
return cursor.fetchall()
|
return cursor.fetchall()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Error getting entries for season {season} in year {year}: {e}")
|
logging.error(f"Error getting entries for season {season} in year {year}: {e}")
|
||||||
|
556
frontend.py
556
frontend.py
@ -153,45 +153,18 @@ class AnimeTracker(QMainWindow):
|
|||||||
central_layout = QVBoxLayout(self.central_widget)
|
central_layout = QVBoxLayout(self.central_widget)
|
||||||
self.filter_bar = QWidget()
|
self.filter_bar = QWidget()
|
||||||
filter_layout = QHBoxLayout(self.filter_bar)
|
filter_layout = QHBoxLayout(self.filter_bar)
|
||||||
label_year = QLabel("Year:")
|
|
||||||
self.year_spin = QSpinBox()
|
|
||||||
self.year_spin.setRange(0, 2100)
|
|
||||||
self.year_spin.setValue(0)
|
|
||||||
self.year_spin.setSpecialValueText("All")
|
|
||||||
filter_layout.addWidget(label_year)
|
|
||||||
filter_layout.addWidget(self.year_spin)
|
|
||||||
label_season = QLabel("Season:")
|
|
||||||
self.season_combo = QComboBox()
|
|
||||||
self.season_combo.addItems(['All', 'winter', 'spring', 'summer', 'fall', 'Other'])
|
|
||||||
filter_layout.addWidget(label_season)
|
|
||||||
filter_layout.addWidget(self.season_combo)
|
|
||||||
label_status = QLabel("Status:")
|
|
||||||
self.status_combo = QComboBox()
|
|
||||||
self.status_combo.addItems(['All', 'unwatched', 'watching', 'completed'])
|
|
||||||
filter_layout.addWidget(label_status)
|
|
||||||
filter_layout.addWidget(self.status_combo)
|
|
||||||
label_type = QLabel("Type:")
|
|
||||||
self.type_combo = QComboBox()
|
|
||||||
self.type_combo.addItems(['All', 'TV', 'Movie', 'OVA', 'Special', 'Short TV', 'Other'])
|
|
||||||
filter_layout.addWidget(label_type)
|
|
||||||
filter_layout.addWidget(self.type_combo)
|
|
||||||
label_search = QLabel("Search:")
|
label_search = QLabel("Search:")
|
||||||
self.search_edit = QLineEdit()
|
self.search_edit = QLineEdit()
|
||||||
self.search_edit.setPlaceholderText("Search name or comment")
|
self.search_edit.setPlaceholderText("Search name")
|
||||||
|
self.search_edit.textChanged.connect(self.filter_tables)
|
||||||
filter_layout.addWidget(label_search)
|
filter_layout.addWidget(label_search)
|
||||||
filter_layout.addWidget(self.search_edit)
|
filter_layout.addWidget(self.search_edit)
|
||||||
apply_btn = QPushButton("Apply")
|
|
||||||
apply_btn.clicked.connect(self.apply_filters)
|
|
||||||
filter_layout.addWidget(apply_btn)
|
|
||||||
central_layout.addWidget(self.filter_bar)
|
central_layout.addWidget(self.filter_bar)
|
||||||
central_layout.addWidget(self.tab_widget)
|
central_layout.addWidget(self.tab_widget)
|
||||||
self.setCentralWidget(self.central_widget)
|
self.setCentralWidget(self.central_widget)
|
||||||
self.year_filter = None
|
self.search_text = ''
|
||||||
self.season_filter = None
|
|
||||||
self.status_filter = None
|
|
||||||
self.type_filter = None
|
|
||||||
self.search_text = None
|
|
||||||
self.table_scale = self.settings.value("tableScale", 1.0, type=float)
|
self.table_scale = self.settings.value("tableScale", 1.0, type=float)
|
||||||
|
self.tables = []
|
||||||
self.create_menu()
|
self.create_menu()
|
||||||
self.load_tabs()
|
self.load_tabs()
|
||||||
self.restoreGeometry(self.settings.value("geometry", self.saveGeometry()))
|
self.restoreGeometry(self.settings.value("geometry", self.saveGeometry()))
|
||||||
@ -200,18 +173,14 @@ class AnimeTracker(QMainWindow):
|
|||||||
self.set_current_tab_by_identifier(last_tab)
|
self.set_current_tab_by_identifier(last_tab)
|
||||||
self.tab_widget.setFocus()
|
self.tab_widget.setFocus()
|
||||||
|
|
||||||
def apply_filters(self):
|
def filter_tables(self, text):
|
||||||
year_val = self.year_spin.value()
|
self.search_text = text.strip().lower()
|
||||||
self.year_filter = year_val if year_val > 0 else None
|
for table in self.tables:
|
||||||
season_val = self.season_combo.currentText()
|
for row in range(table.rowCount()):
|
||||||
self.season_filter = None if season_val == 'All' else ('' if season_val == 'Other' else season_val)
|
name_col = 2 if table.is_pre else 1
|
||||||
status_val = self.status_combo.currentText()
|
name_text = table.cellWidget(row, name_col).text()
|
||||||
self.status_filter = None if status_val == 'All' else status_val
|
clean_name = re.sub(r'<[^>]+>', '', name_text).lower()
|
||||||
type_val = self.type_combo.currentText()
|
table.setRowHidden(row, self.search_text not in clean_name if self.search_text else False)
|
||||||
self.type_filter = None if type_val == 'All' else type_val
|
|
||||||
search_val = self.search_edit.text().strip()
|
|
||||||
self.search_text = search_val if search_val else None
|
|
||||||
self.load_tabs()
|
|
||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
self.settings.setValue("geometry", self.saveGeometry())
|
self.settings.setValue("geometry", self.saveGeometry())
|
||||||
@ -281,143 +250,139 @@ class AnimeTracker(QMainWindow):
|
|||||||
|
|
||||||
def load_tabs(self):
|
def load_tabs(self):
|
||||||
self.tab_widget.clear()
|
self.tab_widget.clear()
|
||||||
show_pre = True
|
self.tables = []
|
||||||
if self.season_filter is not None and self.season_filter != '':
|
# Pre-2010 tab
|
||||||
show_pre = False
|
pre_entries = self.backend.get_pre_2010_entries()
|
||||||
if self.year_filter is not None and self.year_filter >= 2010:
|
pre_tab = QScrollArea()
|
||||||
show_pre = False
|
pre_tab.setWidgetResizable(True)
|
||||||
if show_pre:
|
pre_content = QWidget()
|
||||||
pre_entries = self.backend.get_pre_2010_entries(self.status_filter, self.type_filter, self.search_text, self.year_filter if self.year_filter and self.year_filter < 2010 else None)
|
pre_layout = QVBoxLayout(pre_content)
|
||||||
pre_tab = QScrollArea()
|
if pre_entries:
|
||||||
pre_tab.setWidgetResizable(True)
|
table = CustomTableWidget(self, is_pre=True)
|
||||||
pre_content = QWidget()
|
table.is_pre = True
|
||||||
pre_layout = QVBoxLayout(pre_content)
|
self.tables.append(table)
|
||||||
if pre_entries:
|
table.setRowCount(len(pre_entries))
|
||||||
table = CustomTableWidget(self, is_pre=True)
|
table.setColumnCount(7)
|
||||||
table.setRowCount(len(pre_entries))
|
headers = ['ID', 'Year', 'Name', 'Type', 'Status', 'Comment', 'Actions']
|
||||||
table.setColumnCount(7)
|
table.setHorizontalHeaderLabels(headers)
|
||||||
headers = ['ID', 'Year', 'Name', 'Type', 'Status', 'Comment', 'Actions']
|
table.setColumnHidden(0, True)
|
||||||
table.setHorizontalHeaderLabels(headers)
|
table.setAlternatingRowColors(True)
|
||||||
table.setColumnHidden(0, True)
|
table.setShowGrid(True)
|
||||||
table.setAlternatingRowColors(True)
|
header = table.horizontalHeader()
|
||||||
table.setShowGrid(True)
|
header.setStretchLastSection(False)
|
||||||
header = table.horizontalHeader()
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
header.setStretchLastSection(False)
|
table.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||||
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||||
table.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
header.setSectionResizeMode(0, QHeaderView.Fixed) # ID hidden
|
||||||
table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
header.setSectionResizeMode(1, QHeaderView.ResizeToContents) # Year
|
||||||
header.setSectionResizeMode(0, QHeaderView.Fixed) # ID hidden
|
header.setSectionResizeMode(2, QHeaderView.Stretch) # Name
|
||||||
header.setSectionResizeMode(1, QHeaderView.ResizeToContents) # Year
|
header.setSectionResizeMode(3, QHeaderView.ResizeToContents) # Type
|
||||||
header.setSectionResizeMode(2, QHeaderView.Stretch) # Name
|
header.setSectionResizeMode(4, QHeaderView.ResizeToContents) # Status
|
||||||
header.setSectionResizeMode(3, QHeaderView.ResizeToContents) # Type
|
header.setSectionResizeMode(5, QHeaderView.Stretch) # Comment
|
||||||
header.setSectionResizeMode(4, QHeaderView.ResizeToContents) # Status
|
header.setSectionResizeMode(6, QHeaderView.ResizeToContents) # Actions
|
||||||
header.setSectionResizeMode(5, QHeaderView.Stretch) # Comment
|
table.setColumnWidth(0, 0) # Set ID column width to 0 to ensure it's hidden
|
||||||
header.setSectionResizeMode(6, QHeaderView.ResizeToContents) # Actions
|
font = QFont()
|
||||||
table.setColumnWidth(0, 0) # Set ID column width to 0 to ensure it's hidden
|
font.setPointSize(int(10 * self.table_scale))
|
||||||
font = QFont()
|
header_font = QFont()
|
||||||
font.setPointSize(int(10 * self.table_scale))
|
header_font.setPointSize(int(10 * self.table_scale))
|
||||||
header_font = QFont()
|
header_font.setBold(True)
|
||||||
header_font.setPointSize(int(10 * self.table_scale))
|
table.setFont(font)
|
||||||
header_font.setBold(True)
|
table.horizontalHeader().setFont(header_font)
|
||||||
table.setFont(font)
|
table.verticalHeader().setFont(font)
|
||||||
table.horizontalHeader().setFont(header_font)
|
for row, entry in enumerate(pre_entries):
|
||||||
table.verticalHeader().setFont(font)
|
col = 0
|
||||||
for row, entry in enumerate(pre_entries):
|
# ID
|
||||||
col = 0
|
id_item = QTableWidgetItem(str(entry[0]))
|
||||||
# ID
|
table.setItem(row, col, id_item)
|
||||||
id_item = QTableWidgetItem(str(entry[0]))
|
col += 1
|
||||||
table.setItem(row, col, id_item)
|
# Year
|
||||||
col += 1
|
year_item = QTableWidgetItem(str(entry[2]))
|
||||||
# Year
|
year_item.setFont(font)
|
||||||
year_item = QTableWidgetItem(str(entry[2]))
|
table.setItem(row, col, year_item)
|
||||||
year_item.setFont(font)
|
col += 1
|
||||||
table.setItem(row, col, year_item)
|
# Name
|
||||||
col += 1
|
name = entry[1]
|
||||||
# Name
|
url = entry[7]
|
||||||
name = entry[1]
|
name_label = QLabel()
|
||||||
url = entry[7]
|
name_font = QFont(font)
|
||||||
name_label = QLabel()
|
if entry[4] == 'watching':
|
||||||
name_font = QFont(font)
|
name_font.setItalic(True)
|
||||||
if entry[4] == 'watching':
|
elif entry[4] == 'completed':
|
||||||
name_font.setItalic(True)
|
name_font.setStrikeOut(True)
|
||||||
elif entry[4] == 'completed':
|
name_label.setFont(name_font)
|
||||||
name_font.setStrikeOut(True)
|
if url:
|
||||||
name_label.setFont(name_font)
|
name_escaped = html.escape(name)
|
||||||
if url:
|
name_label.setText(f'<a href="{url}" style="color: #0000FF; text-decoration: none;">{name_escaped}</a>')
|
||||||
name_escaped = html.escape(name)
|
name_label.setOpenExternalLinks(True)
|
||||||
name_label.setText(f'<a href="{url}" style="color: #0000FF; text-decoration: none;">{name_escaped}</a>')
|
else:
|
||||||
name_label.setOpenExternalLinks(True)
|
name_label.setText(html.escape(name))
|
||||||
else:
|
name_label.setStyleSheet("padding-left: 10px;")
|
||||||
name_label.setText(html.escape(name))
|
table.setCellWidget(row, col, name_label)
|
||||||
name_label.setStyleSheet("padding-left: 10px;")
|
col += 1
|
||||||
table.setCellWidget(row, col, name_label)
|
# Type
|
||||||
col += 1
|
type_item = QTableWidgetItem(entry[5] or '')
|
||||||
# Type
|
type_item.setFont(font)
|
||||||
type_item = QTableWidgetItem(entry[5] or '')
|
table.setItem(row, col, type_item)
|
||||||
type_item.setFont(font)
|
col += 1
|
||||||
table.setItem(row, col, type_item)
|
# Status
|
||||||
col += 1
|
status_item = QTableWidgetItem(entry[4])
|
||||||
# Status
|
status_item.setFont(font)
|
||||||
status_item = QTableWidgetItem(entry[4])
|
table.setItem(row, col, status_item)
|
||||||
status_item.setFont(font)
|
col += 1
|
||||||
table.setItem(row, col, status_item)
|
# Comment
|
||||||
col += 1
|
comment_item = QTableWidgetItem(entry[6] or '')
|
||||||
# Comment
|
comment_item.setFont(font)
|
||||||
comment_item = QTableWidgetItem(entry[6] or '')
|
table.setItem(row, col, comment_item)
|
||||||
comment_item.setFont(font)
|
col += 1
|
||||||
table.setItem(row, col, comment_item)
|
# Actions
|
||||||
col += 1
|
actions_widget = self.create_actions_widget(entry[0], entry[4])
|
||||||
# Actions
|
for child in actions_widget.findChildren(QToolButton):
|
||||||
actions_widget = self.create_actions_widget(entry[0], entry[4])
|
child.setFont(font)
|
||||||
for child in actions_widget.findChildren(QToolButton):
|
table.setCellWidget(row, col, actions_widget)
|
||||||
child.setFont(font)
|
table.resizeColumnsToContents()
|
||||||
table.setCellWidget(row, col, actions_widget)
|
table.resizeRowsToContents()
|
||||||
table.resizeColumnsToContents()
|
# Calculate fixed height
|
||||||
table.resizeRowsToContents()
|
height = table.horizontalHeader().height() + 2 # small margin
|
||||||
# Calculate fixed height
|
for i in range(table.rowCount()):
|
||||||
height = table.horizontalHeader().height() + 2 # small margin
|
height += table.rowHeight(i)
|
||||||
for i in range(table.rowCount()):
|
table.setFixedHeight(height)
|
||||||
height += table.rowHeight(i)
|
# Apply status colors
|
||||||
table.setFixedHeight(height)
|
status_col = 4
|
||||||
# Apply status colors
|
for r in range(table.rowCount()):
|
||||||
status_col = 4
|
status = table.item(r, status_col).text()
|
||||||
for r in range(table.rowCount()):
|
if status == 'unwatched':
|
||||||
status = table.item(r, status_col).text()
|
color = QColor(255, 255, 255)
|
||||||
if status == 'unwatched':
|
elif status == 'watching':
|
||||||
color = QColor(255, 255, 255)
|
color = QColor(255, 255, 0)
|
||||||
elif status == 'watching':
|
elif status == 'completed':
|
||||||
color = QColor(255, 255, 0)
|
color = QColor(0, 255, 0)
|
||||||
elif status == 'completed':
|
else:
|
||||||
color = QColor(0, 255, 0)
|
color = QColor(255, 255, 255)
|
||||||
else:
|
for c in range(table.columnCount()):
|
||||||
color = QColor(255, 255, 255)
|
if c == 0:
|
||||||
for c in range(table.columnCount()):
|
continue # skip hidden id
|
||||||
if c == 0:
|
item = table.item(r, c)
|
||||||
continue # skip hidden id
|
if item:
|
||||||
item = table.item(r, c)
|
item.setBackground(color)
|
||||||
if item:
|
widget = table.cellWidget(r, c)
|
||||||
item.setBackground(color)
|
if widget:
|
||||||
widget = table.cellWidget(r, c)
|
widget.setStyleSheet(f"background-color: {color.name()};")
|
||||||
if widget:
|
pre_layout.addWidget(table)
|
||||||
widget.setStyleSheet(f"background-color: {color.name()};")
|
pre_tab.setWidget(pre_content)
|
||||||
pre_layout.addWidget(table)
|
tab_text = "Pre-2010"
|
||||||
pre_tab.setWidget(pre_content)
|
completed = False
|
||||||
tab_text = "Pre-2010"
|
total = len(pre_entries)
|
||||||
completed = False
|
if total > 0:
|
||||||
total = len(pre_entries)
|
comp = sum(1 for e in pre_entries if e[4] == 'completed')
|
||||||
if total > 0:
|
perc = (comp / total * 100)
|
||||||
comp = sum(1 for e in pre_entries if e[4] == 'completed')
|
tab_text += f" ({perc:.0f}%)"
|
||||||
perc = (comp / total * 100)
|
if comp == total:
|
||||||
tab_text += f" ({perc:.0f}%)"
|
completed = True
|
||||||
if comp == total:
|
index = self.tab_widget.addTab(pre_tab, tab_text)
|
||||||
completed = True
|
if completed:
|
||||||
index = self.tab_widget.addTab(pre_tab, tab_text)
|
self.tab_widget.tabBar().setTabTextColor(index, QColor('gray'))
|
||||||
if completed:
|
|
||||||
self.tab_widget.tabBar().setTabTextColor(index, QColor('gray'))
|
|
||||||
# Years >= 2010
|
# Years >= 2010
|
||||||
years = self.backend.get_years()
|
years = self.backend.get_years()
|
||||||
if self.year_filter is not None:
|
|
||||||
years = [self.year_filter] if self.year_filter in years else []
|
|
||||||
for year in years:
|
for year in years:
|
||||||
year_tab = QScrollArea()
|
year_tab = QScrollArea()
|
||||||
year_tab.setWidgetResizable(True)
|
year_tab.setWidgetResizable(True)
|
||||||
@ -426,126 +391,123 @@ class AnimeTracker(QMainWindow):
|
|||||||
total_entries = 0
|
total_entries = 0
|
||||||
comp_entries = 0
|
comp_entries = 0
|
||||||
for season in ['winter', 'spring', 'summer', 'fall', '']:
|
for season in ['winter', 'spring', 'summer', 'fall', '']:
|
||||||
show_section = True
|
entries = self.backend.get_entries_for_season(year, season)
|
||||||
if self.season_filter is not None:
|
if entries:
|
||||||
if season != self.season_filter:
|
s_name = season.capitalize() if season else 'Other'
|
||||||
show_section = False
|
label = QLabel(s_name)
|
||||||
if show_section:
|
season_font = QFont()
|
||||||
entries = self.backend.get_entries_for_season(year, season, self.status_filter, self.type_filter, self.search_text)
|
season_font.setPointSize(int(12 * self.table_scale))
|
||||||
if entries:
|
season_font.setBold(True)
|
||||||
s_name = season.capitalize() if season else 'Other'
|
label.setFont(season_font)
|
||||||
label = QLabel(s_name)
|
layout.addWidget(label)
|
||||||
season_font = QFont()
|
table = CustomTableWidget(self, is_pre=False)
|
||||||
season_font.setPointSize(int(12 * self.table_scale))
|
table.is_pre = False
|
||||||
season_font.setBold(True)
|
self.tables.append(table)
|
||||||
label.setFont(season_font)
|
table.setRowCount(len(entries))
|
||||||
layout.addWidget(label)
|
table.setColumnCount(6)
|
||||||
table = CustomTableWidget(self, is_pre=False)
|
headers = ['ID', 'Name', 'Type', 'Status', 'Comment', 'Actions']
|
||||||
table.setRowCount(len(entries))
|
table.setHorizontalHeaderLabels(headers)
|
||||||
table.setColumnCount(6)
|
table.setColumnHidden(0, True)
|
||||||
headers = ['ID', 'Name', 'Type', 'Status', 'Comment', 'Actions']
|
table.setAlternatingRowColors(True)
|
||||||
table.setHorizontalHeaderLabels(headers)
|
table.setShowGrid(True)
|
||||||
table.setColumnHidden(0, True)
|
header = table.horizontalHeader()
|
||||||
table.setAlternatingRowColors(True)
|
header.setStretchLastSection(False)
|
||||||
table.setShowGrid(True)
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
header = table.horizontalHeader()
|
table.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||||
header.setStretchLastSection(False)
|
table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||||
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
header.setSectionResizeMode(0, QHeaderView.Fixed) # ID hidden
|
||||||
table.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
header.setSectionResizeMode(1, QHeaderView.Stretch) # Name
|
||||||
table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
header.setSectionResizeMode(2, QHeaderView.ResizeToContents) # Type
|
||||||
header.setSectionResizeMode(0, QHeaderView.Fixed) # ID hidden
|
header.setSectionResizeMode(3, QHeaderView.ResizeToContents) # Status
|
||||||
header.setSectionResizeMode(1, QHeaderView.Stretch) # Name
|
header.setSectionResizeMode(4, QHeaderView.Stretch) # Comment
|
||||||
header.setSectionResizeMode(2, QHeaderView.ResizeToContents) # Type
|
header.setSectionResizeMode(5, QHeaderView.ResizeToContents) # Actions
|
||||||
header.setSectionResizeMode(3, QHeaderView.ResizeToContents) # Status
|
table.setColumnWidth(0, 0) # Set ID column width to 0 to ensure it's hidden
|
||||||
header.setSectionResizeMode(4, QHeaderView.Stretch) # Comment
|
font = QFont()
|
||||||
header.setSectionResizeMode(5, QHeaderView.ResizeToContents) # Actions
|
font.setPointSize(int(10 * self.table_scale))
|
||||||
table.setColumnWidth(0, 0) # Set ID column width to 0 to ensure it's hidden
|
header_font = QFont()
|
||||||
font = QFont()
|
header_font.setPointSize(int(10 * self.table_scale))
|
||||||
font.setPointSize(int(10 * self.table_scale))
|
header_font.setBold(True)
|
||||||
header_font = QFont()
|
table.setFont(font)
|
||||||
header_font.setPointSize(int(10 * self.table_scale))
|
table.horizontalHeader().setFont(header_font)
|
||||||
header_font.setBold(True)
|
table.verticalHeader().setFont(font)
|
||||||
table.setFont(font)
|
for row, entry in enumerate(entries):
|
||||||
table.horizontalHeader().setFont(header_font)
|
col = 0
|
||||||
table.verticalHeader().setFont(font)
|
# ID
|
||||||
for row, entry in enumerate(entries):
|
id_item = QTableWidgetItem(str(entry[0]))
|
||||||
col = 0
|
table.setItem(row, col, id_item)
|
||||||
# ID
|
col += 1
|
||||||
id_item = QTableWidgetItem(str(entry[0]))
|
# Name
|
||||||
table.setItem(row, col, id_item)
|
name = entry[1]
|
||||||
col += 1
|
url = entry[7]
|
||||||
# Name
|
name_label = QLabel()
|
||||||
name = entry[1]
|
name_font = QFont(font)
|
||||||
url = entry[7]
|
if entry[4] == 'watching':
|
||||||
name_label = QLabel()
|
name_font.setItalic(True)
|
||||||
name_font = QFont(font)
|
elif entry[4] == 'completed':
|
||||||
if entry[4] == 'watching':
|
name_font.setStrikeOut(True)
|
||||||
name_font.setItalic(True)
|
name_label.setFont(name_font)
|
||||||
elif entry[4] == 'completed':
|
if url:
|
||||||
name_font.setStrikeOut(True)
|
name_escaped = html.escape(name)
|
||||||
name_label.setFont(name_font)
|
name_label.setText(f'<a href="{url}" style="color: #0000FF; text-decoration: none;">{name_escaped}</a>')
|
||||||
if url:
|
name_label.setOpenExternalLinks(True)
|
||||||
name_escaped = html.escape(name)
|
else:
|
||||||
name_label.setText(f'<a href="{url}" style="color: #0000FF; text-decoration: none;">{name_escaped}</a>')
|
name_label.setText(html.escape(name))
|
||||||
name_label.setOpenExternalLinks(True)
|
name_label.setStyleSheet("padding-left: 10px;")
|
||||||
else:
|
table.setCellWidget(row, col, name_label)
|
||||||
name_label.setText(html.escape(name))
|
col += 1
|
||||||
name_label.setStyleSheet("padding-left: 10px;")
|
# Type
|
||||||
table.setCellWidget(row, col, name_label)
|
type_item = QTableWidgetItem(entry[5] or '')
|
||||||
col += 1
|
type_item.setFont(font)
|
||||||
# Type
|
table.setItem(row, col, type_item)
|
||||||
type_item = QTableWidgetItem(entry[5] or '')
|
col += 1
|
||||||
type_item.setFont(font)
|
# Status
|
||||||
table.setItem(row, col, type_item)
|
status_item = QTableWidgetItem(entry[4])
|
||||||
col += 1
|
status_item.setFont(font)
|
||||||
# Status
|
table.setItem(row, col, status_item)
|
||||||
status_item = QTableWidgetItem(entry[4])
|
col += 1
|
||||||
status_item.setFont(font)
|
# Comment
|
||||||
table.setItem(row, col, status_item)
|
comment_item = QTableWidgetItem(entry[6] or '')
|
||||||
col += 1
|
comment_item.setFont(font)
|
||||||
# Comment
|
table.setItem(row, col, comment_item)
|
||||||
comment_item = QTableWidgetItem(entry[6] or '')
|
col += 1
|
||||||
comment_item.setFont(font)
|
# Actions
|
||||||
table.setItem(row, col, comment_item)
|
actions_widget = self.create_actions_widget(entry[0], entry[4])
|
||||||
col += 1
|
for child in actions_widget.findChildren(QToolButton):
|
||||||
# Actions
|
child.setFont(font)
|
||||||
actions_widget = self.create_actions_widget(entry[0], entry[4])
|
table.setCellWidget(row, col, actions_widget)
|
||||||
for child in actions_widget.findChildren(QToolButton):
|
table.resizeColumnsToContents()
|
||||||
child.setFont(font)
|
table.resizeRowsToContents()
|
||||||
table.setCellWidget(row, col, actions_widget)
|
# Calculate fixed height
|
||||||
table.resizeColumnsToContents()
|
height = table.horizontalHeader().height() + 2 # small margin
|
||||||
table.resizeRowsToContents()
|
for i in range(table.rowCount()):
|
||||||
# Calculate fixed height
|
height += table.rowHeight(i)
|
||||||
height = table.horizontalHeader().height() + 2 # small margin
|
table.setFixedHeight(height)
|
||||||
for i in range(table.rowCount()):
|
# Apply status colors
|
||||||
height += table.rowHeight(i)
|
status_col = 3
|
||||||
table.setFixedHeight(height)
|
for r in range(table.rowCount()):
|
||||||
# Apply status colors
|
status = table.item(r, status_col).text()
|
||||||
status_col = 3
|
if status == 'unwatched':
|
||||||
for r in range(table.rowCount()):
|
color = QColor(255, 255, 255)
|
||||||
status = table.item(r, status_col).text()
|
elif status == 'watching':
|
||||||
if status == 'unwatched':
|
color = QColor(255, 255, 0)
|
||||||
color = QColor(255, 255, 255)
|
elif status == 'completed':
|
||||||
elif status == 'watching':
|
color = QColor(0, 255, 0)
|
||||||
color = QColor(255, 255, 0)
|
else:
|
||||||
elif status == 'completed':
|
color = QColor(255, 255, 255)
|
||||||
color = QColor(0, 255, 0)
|
for c in range(table.columnCount()):
|
||||||
else:
|
if c == 0:
|
||||||
color = QColor(255, 255, 255)
|
continue # skip hidden id
|
||||||
for c in range(table.columnCount()):
|
item = table.item(r, c)
|
||||||
if c == 0:
|
if item:
|
||||||
continue # skip hidden id
|
item.setBackground(color)
|
||||||
item = table.item(r, c)
|
widget = table.cellWidget(r, c)
|
||||||
if item:
|
if widget:
|
||||||
item.setBackground(color)
|
widget.setStyleSheet(f"background-color: {color.name()};")
|
||||||
widget = table.cellWidget(r, c)
|
layout.addWidget(table)
|
||||||
if widget:
|
total_entries += len(entries)
|
||||||
widget.setStyleSheet(f"background-color: {color.name()};")
|
comp_entries += sum(1 for e in entries if e[4] == 'completed')
|
||||||
layout.addWidget(table)
|
|
||||||
total_entries += len(entries)
|
|
||||||
comp_entries += sum(1 for e in entries if e[4] == 'completed')
|
|
||||||
year_tab.setWidget(content)
|
year_tab.setWidget(content)
|
||||||
if total_entries > 0 or (self.year_filter == year):
|
if total_entries > 0:
|
||||||
perc = (comp_entries / total_entries * 100) if total_entries > 0 else 0
|
perc = (comp_entries / total_entries * 100) if total_entries > 0 else 0
|
||||||
tab_text = f"{year} ({perc:.0f}%)"
|
tab_text = f"{year} ({perc:.0f}%)"
|
||||||
completed = (comp_entries == total_entries)
|
completed = (comp_entries == total_entries)
|
||||||
|
Loading…
Reference in New Issue
Block a user