diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b2e036..595c060 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,3 @@ -# 0.5.2 - - * Update icon again to remove background - * Adjust History icon and reorder toolbar items - * Try to address checkbox/bullet size issues (again) - * Fix HTML export of markdown (with newlines, tables and other styling preserved) - # 0.5.1 * Try to address Noto Sans font issue that works for both numbers and checkbox/bullets. diff --git a/README.md b/README.md index 5cf77e5..cdfdfc5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ## Introduction -Bouquin ("Book-ahn") is a notebook and planner application written in Python, Qt and SQLCipher. +Bouquin ("Book-ahn") is a notebook and planner application written in Python, PyQt and SQLCipher. It is designed to treat each day as its own 'page', complete with Markdown rendering, tagging, search, reminders and time logging for those of us who need to keep track of not just TODOs, but diff --git a/bouquin/db.py b/bouquin/db.py index ba6b6ce..d6211f5 100644 --- a/bouquin/db.py +++ b/bouquin/db.py @@ -5,7 +5,6 @@ import datetime as _dt import hashlib import html import json -import markdown import re from dataclasses import dataclass @@ -441,33 +440,14 @@ class DBManager: '', '', f"{html.escape(title)}", - "", + "", "", f"

{html.escape(title)}

", ] for d, c in entries: - body_html = markdown.markdown( - c, - extensions=[ - "extra", - "nl2br", - ], - output_format="html5", - ) - parts.append( - f"
" - f"
" - f"
{body_html}
" - f"
" + f"
{c}
" ) parts.append("") diff --git a/bouquin/icons/bouquin.svg b/bouquin/icons/bouquin.svg index b282050..e3d5e51 100644 --- a/bouquin/icons/bouquin.svg +++ b/bouquin/icons/bouquin.svg @@ -4,10 +4,21 @@ viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" > + + + diff --git a/bouquin/markdown_editor.py b/bouquin/markdown_editor.py index ac8a849..27850f6 100644 --- a/bouquin/markdown_editor.py +++ b/bouquin/markdown_editor.py @@ -119,22 +119,6 @@ class MarkdownEditor(QTextEdit): self._apply_code_block_spacing() QTimer.singleShot(0, self._update_code_block_row_backgrounds) - def setFont(self, font: QFont) -> None: # type: ignore[override] - """ - Ensure that whenever the base editor font changes, our highlighter - re-computes checkbox / bullet formats. - """ - # Keep qfont in sync - self.qfont = QFont(font) - super().setFont(self.qfont) - - # If the highlighter is already attached, let it rebuild its formats - highlighter = getattr(self, "highlighter", None) - if highlighter is not None: - refresh = getattr(highlighter, "refresh_for_font_change", None) - if callable(refresh): - refresh() - def showEvent(self, e): super().showEvent(e) # First time the widget is shown, Qt may rebuild layout once more. diff --git a/bouquin/markdown_highlighter.py b/bouquin/markdown_highlighter.py index f9826ff..7674d1b 100644 --- a/bouquin/markdown_highlighter.py +++ b/bouquin/markdown_highlighter.py @@ -6,7 +6,6 @@ from PySide6.QtGui import ( QColor, QFont, QFontDatabase, - QFontMetrics, QGuiApplication, QPalette, QSyntaxHighlighter, @@ -34,14 +33,6 @@ class MarkdownHighlighter(QSyntaxHighlighter): self._setup_formats() self.rehighlight() - def refresh_for_font_change(self) -> None: - """ - Called when the editor's base font changes (zoom / settings). - It rebuilds any formats that depend on the editor font metrics. - """ - self._setup_formats() - self.rehighlight() - def _setup_formats(self): """Setup text formats for different markdown elements.""" @@ -119,21 +110,8 @@ class MarkdownHighlighter(QSyntaxHighlighter): # Use Symbols font for checkbox and bullet glyphs if present if self._editor is not None and hasattr(self._editor, "symbols_font_family"): - base_font = QFont(self._editor.qfont) # copy of editor font - symbols_font = QFont(self._editor.symbols_font_family) - symbols_font.setPointSizeF(base_font.pointSizeF()) - - base_metrics = QFontMetrics(base_font) - sym_metrics = QFontMetrics(symbols_font) - - # If Symbols glyphs are noticeably shorter than the text, - # scale them up so the visual heights roughly match. - if sym_metrics.height() > 0: - ratio = base_metrics.height() / sym_metrics.height() - if ratio > 1.05: # more than ~5% smaller - ratio = min(ratio, 1.4) # Oh, Tod, Tod. Don't overdo it. - symbols_font.setPointSizeF(symbols_font.pointSizeF() * ratio) - + base_size = self._editor.qfont.pointSize() + symbols_font = QFont(self._editor.symbols_font_family, base_size) self.checkbox_format.setFont(symbols_font) self.bullet_format.setFont(symbols_font) diff --git a/bouquin/reminders.py b/bouquin/reminders.py index 5306206..f99eef7 100644 --- a/bouquin/reminders.py +++ b/bouquin/reminders.py @@ -191,7 +191,7 @@ class UpcomingRemindersWidget(QFrame): self.toggle_btn.clicked.connect(self._on_toggle) self.add_btn = QToolButton() - self.add_btn.setText("⏰") + self.add_btn.setIcon(self.style().standardIcon(QStyle.SP_FileDialogNewFolder)) self.add_btn.setToolTip("Add Reminder") self.add_btn.setAutoRaise(True) self.add_btn.clicked.connect(self._add_reminder) diff --git a/bouquin/toolbar.py b/bouquin/toolbar.py index c4274a4..cba1820 100644 --- a/bouquin/toolbar.py +++ b/bouquin/toolbar.py @@ -100,17 +100,6 @@ class ToolBar(QToolBar): self.actCheckboxes.setToolTip(strings._("toolbar_toggle_checkboxes")) self.actCheckboxes.triggered.connect(self.checkboxesRequested) - # Images - self.actInsertImg = QAction("📸", self) - self.actInsertImg.setToolTip(strings._("insert_images")) - self.actInsertImg.setShortcut("Ctrl+Shift+I") - self.actInsertImg.triggered.connect(self.insertImageRequested) - - # History button - self.actHistory = QAction("🔁", self) - self.actHistory.setToolTip(strings._("history")) - self.actHistory.triggered.connect(self.historyRequested) - # Alarm / reminder self.actAlarm = QAction("⏰", self) self.actAlarm.setToolTip(strings._("toolbar_alarm")) @@ -126,6 +115,17 @@ class ToolBar(QToolBar): self.actTable.setToolTip(strings._("toolbar_insert_table")) self.actTable.triggered.connect(self.tableRequested) + # Images + self.actInsertImg = QAction("📸", self) + self.actInsertImg.setToolTip(strings._("insert_images")) + self.actInsertImg.setShortcut("Ctrl+Shift+I") + self.actInsertImg.triggered.connect(self.insertImageRequested) + + # History button + self.actHistory = QAction("⎌", self) + self.actHistory.setToolTip(strings._("history")) + self.actHistory.triggered.connect(self.historyRequested) + # Set exclusive buttons in QActionGroups self.grpHeadings = QActionGroup(self) self.grpHeadings.setExclusive(True) @@ -162,10 +162,10 @@ class ToolBar(QToolBar): self.actBullets, self.actNumbers, self.actCheckboxes, - self.actTable, - self.actInsertImg, self.actAlarm, self.actTimer, + self.actTable, + self.actInsertImg, self.actHistory, ] ) @@ -195,7 +195,7 @@ class ToolBar(QToolBar): self._style_letter_button(self.actTable, "⊞") # History - self._style_letter_button(self.actHistory, "🔁") + self._style_letter_button(self.actHistory, "⎌") def _style_letter_button( self, diff --git a/poetry.lock b/poetry.lock index b968699..ac46700 100644 --- a/poetry.lock +++ b/poetry.lock @@ -307,21 +307,6 @@ files = [ {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, ] -[[package]] -name = "markdown" -version = "3.10" -description = "Python implementation of John Gruber's Markdown." -optional = false -python-versions = ">=3.10" -files = [ - {file = "markdown-3.10-py3-none-any.whl", hash = "sha256:b5b99d6951e2e4948d939255596523444c0e677c669700b1d17aa4a8a464cb7c"}, - {file = "markdown-3.10.tar.gz", hash = "sha256:37062d4f2aa4b2b6b32aefb80faa300f82cc790cb949a35b8caede34f2b68c0e"}, -] - -[package.extras] -docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] -testing = ["coverage", "pyyaml"] - [[package]] name = "packaging" version = "25.0" @@ -759,4 +744,4 @@ zstd = ["zstandard (>=0.18.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.14" -content-hash = "86db2b4d6498ce9eba7fa9aedf9ce58fec6a63542b5f3bdb3cf6c4067e5b87df" +content-hash = "d5fd8ea759b6bd3f23336930bdce9241659256ed918ec31746787cc86e817235" diff --git a/pyproject.toml b/pyproject.toml index ce8e44a..6f13468 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bouquin" -version = "0.5.2" +version = "0.5.1" description = "Bouquin is a simple, opinionated notebook application written in Python, PyQt and SQLCipher." authors = ["Miguel Jacq "] readme = "README.md" @@ -14,7 +14,6 @@ python = ">=3.10,<3.14" pyside6 = ">=6.8.1,<7.0.0" sqlcipher3-wheels = "^0.5.5.post0" requests = "^2.32.5" -markdown = "^3.10" [tool.poetry.scripts] bouquin = "bouquin.__main__:main" diff --git a/tests/test_reminders.py b/tests/test_reminders.py index c003d86..94be08c 100644 --- a/tests/test_reminders.py +++ b/tests/test_reminders.py @@ -765,6 +765,35 @@ def test_reminder_not_today_skipped(qtbot, fresh_db): assert len(triggered_texts) == 0 +def test_reminder_context_menu_single_item(qtbot, fresh_db): + """Test context menu for a single reminder item.""" + reminder = Reminder( + id=None, + text="Test reminder", + reminder_type=ReminderType.ONCE, + time_str="14:30", + date_iso=date.today().isoformat(), + active=True, + ) + fresh_db.save_reminder(reminder) + + reminders_widget = UpcomingRemindersWidget(fresh_db) + qtbot.addWidget(reminders_widget) + reminders_widget.show() + + # Refresh to populate the list + reminders_widget.refresh() + + # Select the first item + if reminders_widget.reminder_list.count() > 0: + reminders_widget.reminder_list.setCurrentRow(0) + + # Show context menu (won't actually display in tests) + reminders_widget._show_reminder_context_menu( + reminders_widget.reminder_list.pos() + ) + + def test_reminder_context_menu_no_selection(qtbot, fresh_db): """Test context menu with no selection returns early.""" reminders_widget = UpcomingRemindersWidget(fresh_db)