Skip to content

Commit

Permalink
Populate banning dialogs of GUI
Browse files Browse the repository at this point in the history
  • Loading branch information
Raymo111 committed Jul 28, 2023
1 parent 544f55c commit a3a925c
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 42 deletions.
2 changes: 2 additions & 0 deletions dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
print("Converting ui files to python...")
os.system(f"{venv_path}pyside6-uic ui/main.ui -o src/nexus/ui/MainWindow.py")
os.system(f"{venv_path}pyside6-uic ui/banlist.ui -o src/nexus/ui/BanlistDialog.py")
os.system(f"{venv_path}pyside6-uic ui/banword.ui -o src/nexus/ui/BanwordDialog.py")
os.system(f"{venv_path}pyside6-uic ui/confirm.ui -o src/nexus/ui/ConfirmDialog.py")

# Pyinstaller command
build_cmd = "pyinstaller -Fn nexus src/nexus/__main__.py"
Expand Down
27 changes: 22 additions & 5 deletions src/nexus/Freqlog/Freqlog.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,23 +215,31 @@ def check_banned(self, word: str, case: CaseSensitivity) -> bool:
logging.info(f"Checking if '{word}' is banned, case {case.name}")
return self.backend.check_banned(word, case)

def ban_word(self, word: str, case: CaseSensitivity) -> bool:
def ban_word(self, word: str, case: CaseSensitivity, time_added: datetime = datetime.now()) -> bool:
"""
Delete a word entry and add it to the ban list
:returns: True if word was banned, False if it was already banned
"""
time = datetime.now()
logging.info(f"Banning '{word}', case {case.name} - {time}")
res = self.backend.ban_word(word, case, time)
res = self.backend.ban_word(word, case, time_added)
if res:
logging.warning(f"Banned '{word}', case {case.name}")
else:
logging.warning(f"'{word}', case {case.name} already banned")
return res

def unban_word(self, word: str, case: CaseSensitivity) -> bool:
def ban_words(self, entries: dict[str: CaseSensitivity], time_added: datetime = datetime.now()) -> list[bool]:
"""
Remove a word from the ban list
Delete multiple word entries and add them to the ban list
:param entries: dict of {word to ban: case sensitivity}
:return: list of bools, True if word was banned, False if it was already banned
"""
logging.info(f"Banning {len(entries)} words - {time_added}")
return [self.ban_word(word, case, time_added) for word, case in entries.items()]

def unban_word(self, word: str, case: CaseSensitivity, time_added: datetime = datetime.now()) -> bool:
"""
Remove a banlist entry
:returns: True if word was unbanned, False if it was already not banned
"""
logging.info(f"Unbanning '{word}', case {case.name}")
Expand All @@ -242,6 +250,15 @@ def unban_word(self, word: str, case: CaseSensitivity) -> bool:
logging.warning(f"'{word}', case {case.name} isn't banned")
return res

def unban_words(self, entries: dict[str: CaseSensitivity], time_added: datetime = datetime.now()) -> list[bool]:
"""
Remove multiple banlist entries
:param entries: dict of {word to ban: case sensitivity}
:return: list of bools, True if word was unbanned, False if it was already unbanned
"""
logging.info(f"Banning {len(entries)} words - {time_added}")
return [self.unban_word(word, case, time_added) for word, case in entries.items()]

def list_words(self, limit: int = -1, sort_by: WordMetadataAttr = WordMetadataAttr.word,
reverse: bool = False, case: CaseSensitivity = CaseSensitivity.INSENSITIVE) -> list[WordMetadata]:
"""
Expand Down
131 changes: 105 additions & 26 deletions src/nexus/GUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,60 @@

from nexus.Freqlog import Freqlog
from nexus.ui.BanlistDialog import Ui_BanlistDialog
from nexus.ui.BanwordDialog import Ui_BanwordDialog
from nexus.ui.ConfirmDialog import Ui_ConfirmDialog
from nexus.ui.MainWindow import Ui_MainWindow

from nexus.Freqlog.Definitions import CaseSensitivity


class MainWindow(QMainWindow, Ui_MainWindow):
"""Required because Qt is a PITA."""
"""Set up the main window. Required because Qt is a PITA."""

def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)


class BanlistDialog(QDialog, Ui_BanlistDialog):
"""Required because Qt is a PITA."""
"""Set up the banlist dialog. Required because Qt is a PITA."""

def __init__(self, *args, **kwargs):
super(BanlistDialog, self).__init__(*args, **kwargs)
self.setupUi(self)


class BanwordDialog(QDialog, Ui_BanwordDialog):
"""Set up the banword dialog. Required because Qt is a PITA."""

def __init__(self, *args, **kwargs):
super(BanwordDialog, self).__init__(*args, **kwargs)
self.setupUi(self)


class ConfirmDialog(QDialog, Ui_ConfirmDialog):
"""Set up the confirm dialog. Required because Qt is a PITA."""

def __init__(self, *args, **kwargs):
super(ConfirmDialog, self).__init__(*args, **kwargs)
self.setupUi(self)


class GUI(object):
"""Nexus GUI"""

def __init__(self, args: argparse.Namespace):
"""Initialize GUI"""
self.app = QApplication([])
self.window = MainWindow()

# Components
self.start_stop_button: QPushButton = self.window.findChild(QPushButton, "startStop") # type: ignore[assign]
self.refresh_button: QPushButton = self.window.findChild(QPushButton, "refresh") # type: ignore[assign]
self.banlist_button: QPushButton = self.window.findChild(QPushButton, "banlist") # type: ignore[assign]
self.chentry_table: QTableWidget = self.window.findChild(QTableWidget, "chentryTable") # type: ignore[assign]
self.chord_table: QTableWidget = self.window.findChild(QTableWidget, "chordTable") # type: ignore[assign]
self.statusbar: QStatusBar = self.window.findChild(QStatusBar, "statusbar") # type: ignore[assign]
self.start_stop_button: QPushButton = self.window.startStop
self.refresh_button: QPushButton = self.window.refresh
self.banlist_button: QPushButton = self.window.banlist
self.chentry_table: QTableWidget = self.window.chentryTable
self.chord_table: QTableWidget = self.window.chordTable
self.statusbar: QStatusBar = self.window.statusbar

# Signals
self.start_stop_button.clicked.connect(self.start_stop)
Expand All @@ -50,13 +72,15 @@ def __init__(self, args: argparse.Namespace):
self.args = args

def start_logging(self):
self.freqlog = Freqlog(self.args.freq_log_path)
if not self.freqlog:
self.freqlog = Freqlog(self.args.freq_log_path)
self.freqlog.start_logging()

def stop_logging(self):
self.freqlog.stop_logging()

def start_stop(self):
"""Controller for start/stop logging button"""
if self.start_stop_button.text() == "Start logging":
# Update button to starting
# TODO: fix signal blocking (not currently working)
Expand Down Expand Up @@ -100,7 +124,9 @@ def start_stop(self):
self.window.repaint()

def refresh(self):
self.temp_freqlog = Freqlog(self.args.freq_log_path)
"""Controller for refresh button"""
if not self.temp_freqlog:
self.temp_freqlog = Freqlog(self.args.freq_log_path)
words = self.temp_freqlog.list_words()
self.chentry_table.setRowCount(len(words))
for i, word in enumerate(words):
Expand All @@ -113,24 +139,77 @@ def refresh(self):
self.statusbar.showMessage(f"Loaded {len(words)} freqlogged words")

def show_banlist(self):
self.temp_freqlog = Freqlog(self.args.freq_log_path)
banlist_case, banlist_caseless = self.temp_freqlog.list_banned_words()
dialog = BanlistDialog()
dialog.banlistTable.setRowCount(len(banlist_case) + len(banlist_caseless))
for i, word in enumerate(banlist_case):
dialog.banlistTable.setItem(i, 0, QTableWidgetItem(word.word))
dialog.banlistTable.setItem(i, 1,
QTableWidgetItem(str(word.date_added.isoformat(sep=" ", timespec="seconds"))))
dialog.banlistTable.setItem(i, 2, QTableWidgetItem("Sensitive"))
for i, word in enumerate(banlist_caseless):
dialog.banlistTable.setItem(i + len(banlist_case), 0, QTableWidgetItem(word.word))
dialog.banlistTable.setItem(i + len(banlist_case), 1,
QTableWidgetItem(str(word.date_added.isoformat(sep=" ", timespec="seconds"))))
dialog.banlistTable.setItem(i + len(banlist_case), 2, QTableWidgetItem("Insensitive"))
dialog.banlistTable.resizeColumnsToContents()
dialog.exec()
"""Controller for banlist button"""
if not self.temp_freqlog:
self.temp_freqlog = Freqlog(self.args.freq_log_path)
bl_dialog = BanlistDialog()

def refresh_banlist():
"""Refresh banlist table"""
banlist_case, banlist_caseless = self.temp_freqlog.list_banned_words()
bl_dialog.banlistTable.setRowCount(len(banlist_case) + len(banlist_caseless))
for i, word in enumerate(banlist_case):
bl_dialog.banlistTable.setItem(i, 0, QTableWidgetItem(word.word))
bl_dialog.banlistTable.setItem(i, 1,
QTableWidgetItem(
str(word.date_added.isoformat(sep=" ", timespec="seconds"))))
bl_dialog.banlistTable.setItem(i, 2, QTableWidgetItem("Sensitive"))
for i, word in enumerate(banlist_caseless):
bl_dialog.banlistTable.setItem(i + len(banlist_case), 0, QTableWidgetItem(word.word))
bl_dialog.banlistTable.setItem(i + len(banlist_case), 1,
QTableWidgetItem(
str(word.date_added.isoformat(sep=" ", timespec="seconds"))))
bl_dialog.banlistTable.setItem(i + len(banlist_case), 2, QTableWidgetItem("Insensitive"))
bl_dialog.banlistTable.resizeColumnsToContents()

refresh_banlist()

def banword():
"""Controller for banword button"""
bw_dialog = BanwordDialog()

def add_banword():
"""Controller for add button in banword dialog"""
word = bw_dialog.wordInput.text()
if bw_dialog.sensitive.isChecked():
self.temp_freqlog.ban_word(word, CaseSensitivity.SENSITIVE)
elif bw_dialog.firstChar.isChecked():
self.temp_freqlog.ban_word(word, CaseSensitivity.FIRST_CHAR)
else:
self.temp_freqlog.ban_word(word, CaseSensitivity.INSENSITIVE)

# Connect Ok button to add_banword
bw_dialog.buttonBox.accepted.connect(add_banword)
bw_dialog.exec()
refresh_banlist()

# TODO: support banning from right click menu
def remove_banword():
"""Controller for remove button in banlist dialog"""
# Get currently selected row(s)
selected_rows = bl_dialog.banlistTable.selectionModel().selectedRows()
if len(selected_rows) == 0:
return

# Get word(s) from selected row(s)
selected_words = {}
for row in selected_rows:
selected_words[
bl_dialog.banlistTable.item(row.row(), 0).text()
] = (CaseSensitivity.SENSITIVE if bl_dialog.banlistTable.item(row.row(), 2).text() == "Sensitive"
else CaseSensitivity.INSENSITIVE)
confDialog = ConfirmDialog()
confDialog.confirmText.setText(f"Unban {len(selected_words)} word{'s' if len(selected_words) > 1 else ''}?")
confDialog.buttonBox.accepted.connect(lambda: self.temp_freqlog.unban_words(selected_words))
confDialog.exec()
refresh_banlist()

bl_dialog.addButton.clicked.connect(banword)
bl_dialog.removeButton.clicked.connect(remove_banword)
bl_dialog.exec()

def exec(self):
"""Start the GUI"""
self.window.show()
self.refresh()
self.app.exec()
3 changes: 2 additions & 1 deletion tests/Freqlog/backends/SQLite/test_SQLiteBackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,15 @@ def test_ban_unban_word(loaded_backend, word, case, original, remaining):
# Pre-ban
assert backend.check_banned(word, case) is False
assert len(backend.list_words(0, WordMetadataAttr.frequency, True, case)) == original
assert backend.list_banned_words(0, BanlistAttr.word, True) == ([], [])
assert backend.list_banned_words(0, BanlistAttr.word, True) == (set(), set())

backend.ban_word(word, case, TIME)

# Post-ban, pre-unban
assert backend.check_banned(word, case) is True
assert backend.get_word_metadata(word, case) is None
res, res1 = backend.list_banned_words(0, BanlistAttr.word, True)
res, res1 = list(res), list(res1)
assert len(res) == 2 if case == CaseSensitivity.FIRST_CHAR else 1
assert res[0].word == word
assert close_to(res[0].date_added, TIME)
Expand Down
4 changes: 2 additions & 2 deletions ui/banlist.ui
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@
<number>6</number>
</property>
<item>
<widget class="QToolButton" name="toolButton_2">
<widget class="QToolButton" name="addButton">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolButton">
<widget class="QToolButton" name="removeButton">
<property name="text">
<string>Remove</string>
</property>
Expand Down
7 changes: 5 additions & 2 deletions ui/banword.ui
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@
<item>
<widget class="QRadioButton" name="insensitive">
<property name="text">
<string>First Char</string>
<string>Insensitive</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
Expand All @@ -57,7 +60,7 @@
<item>
<widget class="QRadioButton" name="firstChar">
<property name="text">
<string>Insensitive</string>
<string>First char</string>
</property>
</widget>
</item>
Expand Down
19 changes: 13 additions & 6 deletions ui/confirm.ui
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<class>ConfirmDialog</class>
<widget class="QDialog" name="ConfirmDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
<width>307</width>
<height>80</height>
</rect>
</property>
<property name="windowTitle">
<string>Ban word</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="confirmText">
<property name="text">
<string>Are you sure?</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
Expand All @@ -31,7 +38,7 @@
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Dialog</receiver>
<receiver>ConfirmDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
Expand All @@ -47,7 +54,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Dialog</receiver>
<receiver>ConfirmDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
Expand Down

0 comments on commit a3a925c

Please sign in to comment.