bouquin 0.4__tar.gz → 0.4.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. {bouquin-0.4 → bouquin-0.4.2}/PKG-INFO +1 -1
  2. {bouquin-0.4 → bouquin-0.4.2}/bouquin/bug_report_dialog.py +1 -8
  3. {bouquin-0.4 → bouquin-0.4.2}/bouquin/db.py +7 -11
  4. {bouquin-0.4 → bouquin-0.4.2}/bouquin/key_prompt.py +3 -2
  5. {bouquin-0.4 → bouquin-0.4.2}/bouquin/locales/en.json +94 -91
  6. {bouquin-0.4 → bouquin-0.4.2}/bouquin/locales/fr.json +0 -12
  7. {bouquin-0.4 → bouquin-0.4.2}/bouquin/locales/it.json +1 -13
  8. {bouquin-0.4 → bouquin-0.4.2}/bouquin/main_window.py +80 -16
  9. {bouquin-0.4 → bouquin-0.4.2}/bouquin/markdown_editor.py +142 -41
  10. {bouquin-0.4 → bouquin-0.4.2}/bouquin/save_dialog.py +13 -1
  11. {bouquin-0.4 → bouquin-0.4.2}/bouquin/settings.py +9 -0
  12. {bouquin-0.4 → bouquin-0.4.2}/bouquin/settings_dialog.py +128 -61
  13. {bouquin-0.4 → bouquin-0.4.2}/bouquin/statistics_dialog.py +2 -1
  14. {bouquin-0.4 → bouquin-0.4.2}/bouquin/tag_browser.py +4 -4
  15. {bouquin-0.4 → bouquin-0.4.2}/bouquin/time_log.py +127 -38
  16. {bouquin-0.4 → bouquin-0.4.2}/bouquin/toolbar.py +19 -3
  17. {bouquin-0.4 → bouquin-0.4.2}/pyproject.toml +1 -1
  18. {bouquin-0.4 → bouquin-0.4.2}/LICENSE +0 -0
  19. {bouquin-0.4 → bouquin-0.4.2}/README.md +0 -0
  20. {bouquin-0.4 → bouquin-0.4.2}/bouquin/__init__.py +0 -0
  21. {bouquin-0.4 → bouquin-0.4.2}/bouquin/__main__.py +0 -0
  22. {bouquin-0.4 → bouquin-0.4.2}/bouquin/find_bar.py +0 -0
  23. {bouquin-0.4 → bouquin-0.4.2}/bouquin/flow_layout.py +0 -0
  24. {bouquin-0.4 → bouquin-0.4.2}/bouquin/history_dialog.py +0 -0
  25. {bouquin-0.4 → bouquin-0.4.2}/bouquin/lock_overlay.py +0 -0
  26. {bouquin-0.4 → bouquin-0.4.2}/bouquin/main.py +0 -0
  27. {bouquin-0.4 → bouquin-0.4.2}/bouquin/markdown_highlighter.py +0 -0
  28. {bouquin-0.4 → bouquin-0.4.2}/bouquin/search.py +0 -0
  29. {bouquin-0.4 → bouquin-0.4.2}/bouquin/strings.py +0 -0
  30. {bouquin-0.4 → bouquin-0.4.2}/bouquin/tags_widget.py +0 -0
  31. {bouquin-0.4 → bouquin-0.4.2}/bouquin/theme.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bouquin
3
- Version: 0.4
3
+ Version: 0.4.2
4
4
  Summary: Bouquin is a simple, opinionated notebook application written in Python, PyQt and SQLCipher.
5
5
  Home-page: https://git.mig5.net/mig5/bouquin
6
6
  License: GPL-3.0-or-later
@@ -70,10 +70,6 @@ class BugReportDialog(QDialog):
70
70
  self.text_edit.setPlainText(text[: self.MAX_CHARS])
71
71
  self.text_edit.blockSignals(False)
72
72
 
73
- # Clamp cursor position to end of text
74
- if pos > self.MAX_CHARS:
75
- pos = self.MAX_CHARS
76
-
77
73
  cursor.setPosition(pos)
78
74
  self.text_edit.setTextCursor(cursor)
79
75
 
@@ -88,10 +84,7 @@ class BugReportDialog(QDialog):
88
84
  return
89
85
 
90
86
  # Get current app version
91
- try:
92
- version = importlib.metadata.version("bouquin")
93
- except importlib.metadata.PackageNotFoundError:
94
- version = "unknown"
87
+ version = importlib.metadata.version("bouquin")
95
88
 
96
89
  payload: dict[str, str] = {
97
90
  "message": text,
@@ -61,7 +61,10 @@ class DBConfig:
61
61
  idle_minutes: int = 15 # 0 = never lock
62
62
  theme: str = "system"
63
63
  move_todos: bool = False
64
+ tags: bool = True
65
+ time_log: bool = True
64
66
  locale: str = "en"
67
+ font_size: int = 11
65
68
 
66
69
 
67
70
  class DBManager:
@@ -734,12 +737,8 @@ class DBManager:
734
737
  page_most_revisions_count = c
735
738
  page_most_revisions = date_iso
736
739
 
737
- try:
738
- d = _dt.date.fromisoformat(date_iso)
739
- revisions_by_date[d] = c
740
- except ValueError:
741
- # Ignore malformed dates
742
- pass
740
+ d = _dt.date.fromisoformat(date_iso)
741
+ revisions_by_date[d] = c
743
742
 
744
743
  # 4) total words + per-date words (current version only)
745
744
  entries = self.get_all_entries()
@@ -749,11 +748,8 @@ class DBManager:
749
748
  for date_iso, content in entries:
750
749
  wc = self._count_words(content or "")
751
750
  total_words += wc
752
- try:
753
- d = _dt.date.fromisoformat(date_iso)
754
- words_by_date[d] = wc
755
- except ValueError:
756
- pass
751
+ d = _dt.date.fromisoformat(date_iso)
752
+ words_by_date[d] = wc
757
753
 
758
754
  # tags + page with most tags
759
755
 
@@ -99,8 +99,9 @@ class KeyPrompt(QDialog):
99
99
 
100
100
  def db_path(self) -> Path | None:
101
101
  """Return the chosen DB path (or None if unchanged/not shown)."""
102
+ p = self._db_path
102
103
  if self.path_edit is not None:
103
104
  text = self.path_edit.text().strip()
104
105
  if text:
105
- return Path(text)
106
- return self._db_path
106
+ p = Path(text)
107
+ return p
@@ -5,7 +5,6 @@
5
5
  "db_version_id_does_not_belong_to_the_given_date": "version_id does not belong to the given date",
6
6
  "db_key_incorrect": "The key is probably incorrect",
7
7
  "db_database_error": "Database error",
8
- "database_path": "Database path",
9
8
  "database_maintenance": "Database maintenance",
10
9
  "database_compact": "Compact the database",
11
10
  "database_compact_explanation": "Compacting runs VACUUM on the database. This can help reduce its size.",
@@ -26,16 +25,15 @@
26
25
  "close": "Close",
27
26
  "find": "Find",
28
27
  "file": "File",
29
- "locale": "Locale",
28
+ "locale": "Language",
30
29
  "locale_restart": "Please restart the application to load the new language.",
31
30
  "settings": "Settings",
32
31
  "theme": "Theme",
33
32
  "system": "System",
34
33
  "light": "Light",
35
34
  "dark": "Dark",
36
- "behaviour": "Behaviour",
37
35
  "never": "Never",
38
- "browse": "Browse",
36
+ "close_tab": "Close tab",
39
37
  "previous": "Previous",
40
38
  "previous_day": "Previous day",
41
39
  "next": "Next",
@@ -44,7 +42,6 @@
44
42
  "show": "Show",
45
43
  "history": "History",
46
44
  "view_history": "View History",
47
- "export": "Export",
48
45
  "export_accessible_flag": "&Export",
49
46
  "export_entries": "Export entries",
50
47
  "export_complete": "Export complete",
@@ -97,15 +94,23 @@
97
94
  "backup_encrypted_notebook": "Backup encrypted notebook",
98
95
  "enter_a_name_for_this_version": "Enter a name for this version",
99
96
  "new_version_i_saved_at": "New version I saved at",
97
+ "appearance": "Appearance",
98
+ "security": "Security",
99
+ "features": "Features",
100
+ "database": "Database",
100
101
  "save_key_warning": "If you don't want to be prompted for your encryption key, check this to remember it.\nWARNING: the key is saved to disk and could be recoverable if your disk is compromised.",
101
102
  "lock_screen_when_idle": "Lock screen when idle",
102
- "autolock_explanation": "Bouquin will automatically lock the notepad after this length of time, after which you'll need to re-enter the key to unlock it.'nSet to 0 (never) to never lock.",
103
+ "autolock_explanation": "Bouquin will automatically lock the notepad after this length of time, after which you'll need to re-enter the key to unlock it.\nSet to 0 (never) to never lock.",
104
+ "font_size": "Font size",
105
+ "font_size_explanation": "Changing this value will change the size of all paragraph text in all tabs. It does not affect heading or code block size",
103
106
  "search_for_notes_here": "Search for notes here",
104
107
  "toolbar_format": "Format",
105
108
  "toolbar_bold": "Bold",
106
109
  "toolbar_italic": "Italic",
107
110
  "toolbar_strikethrough": "Strikethrough",
108
111
  "toolbar_normal_paragraph_text": "Normal paragraph text",
112
+ "toolbar_font_smaller": "Smaller text",
113
+ "toolbar_font_larger": "Larger text",
109
114
  "toolbar_bulleted_list": "Bulleted list",
110
115
  "toolbar_numbered_list": "Numbered list",
111
116
  "toolbar_code_block": "Code block",
@@ -114,20 +119,11 @@
114
119
  "tags": "Tags",
115
120
  "tag": "Tag",
116
121
  "manage_tags": "Manage tags",
117
- "main_window_manage_tags_accessible_flag": "Manage &Tags",
118
122
  "add_tag_placeholder": "Add a tag and press Enter",
119
123
  "tag_browser_title": "Tag Browser",
120
124
  "tag_browser_instructions": "Click a tag to expand and see all pages with that tag. Click a date to open it. Select a tag to edit its name, change its color, or delete it globally.",
121
- "tag_name": "Tag name",
122
- "tag_color_hex": "Hex colour",
123
125
  "color_hex": "Colour",
124
126
  "date": "Date",
125
- "pick_color": "Pick colour",
126
- "invalid_color_title": "Invalid colour",
127
- "invalid_color_message": "Please enter a valid hex colour like #RRGGBB.",
128
- "add": "Add",
129
- "remove": "Remove",
130
- "ok": "OK",
131
127
  "add_a_tag": "Add a tag",
132
128
  "edit_tag_name": "Edit tag name",
133
129
  "new_tag_name": "New tag name:",
@@ -155,6 +151,7 @@
155
151
  "bug_report_send_failed": "Could not send bug report.",
156
152
  "bug_report_sent_ok": "Bug report sent. Thank you!",
157
153
  "send": "Send",
154
+ "reminder": "Reminder",
158
155
  "set_reminder": "Set reminder prompt",
159
156
  "set_reminder_prompt": "Enter a time",
160
157
  "reminder_no_text_fallback": "You scheduled a reminder to alert you now!",
@@ -162,80 +159,86 @@
162
159
  "invalid_time_message": "Please enter a time in the format HH:MM",
163
160
  "dismiss": "Dismiss",
164
161
  "toolbar_alarm": "Set reminder alarm",
165
- "activities": "Activities",
166
- "activity": "Activity",
167
- "note": "Note",
168
- "activity_delete_error_message": "A problem occurred deleting the activity",
169
- "activity_delete_error_title": "Problem deleting activity",
170
- "activity_rename_error_message": "A problem occurred renaming the activity",
171
- "activity_rename_error_title": "Problem renaming activity",
172
- "activity_required_message": "An activity name is required",
173
- "activity_required_title": "Activity name required",
174
- "add_activity": "Add activity",
175
- "add_project": "Add project",
176
- "add_time_entry": "Add time entry",
177
- "time_period": "Time period",
178
- "by_day": "by day",
179
- "by_month": "by month",
180
- "by_week": "by week",
181
- "date_range": "Date range",
182
- "delete_activity": "Delete activity",
183
- "delete_activity_confirm": "Are you sure you want to delete this activity?",
184
- "delete_activity_title": "Delete activity - are you sure?",
185
- "delete_project": "Delete project",
186
- "delete_project_confirm": "Are you sure you want to delete this project?",
187
- "delete_project_title": "Delete project - are you sure?",
188
- "delete_time_entry": "Delete time entry",
189
- "group_by": "Group by",
190
- "hours": "Hours",
191
- "invalid_activity_message": "The activity is invalid",
192
- "invalid_activity_title": "Invalid activity",
193
- "invalid_project_message": "The project is invalid",
194
- "invalid_project_title": "Invalid project",
195
- "label_key": "Label",
196
- "manage_activities": "Manage activities",
197
- "manage_projects": "Manage projects",
198
- "manage_projects_activities": "Manage project activities",
199
- "open_time_log": "Open time log",
200
- "project": "Project",
201
- "project_delete_error_message": "A problem occurred deleting the project",
202
- "project_delete_error_title": "Problem deleting project",
203
- "project_rename_error_message": "A problem occurred renaming the project",
204
- "project_rename_error_title": "Problem renaming project",
205
- "project_required_message": "A project is required",
206
- "project_required_title": "Project required",
207
- "projects": "Projects",
208
- "rename_activity": "Rename activity",
209
- "rename_project": "Rename project",
210
- "run_report": "Run report",
211
- "add_project_label": "Add a project",
212
- "add_activity_label": "Add an activity",
213
- "select_activity_message": "Select an activity",
214
- "select_activity_title": "Select activity",
215
- "select_project_message": "Select a project",
216
- "select_project_title": "Select project",
217
- "time_log": "Time log",
218
- "time_log_collapsed_hint": "Time log",
219
- "time_log_date_label": "Time log date: {date}",
220
- "time_log_for": "Time log for {date}",
221
- "time_log_no_date": "Time log",
222
- "time_log_no_entries": "No time entries yet",
223
- "time_log_report": "Time log report",
224
- "time_log_report_title": "Time log for {project}",
225
- "time_log_report_meta": "From {start} to {end}, grouped {granularity}",
226
- "time_log_total_hours": "Total time spent",
227
- "time_log_with_total": "Time log ({hours:.2f}h)",
228
- "time_log_total_hours": "Total for day: {hours:.2f}h",
229
- "title_key": "title",
230
- "update_time_entry": "Update time entry",
231
- "time_report_total": "Total: {hours:.2f} hours",
232
- "no_report_title": "No report",
233
- "no_report_message": "Please run a report before exporting.",
234
- "total": "Total",
235
- "export_csv": "Export CSV",
236
- "export_csv_error_title": "Export failed",
237
- "export_csv_error_message": "Could not write CSV file:\n{error}",
238
- "export_pdf": "Export PDF",
239
- "export_pdf_error_title": "PDF export failed",
240
- "export_pdf_error_message": "Could not write PDF file:\n{error}"
162
+ "activities": "Activities",
163
+ "activity": "Activity",
164
+ "note": "Note",
165
+ "activity_delete_error_message": "A problem occurred deleting the activity",
166
+ "activity_delete_error_title": "Problem deleting activity",
167
+ "activity_rename_error_message": "A problem occurred renaming the activity",
168
+ "activity_rename_error_title": "Problem renaming activity",
169
+ "activity_required_message": "An activity name is required",
170
+ "activity_required_title": "Activity name required",
171
+ "add_activity": "Add activity",
172
+ "add_project": "Add project",
173
+ "add_time_entry": "Add time entry",
174
+ "time_period": "Time period",
175
+ "by_day": "by day",
176
+ "by_month": "by month",
177
+ "by_week": "by week",
178
+ "date_range": "Date range",
179
+ "delete_activity": "Delete activity",
180
+ "delete_activity_confirm": "Are you sure you want to delete this activity?",
181
+ "delete_activity_title": "Delete activity - are you sure?",
182
+ "delete_project": "Delete project",
183
+ "delete_project_confirm": "Are you sure you want to delete this project?",
184
+ "delete_project_title": "Delete project - are you sure?",
185
+ "delete_time_entry": "Delete time entry",
186
+ "group_by": "Group by",
187
+ "hours": "Hours",
188
+ "invalid_activity_message": "The activity is invalid",
189
+ "invalid_activity_title": "Invalid activity",
190
+ "invalid_project_message": "The project is invalid",
191
+ "invalid_project_title": "Invalid project",
192
+ "manage_activities": "Manage activities",
193
+ "manage_projects": "Manage projects",
194
+ "manage_projects_activities": "Manage project activities",
195
+ "open_time_log": "Open time log",
196
+ "project": "Project",
197
+ "project_delete_error_message": "A problem occurred deleting the project",
198
+ "project_delete_error_title": "Problem deleting project",
199
+ "project_rename_error_message": "A problem occurred renaming the project",
200
+ "project_rename_error_title": "Problem renaming project",
201
+ "project_required_message": "A project is required",
202
+ "project_required_title": "Project required",
203
+ "projects": "Projects",
204
+ "rename_activity": "Rename activity",
205
+ "rename_project": "Rename project",
206
+ "run_report": "Run report",
207
+ "add_activity_title": "Add activity",
208
+ "add_activity_label": "Add an activity",
209
+ "rename_activity_label": "Rename activity",
210
+ "add_project_title": "Add project",
211
+ "add_project_label": "Add a project",
212
+ "rename_activity_title": "Rename this activity",
213
+ "rename_project_label": "Rename project",
214
+ "rename_project_title": "Rename this project",
215
+ "select_activity_message": "Select an activity",
216
+ "select_activity_title": "Select activity",
217
+ "select_project_message": "Select a project",
218
+ "select_project_title": "Select project",
219
+ "time_log": "Time log",
220
+ "time_log_collapsed_hint": "Time log",
221
+ "time_log_date_label": "Time log date: {date}",
222
+ "time_log_for": "Time log for {date}",
223
+ "time_log_no_date": "Time log",
224
+ "time_log_no_entries": "No time entries yet",
225
+ "time_log_report": "Time log report",
226
+ "time_log_report_title": "Time log for {project}",
227
+ "time_log_report_meta": "From {start} to {end}, grouped {granularity}",
228
+ "time_log_total_hours": "Total time spent",
229
+ "time_log_with_total": "Time log ({hours:.2f}h)",
230
+ "time_log_total_hours": "Total for day: {hours:.2f}h",
231
+ "update_time_entry": "Update time entry",
232
+ "time_report_total": "Total: {hours:.2f} hours",
233
+ "no_report_title": "No report",
234
+ "no_report_message": "Please run a report before exporting.",
235
+ "total": "Total",
236
+ "export_csv": "Export CSV",
237
+ "export_csv_error_title": "Export failed",
238
+ "export_csv_error_message": "Could not write CSV file:\n{error}",
239
+ "export_pdf": "Export PDF",
240
+ "export_pdf_error_title": "PDF export failed",
241
+ "export_pdf_error_message": "Could not write PDF file:\n{error}",
242
+ "enable_tags_feature": "Enable Tags",
243
+ "enable_time_log_feature": "Enable Time Logging"
241
244
  }
@@ -5,7 +5,6 @@
5
5
  "db_version_id_does_not_belong_to_the_given_date": "version_id ne correspond pas à la date indiquée",
6
6
  "db_key_incorrect": "La clé est peut-être incorrecte",
7
7
  "db_database_error": "Erreur de base de données",
8
- "database_path": "Chemin de la base de données",
9
8
  "database_maintenance": "Maintenance de la base de données",
10
9
  "database_compact": "Compacter la base de données",
11
10
  "database_compact_explanation": "La compaction exécute VACUUM sur la base de données. Cela peut aider à réduire sa taille.",
@@ -33,9 +32,7 @@
33
32
  "system": "Système",
34
33
  "light": "Clair",
35
34
  "dark": "Sombre",
36
- "behaviour": "Comportement",
37
35
  "never": "Jamais",
38
- "browse": "Parcourir",
39
36
  "previous": "Précédent",
40
37
  "previous_day": "Jour précédent",
41
38
  "next": "Suivant",
@@ -44,7 +41,6 @@
44
41
  "show": "Afficher",
45
42
  "history": "Historique",
46
43
  "view_history": "Afficher l'historique",
47
- "export": "Exporter",
48
44
  "export_accessible_flag": "E&xporter",
49
45
  "export_entries": "Exporter les entrées",
50
46
  "export_complete": "Exportation terminée",
@@ -117,16 +113,8 @@
117
113
  "add_tag_placeholder": "Ajouter une étiquette et appuyez sur Entrée",
118
114
  "tag_browser_title": "Navigateur de étiquettes",
119
115
  "tag_browser_instructions": "Cliquez sur une étiquette pour l'étendre et voir toutes les pages avec cette étiquette. Cliquez sur une date pour l'ouvrir. Sélectionnez une étiquette pour modifier son nom, changer sa couleur ou la supprimer globalement.",
120
- "tag_name": "Nom de l'étiquette",
121
- "tag_color_hex": "Couleur hexadécimale",
122
116
  "color_hex": "Couleur",
123
117
  "date": "Date",
124
- "pick_color": "Choisir la couleur",
125
- "invalid_color_title": "Couleur invalide",
126
- "invalid_color_message": "Veuillez entrer une couleur hexadécimale valide comme #RRGGBB.",
127
- "add": "Ajouter",
128
- "remove": "Supprimer",
129
- "ok": "OK",
130
118
  "add_a_tag": "Ajouter une étiquette",
131
119
  "edit_tag_name": "Modifier le nom de l'étiquette",
132
120
  "new_tag_name": "Nouveau nom de l'étiquette :",
@@ -3,9 +3,8 @@
3
3
  "db_issues_reported": "problema/i segnalato/i",
4
4
  "db_reopen_failed_after_rekey": "Riapertura fallita dopo il cambio chiave",
5
5
  "db_version_id_does_not_belong_to_the_given_date": "version_id non appartiene alla data indicata",
6
- "db_key_incorrect": "La chiave è probabilmente errata",
7
6
  "db_database_error": "Errore del database",
8
- "database_path": "Percorso del database",
7
+ "db_key_incorrect": "La chiave è probabilmente errata",
9
8
  "database_maintenance": "Manutenzione del database",
10
9
  "database_compact": "Compatta il database",
11
10
  "database_compact_explanation": "La compattazione esegue VACUUM sul database. Può aiutare a ridurne le dimensioni.",
@@ -33,9 +32,7 @@
33
32
  "system": "Sistema",
34
33
  "light": "Chiaro",
35
34
  "dark": "Scuro",
36
- "behaviour": "Comportamento",
37
35
  "never": "Mai",
38
- "browse": "Sfoglia",
39
36
  "previous": "Precedente",
40
37
  "previous_day": "Giorno precedente",
41
38
  "next": "Successivo",
@@ -44,7 +41,6 @@
44
41
  "show": "Mostra",
45
42
  "history": "Cronologia",
46
43
  "view_history": "Visualizza cronologia",
47
- "export": "Esporta",
48
44
  "export_accessible_flag": "&Esporta",
49
45
  "export_entries": "Esporta voci",
50
46
  "export_complete": "Esportazione completata",
@@ -116,16 +112,8 @@
116
112
  "add_tag_placeholder": "Aggiungi un tag e premi Invio",
117
113
  "tag_browser_title": "Browser dei tag",
118
114
  "tag_browser_instructions": "Fai clic su un tag per espandere e vedere tutte le pagine con quel tag. Fai clic su una data per aprirla. Seleziona un tag per modificarne il nome, cambiarne il colore o eliminarlo globalmente.",
119
- "tag_name": "Nome del tag",
120
- "tag_color_hex": "Colore esadecimale",
121
115
  "color_hex": "Colore",
122
116
  "date": "Data",
123
- "pick_color": "Scegli colore",
124
- "invalid_color_title": "Colore non valido",
125
- "invalid_color_message": "Inserisci un colore esadecimale valido come #RRGGBB.",
126
- "add": "Aggiungi",
127
- "remove": "Rimuovi",
128
- "ok": "OK",
129
117
  "add_a_tag": "Aggiungi un tag",
130
118
  "edit_tag_name": "Modifica nome tag",
131
119
  "new_tag_name": "Nuovo nome tag:",
@@ -66,7 +66,7 @@ from .statistics_dialog import StatisticsDialog
66
66
  from . import strings
67
67
  from .tags_widget import PageTagsWidget
68
68
  from .theme import ThemeManager
69
- from .time_log import TimeLogWidget, TimeReportDialog
69
+ from .time_log import TimeLogWidget
70
70
  from .toolbar import ToolBar
71
71
 
72
72
 
@@ -92,6 +92,8 @@ class MainWindow(QMainWindow):
92
92
  else:
93
93
  self._try_connect()
94
94
 
95
+ self.settings = QSettings(APP_ORG, APP_NAME)
96
+
95
97
  # ---- UI: Left fixed panel (calendar) + right editor -----------------
96
98
  self.calendar = QCalendarWidget()
97
99
  self.calendar.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
@@ -219,18 +221,10 @@ class MainWindow(QMainWindow):
219
221
  act_backup.setShortcut("Ctrl+Shift+B")
220
222
  act_backup.triggered.connect(self._backup)
221
223
  file_menu.addAction(act_backup)
222
- act_tags = QAction(strings._("main_window_manage_tags_accessible_flag"), self)
223
- act_tags.setShortcut("Ctrl+T")
224
- act_tags.triggered.connect(self.tags._open_manager)
225
- file_menu.addAction(act_tags)
226
224
  act_stats = QAction(strings._("main_window_statistics_accessible_flag"), self)
227
225
  act_stats.setShortcut("Shift+Ctrl+S")
228
226
  act_stats.triggered.connect(self._open_statistics)
229
227
  file_menu.addAction(act_stats)
230
- act_time_report = QAction(strings._("time_log_report"), self)
231
- act_time_report.setShortcut("Ctrl+Shift+L")
232
- act_time_report.triggered.connect(self._open_time_report)
233
- file_menu.addAction(act_time_report)
234
228
  file_menu.addSeparator()
235
229
  act_quit = QAction("&" + strings._("quit"), self)
236
230
  act_quit.setShortcut("Ctrl+Q")
@@ -260,6 +254,13 @@ class MainWindow(QMainWindow):
260
254
  nav_menu.addAction(act_today)
261
255
  self.addAction(act_today)
262
256
 
257
+ act_close_tab = QAction(strings._("close_tab"), self)
258
+ act_close_tab.setShortcut("Ctrl+W")
259
+ act_close_tab.setShortcutContext(Qt.ApplicationShortcut)
260
+ act_close_tab.triggered.connect(self._close_current_tab)
261
+ nav_menu.addAction(act_close_tab)
262
+ self.addAction(act_close_tab)
263
+
263
264
  act_find = QAction(strings._("find_on_page"), self)
264
265
  act_find.setShortcut(QKeySequence.Find)
265
266
  act_find.triggered.connect(self.findBar.show_bar)
@@ -313,8 +314,13 @@ class MainWindow(QMainWindow):
313
314
  self._load_selected_date()
314
315
  self._refresh_calendar_marks()
315
316
 
317
+ # Hide tags and time log widgets if not enabled
318
+ if not self.cfg.tags:
319
+ self.tags.hide()
320
+ if not self.cfg.time_log:
321
+ self.time_log.hide()
322
+
316
323
  # Restore window position from settings
317
- self.settings = QSettings(APP_ORG, APP_NAME)
318
324
  self._restore_window_position()
319
325
 
320
326
  # re-apply all runtime color tweaks when theme changes
@@ -480,6 +486,9 @@ class MainWindow(QMainWindow):
480
486
 
481
487
  editor = MarkdownEditor(self.themes)
482
488
 
489
+ # Apply user’s preferred font size
490
+ self._apply_font_size(editor)
491
+
483
492
  # Set up the editor's event connections
484
493
  editor.currentCharFormatChanged.connect(lambda _f: self._sync_toolbar())
485
494
  editor.cursorPositionChanged.connect(self._sync_toolbar)
@@ -520,6 +529,12 @@ class MainWindow(QMainWindow):
520
529
 
521
530
  self.tab_widget.removeTab(index)
522
531
 
532
+ def _close_current_tab(self):
533
+ """Close the currently active tab via shortcuts (Ctrl+W)."""
534
+ idx = self.tab_widget.currentIndex()
535
+ if idx >= 0:
536
+ self._close_tab(idx)
537
+
523
538
  def _on_tab_changed(self, index: int):
524
539
  """Handle tab change - reconnect toolbar and sync UI."""
525
540
  if index < 0:
@@ -901,6 +916,17 @@ class MainWindow(QMainWindow):
901
916
  pass
902
917
 
903
918
  # ----------------- Some theme helpers -------------------#
919
+ def _apply_font_size(self, editor: MarkdownEditor) -> None:
920
+ """Apply the saved font size to a newly created editor."""
921
+ size = self.cfg.font_size
922
+ editor.qfont.setPointSize(size)
923
+ editor.setFont(editor.qfont)
924
+ self.cfg.font_size = size
925
+ # save size to settings
926
+ cfg = load_db_config()
927
+ cfg.font_size = self.cfg.font_size
928
+ save_db_config(cfg)
929
+
904
930
  def _retheme_overrides(self):
905
931
  self._apply_calendar_text_colors()
906
932
  self._apply_search_highlights(getattr(self, "_search_highlighted_dates", set()))
@@ -984,6 +1010,8 @@ class MainWindow(QMainWindow):
984
1010
  self._tb_numbers = lambda: self._call_editor("toggle_numbers")
985
1011
  self._tb_checkboxes = lambda: self._call_editor("toggle_checkboxes")
986
1012
  self._tb_alarm = self._on_alarm_requested
1013
+ self._tb_font_larger = self._on_font_larger_requested
1014
+ self._tb_font_smaller = self._on_font_smaller_requested
987
1015
 
988
1016
  tb.boldRequested.connect(self._tb_bold)
989
1017
  tb.italicRequested.connect(self._tb_italic)
@@ -996,6 +1024,8 @@ class MainWindow(QMainWindow):
996
1024
  tb.alarmRequested.connect(self._tb_alarm)
997
1025
  tb.insertImageRequested.connect(self._on_insert_image)
998
1026
  tb.historyRequested.connect(self._open_history)
1027
+ tb.fontSizeLargerRequested.connect(self._tb_font_larger)
1028
+ tb.fontSizeSmallerRequested.connect(self._tb_font_smaller)
999
1029
 
1000
1030
  self._toolbar_bound = True
1001
1031
 
@@ -1041,6 +1071,34 @@ class MainWindow(QMainWindow):
1041
1071
  self.toolBar.actBullets.setChecked(bool(bullets_on))
1042
1072
  self.toolBar.actNumbers.setChecked(bool(numbers_on))
1043
1073
 
1074
+ def _change_font_size(self, delta: int) -> None:
1075
+ """Change font size for all editor tabs and save the setting."""
1076
+ old_size = self.cfg.font_size
1077
+ new_size = old_size + delta
1078
+
1079
+ self.cfg.font_size = new_size
1080
+ # save size to settings
1081
+ cfg = load_db_config()
1082
+ cfg.font_size = self.cfg.font_size
1083
+ save_db_config(cfg)
1084
+
1085
+ # Apply font size change to all open editors
1086
+ self._apply_font_size_to_all_tabs(new_size)
1087
+
1088
+ def _apply_font_size_to_all_tabs(self, size: int) -> None:
1089
+ for i in range(self.tab_widget.count()):
1090
+ ed = self.tab_widget.widget(i)
1091
+ if not isinstance(ed, MarkdownEditor):
1092
+ continue
1093
+ ed.qfont.setPointSize(size)
1094
+ ed.setFont(ed.qfont)
1095
+
1096
+ def _on_font_larger_requested(self) -> None:
1097
+ self._change_font_size(+1)
1098
+
1099
+ def _on_font_smaller_requested(self) -> None:
1100
+ self._change_font_size(-1)
1101
+
1044
1102
  # ----------- Alarms handler ------------#
1045
1103
  def _on_alarm_requested(self):
1046
1104
  """Create a one-shot reminder based on the current line in the editor."""
@@ -1307,13 +1365,17 @@ class MainWindow(QMainWindow):
1307
1365
  self.cfg.idle_minutes = getattr(new_cfg, "idle_minutes", self.cfg.idle_minutes)
1308
1366
  self.cfg.theme = getattr(new_cfg, "theme", self.cfg.theme)
1309
1367
  self.cfg.move_todos = getattr(new_cfg, "move_todos", self.cfg.move_todos)
1368
+ self.cfg.tags = getattr(new_cfg, "tags", self.cfg.tags)
1369
+ self.cfg.time_log = getattr(new_cfg, "time_log", self.cfg.time_log)
1310
1370
  self.cfg.locale = getattr(new_cfg, "locale", self.cfg.locale)
1371
+ self.cfg.font_size = getattr(new_cfg, "font_size", self.cfg.font_size)
1311
1372
 
1312
1373
  # Persist once
1313
1374
  save_db_config(self.cfg)
1314
-
1315
1375
  # Apply idle setting immediately (restart the timer with new interval if it changed)
1316
1376
  self._apply_idle_minutes(self.cfg.idle_minutes)
1377
+ # Apply font size to all tabs
1378
+ self._apply_font_size_to_all_tabs(self.cfg.font_size)
1317
1379
 
1318
1380
  # If the DB path changed, reconnect
1319
1381
  if self.cfg.path != old_path:
@@ -1328,6 +1390,13 @@ class MainWindow(QMainWindow):
1328
1390
  self._load_selected_date()
1329
1391
  self._refresh_calendar_marks()
1330
1392
 
1393
+ # Show or hide the tags and time_log features depending on what the settings are now.
1394
+ self.tags.hide() if not self.cfg.tags else self.tags.show()
1395
+ if not self.cfg.time_log:
1396
+ self.time_log.hide()
1397
+ else:
1398
+ self.time_log.show()
1399
+
1331
1400
  # ------------ Statistics handler --------------- #
1332
1401
 
1333
1402
  def _open_statistics(self):
@@ -1345,11 +1414,6 @@ class MainWindow(QMainWindow):
1345
1414
  dlg._heatmap.date_clicked.connect(on_date_clicked)
1346
1415
  dlg.exec()
1347
1416
 
1348
- # ------------ Timesheet report handler --------------- #
1349
- def _open_time_report(self):
1350
- dlg = TimeReportDialog(self.db, self)
1351
- dlg.exec()
1352
-
1353
1417
  # ------------ Window positioning --------------- #
1354
1418
  def _restore_window_position(self):
1355
1419
  geom = self.settings.value("main/geometry", None)