repdf 0.1.3__tar.gz → 0.1.4__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 (51) hide show
  1. {repdf-0.1.3 → repdf-0.1.4}/PKG-INFO +3 -3
  2. {repdf-0.1.3 → repdf-0.1.4}/README.md +2 -2
  3. {repdf-0.1.3 → repdf-0.1.4}/pyproject.toml +1 -1
  4. {repdf-0.1.3 → repdf-0.1.4}/pyproject.toml.orig +1 -1
  5. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/icons.py +5 -7
  6. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/search_panel.py +72 -33
  7. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/strings.py +5 -0
  8. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/__init__.py +0 -0
  9. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/__main__.py +0 -0
  10. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/annotation_data.py +0 -0
  11. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/annotation_editor.py +0 -0
  12. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/annotation_geometry.py +0 -0
  13. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/annotation_graphics.py +0 -0
  14. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/annotation_reader_cache.py +0 -0
  15. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/annotation_spin.py +0 -0
  16. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/annotation_store.py +0 -0
  17. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/annotation_tree.py +0 -0
  18. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/app.py +0 -0
  19. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/assets/check-dark.svg +0 -0
  20. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/assets/check.svg +0 -0
  21. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/assets/partial-dark.svg +0 -0
  22. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/assets/partial.svg +0 -0
  23. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/assets/repdf.ico +0 -0
  24. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/assets/repdf.png +0 -0
  25. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/core.py +0 -0
  26. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/entrypoint.py +0 -0
  27. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/floating_tools.py +0 -0
  28. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/icon_layout.py +0 -0
  29. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/images.py +0 -0
  30. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/message_dialogs.py +0 -0
  31. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/navigation.py +0 -0
  32. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/ocr.py +0 -0
  33. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/ocr_languages.py +0 -0
  34. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/ocr_models.py +0 -0
  35. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/packaging_smoke.py +0 -0
  36. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/page_view.py +0 -0
  37. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/pdf_annotations.py +0 -0
  38. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/pdf_navigation.py +0 -0
  39. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/preferences.py +0 -0
  40. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/preview.py +0 -0
  41. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/print_preview.py +0 -0
  42. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/printing.py +0 -0
  43. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/render_worker.py +0 -0
  44. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/renderer.py +0 -0
  45. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/saving.py +0 -0
  46. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/search.py +0 -0
  47. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/shortcut_hints.py +0 -0
  48. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/theme.py +0 -0
  49. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/toolbar.py +0 -0
  50. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/widgets.py +0 -0
  51. {repdf-0.1.3 → repdf-0.1.4}/src/repdf/workers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: repdf
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: RePDF (Read the PDF): a desktop PDF reader with printing, search, bookmarks, OCR and page rearrangement.
5
5
  Requires-Dist: onnxruntime>=1.31.0,<2
6
6
  Requires-Dist: pillow>=11.0,<13
@@ -76,7 +76,7 @@ repdf
76
76
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-extract-image-dark.png"><img src="docs/images/toolbar-extract-image.png" width="24" alt="擷取圖片圖示"></picture> | 擷取圖片 | 啟用後點選內嵌點陣圖片,再選擇位置另存為 PNG。 | — |
77
77
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-bookmarks-dark.png"><img src="docs/images/toolbar-bookmarks.png" width="24" alt="書籤圖示"></picture> | 書籤 | 在左側章節樹展開或收合書籤,點選章節即可跳頁。 | — |
78
78
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-annotations-dark.png"><img src="docs/images/toolbar-annotations.png" width="24" alt="註解圖示"></picture> | 註解 | 在左側列出註解,點選即可跳至對應頁面。 | — |
79
- | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-search-dark.png"><img src="docs/images/toolbar-search.png" width="24" alt="搜尋文字圖示"></picture> | 搜尋文字 | 在右側窗格搜尋文字,上方選檔案、下方選命中段落,單擊即可跳頁並高亮。 | Windows/Linux:<kbd>Ctrl</kbd>+<kbd>F</kbd>;macOS:<kbd>⌘</kbd>+<kbd>F</kbd> |
79
+ | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-search-dark.png"><img src="docs/images/toolbar-search.png" width="24" alt="搜尋文字圖示"></picture> | 搜尋文字 | 在右側窗格搜尋文字,上方以「檔名/筆數」表格選檔案,下方以「頁碼/段落」表格選命中項目,單擊即可跳頁並高亮。 | Windows/Linux:<kbd>Ctrl</kbd>+<kbd>F</kbd>;macOS:<kbd>⌘</kbd>+<kbd>F</kbd> |
80
80
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-text-markup-dark.png"><img src="docs/images/toolbar-text-markup.png" width="24" alt="文字畫線"></picture> | 文字畫線 | 拖曳選字畫線;下拉設定螢光筆、底線、刪除線、波浪線、顏色與粗細。 | — |
81
81
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-callout-dark.png"><img src="docs/images/toolbar-callout.png" width="24" alt="箭頭文字註解"></picture> | 文字註解 | 下拉選擇箭頭文字框或便利貼,點選頁面新增;雙擊可編輯文字。 | — |
82
82
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-drawing-dark.png"><img src="docs/images/toolbar-drawing.png" width="24" alt="繪圖註解"></picture> | 繪圖註解 | 下拉選擇直線、箭頭、矩形、橢圓或自由手繪;設定線條與填色後拖曳建立。 | — |
@@ -218,7 +218,7 @@ repdf
218
218
  1. 點「搜尋文字」或按 <kbd>Ctrl</kbd>+<kbd>F</kbd>(macOS:<kbd>⌘</kbd>+<kbd>F</kbd>),開啟右側窗格。
219
219
  2. 輸入搜尋內容,選擇「目前標籤頁」、「勾選的標籤頁」或「所有標籤頁」;同一列的 `.*`、`Aa` 與底線 `ab` 狀態按鈕分別切換「規則表達式」、「區分大小寫」與「僅限單字」,亮起表示啟用。
220
220
  3. 按 <kbd>Enter</kbd> 或「搜尋」執行;修改條件後再次執行才會更新結果。
221
- 4. 上方選取有命中的檔案,下方以交錯底色單行列出命中段落、原始頁碼與命中次數;內容過長時以 `...` 結尾,滑鼠停留可查看完整段落。
221
+ 4. 上方「檔案」表格列出檔名與命中段落筆數;選取檔案後,下方「命中項目」表格以「頁碼/段落」分欄顯示,段落採交錯底色單行呈現,命中次數保留在提示文字中;內容過長時以 `...` 結尾,滑鼠停留可查看完整段落。
222
222
  5. 單擊段落,切換到對應標籤與頁面,捲至命中位置;尚未載入的頁面會自動載入。命中預設以黃色螢光筆標示,選取段落以較深的同色系突出。
223
223
 
224
224
  - 預設搜尋目前標籤頁、不區分大小寫、不使用規則表達式;三種範圍互斥。
@@ -59,7 +59,7 @@ repdf
59
59
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-extract-image-dark.png"><img src="docs/images/toolbar-extract-image.png" width="24" alt="擷取圖片圖示"></picture> | 擷取圖片 | 啟用後點選內嵌點陣圖片,再選擇位置另存為 PNG。 | — |
60
60
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-bookmarks-dark.png"><img src="docs/images/toolbar-bookmarks.png" width="24" alt="書籤圖示"></picture> | 書籤 | 在左側章節樹展開或收合書籤,點選章節即可跳頁。 | — |
61
61
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-annotations-dark.png"><img src="docs/images/toolbar-annotations.png" width="24" alt="註解圖示"></picture> | 註解 | 在左側列出註解,點選即可跳至對應頁面。 | — |
62
- | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-search-dark.png"><img src="docs/images/toolbar-search.png" width="24" alt="搜尋文字圖示"></picture> | 搜尋文字 | 在右側窗格搜尋文字,上方選檔案、下方選命中段落,單擊即可跳頁並高亮。 | Windows/Linux:<kbd>Ctrl</kbd>+<kbd>F</kbd>;macOS:<kbd>⌘</kbd>+<kbd>F</kbd> |
62
+ | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-search-dark.png"><img src="docs/images/toolbar-search.png" width="24" alt="搜尋文字圖示"></picture> | 搜尋文字 | 在右側窗格搜尋文字,上方以「檔名/筆數」表格選檔案,下方以「頁碼/段落」表格選命中項目,單擊即可跳頁並高亮。 | Windows/Linux:<kbd>Ctrl</kbd>+<kbd>F</kbd>;macOS:<kbd>⌘</kbd>+<kbd>F</kbd> |
63
63
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-text-markup-dark.png"><img src="docs/images/toolbar-text-markup.png" width="24" alt="文字畫線"></picture> | 文字畫線 | 拖曳選字畫線;下拉設定螢光筆、底線、刪除線、波浪線、顏色與粗細。 | — |
64
64
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-callout-dark.png"><img src="docs/images/toolbar-callout.png" width="24" alt="箭頭文字註解"></picture> | 文字註解 | 下拉選擇箭頭文字框或便利貼,點選頁面新增;雙擊可編輯文字。 | — |
65
65
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-drawing-dark.png"><img src="docs/images/toolbar-drawing.png" width="24" alt="繪圖註解"></picture> | 繪圖註解 | 下拉選擇直線、箭頭、矩形、橢圓或自由手繪;設定線條與填色後拖曳建立。 | — |
@@ -201,7 +201,7 @@ repdf
201
201
  1. 點「搜尋文字」或按 <kbd>Ctrl</kbd>+<kbd>F</kbd>(macOS:<kbd>⌘</kbd>+<kbd>F</kbd>),開啟右側窗格。
202
202
  2. 輸入搜尋內容,選擇「目前標籤頁」、「勾選的標籤頁」或「所有標籤頁」;同一列的 `.*`、`Aa` 與底線 `ab` 狀態按鈕分別切換「規則表達式」、「區分大小寫」與「僅限單字」,亮起表示啟用。
203
203
  3. 按 <kbd>Enter</kbd> 或「搜尋」執行;修改條件後再次執行才會更新結果。
204
- 4. 上方選取有命中的檔案,下方以交錯底色單行列出命中段落、原始頁碼與命中次數;內容過長時以 `...` 結尾,滑鼠停留可查看完整段落。
204
+ 4. 上方「檔案」表格列出檔名與命中段落筆數;選取檔案後,下方「命中項目」表格以「頁碼/段落」分欄顯示,段落採交錯底色單行呈現,命中次數保留在提示文字中;內容過長時以 `...` 結尾,滑鼠停留可查看完整段落。
205
205
  5. 單擊段落,切換到對應標籤與頁面,捲至命中位置;尚未載入的頁面會自動載入。命中預設以黃色螢光筆標示,選取段落以較深的同色系突出。
206
206
 
207
207
  - 預設搜尋目前標籤頁、不區分大小寫、不使用規則表達式;三種範圍互斥。
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "repdf"
3
- version = "0.1.3"
3
+ version = "0.1.4"
4
4
  description = "RePDF (Read the PDF): a desktop PDF reader with printing, search, bookmarks, OCR and page rearrangement."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "repdf"
3
- version = "0.1.3"
3
+ version = "0.1.4"
4
4
  description = "RePDF (Read the PDF): a desktop PDF reader with printing, search, bookmarks, OCR and page rearrangement."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -229,13 +229,11 @@ def toolbar_icon(kind: str) -> QIcon:
229
229
  painter.drawLine(13, 18, 22, 9)
230
230
  painter.drawLine(20, 8, 23, 11)
231
231
  elif kind == "export":
232
- painter.drawPolyline(QPolygonF([QPointF(8, 16), QPointF(4, 16), QPointF(4, 3),
233
- QPointF(14, 3), QPointF(18, 7), QPointF(18, 10)]))
234
- painter.drawPolyline(QPolygonF([QPointF(14, 3), QPointF(14, 7), QPointF(18, 7)]))
235
- painter.drawLine(13, 11, 13, 20)
236
- painter.drawPolyline(QPolygonF([QPointF(9, 16), QPointF(13, 20), QPointF(17, 16)]))
237
- painter.drawPolyline(QPolygonF([QPointF(6, 20), QPointF(6, 22), QPointF(20, 22),
238
- QPointF(20, 20)]))
232
+ painter.drawPolygon(QPolygonF([QPointF(4, 2), QPointF(14, 2), QPointF(20, 8),
233
+ QPointF(20, 22), QPointF(4, 22)]))
234
+ painter.drawPolyline(QPolygonF([QPointF(14, 2), QPointF(14, 8), QPointF(20, 8)]))
235
+ painter.drawLine(12, 11, 12, 18)
236
+ painter.drawPolyline(QPolygonF([QPointF(8, 14), QPointF(12, 18), QPointF(16, 14)]))
239
237
  elif kind == "split":
240
238
  painter.drawRoundedRect(QRectF(2, 2, 8, 13), 1, 1)
241
239
  painter.drawRoundedRect(QRectF(14, 9, 8, 13), 1, 1)
@@ -5,8 +5,8 @@ from html import escape
5
5
  from PySide6.QtCore import QEvent, QObject, QSize, Qt, QTimer, Signal
6
6
  from PySide6.QtGui import QAction, QActionGroup, QColor, QIcon, QPainter, QPixmap
7
7
  from PySide6.QtWidgets import (
8
- QAbstractItemView, QColorDialog, QComboBox, QHBoxLayout, QLabel, QLayout, QLineEdit, QListView, QListWidget,
9
- QListWidgetItem, QMenu, QSplitter, QStyle, QStyledItemDelegate, QStyleOptionViewItem,
8
+ QAbstractItemView, QColorDialog, QComboBox, QGroupBox, QHeaderView, QHBoxLayout, QLabel, QLayout, QLineEdit,
9
+ QTreeWidget, QTreeWidgetItem, QMenu, QSplitter, QStyle, QStyledItemDelegate, QStyleOptionViewItem,
10
10
  QToolButton, QVBoxLayout, QWidget,
11
11
  )
12
12
 
@@ -26,7 +26,13 @@ class SearchStatus(QLabel):
26
26
  self.setToolTip('<qt>' + escape(text).replace('\n', '<br>') + '</qt>')
27
27
 
28
28
 
29
- class ParagraphDelegate(QStyledItemDelegate):
29
+ class ResultRowDelegate(QStyledItemDelegate):
30
+ def sizeHint(self, option, index):
31
+ hint = super().sizeHint(option, index)
32
+ return QSize(hint.width(), option.fontMetrics.height() + 4)
33
+
34
+
35
+ class ParagraphDelegate(ResultRowDelegate):
30
36
  """Keep complete result text in the model, but paint one elided line."""
31
37
 
32
38
  @staticmethod
@@ -49,7 +55,7 @@ class ParagraphDelegate(QStyledItemDelegate):
49
55
  style.drawControl(QStyle.ControlElement.CE_ItemViewItem, opt, painter, opt.widget)
50
56
 
51
57
  def sizeHint(self, option, index):
52
- return QSize(0, option.fontMetrics.height() + 10)
58
+ return QSize(0, option.fontMetrics.height() + 4)
53
59
 
54
60
 
55
61
  class SearchPanel(QWidget):
@@ -150,22 +156,48 @@ class SearchPanel(QWidget):
150
156
  status_row.addWidget(self.status, 1)
151
157
  layout.addLayout(status_row)
152
158
  self.results_splitter = QSplitter(Qt.Orientation.Vertical)
153
- self.files = QListWidget()
159
+ self.files = QTreeWidget()
154
160
  self.files.setAccessibleName(tr('有命中的檔案'))
155
- self.files.setMinimumSize(0, 0)
161
+ self.files.setHeaderLabels([tr('檔名'), tr('筆數')])
162
+ self.files.headerItem().setTextAlignment(1, Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
163
+ self.files.header().setStretchLastSection(False)
164
+ self.files.header().setSectionResizeMode(0, QHeaderView.ResizeMode.Stretch)
165
+ self.files.header().setSectionResizeMode(1, QHeaderView.ResizeMode.ResizeToContents)
156
166
  self.files.setTextElideMode(Qt.TextElideMode.ElideMiddle)
157
- self.files.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
158
- self.paragraphs = QListWidget()
167
+ self.files.setItemDelegate(ResultRowDelegate(self.files))
168
+ self.paragraphs = QTreeWidget()
159
169
  self.paragraphs.setAccessibleName(tr('命中段落'))
160
- self.paragraphs.setWordWrap(False)
170
+ self.paragraphs.setHeaderLabels([tr('頁碼'), tr('段落')])
171
+ self.paragraphs.headerItem().setTextAlignment(0, Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
172
+ self.paragraphs.header().setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents)
173
+ self.paragraphs.header().setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch)
174
+ self.paragraphs.setItemDelegate(ResultRowDelegate(self.paragraphs))
175
+ self.paragraphs.setItemDelegateForColumn(1, ParagraphDelegate(self.paragraphs))
161
176
  self.paragraphs.setAlternatingRowColors(True)
162
- self.paragraphs.setItemDelegate(ParagraphDelegate(self.paragraphs))
163
- self.paragraphs.setResizeMode(QListView.ResizeMode.Adjust)
164
- self.paragraphs.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel)
165
- self.paragraphs.setMinimumSize(0, 0)
166
- self.paragraphs.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
167
- self.results_splitter.addWidget(self.files)
168
- self.results_splitter.addWidget(self.paragraphs)
177
+ self.result_groups = []
178
+ for table, title in ((self.files, '檔案'), (self.paragraphs, '命中項目')):
179
+ table.setRootIsDecorated(False)
180
+ table.setItemsExpandable(False)
181
+ table.setUniformRowHeights(True)
182
+ table.setWordWrap(False)
183
+ table.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
184
+ table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
185
+ table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
186
+ table.setMinimumSize(0, 0)
187
+ table.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
188
+ table.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel)
189
+ table.header().setMinimumSectionSize(40)
190
+ table.header().setSectionsMovable(False)
191
+ header_font = table.header().font()
192
+ header_font.setBold(True)
193
+ table.header().setFont(header_font)
194
+ group = QGroupBox(tr(title))
195
+ group.setMinimumSize(0, 0)
196
+ group_layout = QVBoxLayout(group)
197
+ group_layout.setContentsMargins(6, 8, 6, 6)
198
+ group_layout.addWidget(table)
199
+ self.result_groups.append(group)
200
+ self.results_splitter.addWidget(group)
169
201
  self.results_splitter.setSizes([140, 260])
170
202
  layout.addWidget(self.results_splitter, 1)
171
203
  self.refresh_icons()
@@ -219,6 +251,10 @@ class SearchPanel(QWidget):
219
251
  self.highlight_color_action.setText(tr('命中標示顏色'))
220
252
  self.scope.setCurrentIndex(index)
221
253
  self.query.setPlaceholderText(tr('輸入文字或規則表達式'))
254
+ self.files.setHeaderLabels([tr('檔名'), tr('筆數')])
255
+ self.paragraphs.setHeaderLabels([tr('頁碼'), tr('段落')])
256
+ for group, title in zip(self.result_groups, ('檔案', '命中項目')):
257
+ group.setTitle(tr(title))
222
258
 
223
259
  def set_compact(self, compact):
224
260
  self.options_box.setVisible(not compact)
@@ -454,7 +490,7 @@ class SearchController(QObject):
454
490
  def _refresh_files(self):
455
491
  p = self.panel
456
492
  current = p.files.currentItem()
457
- selected_id = current.data(Qt.ItemDataRole.UserRole) if current else None
493
+ selected_id = current.data(0, Qt.ItemDataRole.UserRole) if current else None
458
494
  p.files.blockSignals(True)
459
495
  p.files.clear()
460
496
  for document_id in self.order:
@@ -464,43 +500,46 @@ class SearchController(QObject):
464
500
  if not paragraphs:
465
501
  continue
466
502
  doc = self.owner.documents[document_id]
467
- item = QListWidgetItem(tr('{p0} — {p1} 處/{p2} 段', p0=doc.source_path.name,
468
- p1=sum(p['count'] for p in paragraphs), p2=len(paragraphs)))
469
- item.setData(Qt.ItemDataRole.UserRole, document_id)
470
- item.setToolTip(str(doc.source_path))
471
- p.files.addItem(item)
503
+ item = QTreeWidgetItem([doc.source_path.name, str(len(paragraphs))])
504
+ item.setData(0, Qt.ItemDataRole.UserRole, document_id)
505
+ item.setTextAlignment(1, Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
506
+ item.setToolTip(0, str(doc.source_path))
507
+ item.setToolTip(1, tr('找到 {p0} 個段落、{p1} 處命中', p0=len(paragraphs), p1=sum(p['count'] for p in paragraphs)))
508
+ p.files.addTopLevelItem(item)
472
509
  if document_id == selected_id:
473
510
  p.files.setCurrentItem(item)
474
- if p.files.currentRow() < 0 and p.files.count():
475
- p.files.setCurrentRow(0)
511
+ if p.files.currentItem() is None and p.files.topLevelItemCount():
512
+ p.files.setCurrentItem(p.files.topLevelItem(0))
476
513
  p.files.blockSignals(False)
477
514
  self._show_paragraphs()
478
515
 
479
516
  def _show_paragraphs(self, *_args):
480
517
  p = self.panel
481
518
  selected = p.paragraphs.currentItem()
482
- previous = selected.data(Qt.ItemDataRole.UserRole) if selected else None
519
+ previous = selected.data(0, Qt.ItemDataRole.UserRole) if selected else None
483
520
  p.paragraphs.clear()
484
521
  file_item = p.files.currentItem()
485
522
  if file_item is None:
486
523
  return
487
- document_id = file_item.data(Qt.ItemDataRole.UserRole)
524
+ document_id = file_item.data(0, Qt.ItemDataRole.UserRole)
488
525
  doc = self.owner.documents.get(document_id)
489
526
  if doc is None:
490
527
  return
491
528
  for page in doc.page_order:
492
529
  for result in self.results.get(document_id, {}).get(page, []):
493
530
  key = (document_id, page, result['paragraph_id'])
494
- item = QListWidgetItem(tr('第 {p0} 頁 · {p1} 處命中 · {p2}',
495
- p0=page + 1, p1=result['count'], p2=result['text']))
496
- item.setData(Qt.ItemDataRole.UserRole, key)
497
- item.setToolTip('<qt>' + escape(result['text']).replace('\n', '<br>') + '</qt>')
498
- p.paragraphs.addItem(item)
531
+ item = QTreeWidgetItem([str(page + 1), result['text']])
532
+ item.setTextAlignment(0, Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
533
+ item.setData(0, Qt.ItemDataRole.UserRole, key)
534
+ tooltip = '<qt>' + escape(tr('第 {p0} 頁 · {p1} 處命中 · {p2}', p0=page + 1, p1=result['count'], p2=result['text'])).replace('\n', '<br>') + '</qt>'
535
+ item.setToolTip(0, tooltip)
536
+ item.setToolTip(1, tooltip)
537
+ p.paragraphs.addTopLevelItem(item)
499
538
  if key == previous:
500
539
  p.paragraphs.setCurrentItem(item)
501
540
 
502
- def _activate_item(self, item):
503
- document_id, page, paragraph_id = item.data(Qt.ItemDataRole.UserRole)
541
+ def _activate_item(self, item, _column=0):
542
+ document_id, page, paragraph_id = item.data(0, Qt.ItemDataRole.UserRole)
504
543
  doc = self.owner.documents.get(document_id)
505
544
  if doc is None or not doc.ready:
506
545
  return
@@ -5,6 +5,11 @@ from string import Formatter
5
5
 
6
6
  LANGUAGE = "zh"
7
7
  ENGLISH = {
8
+ '檔案': 'Files',
9
+ '檔名': 'Filename',
10
+ '筆數': 'Count',
11
+ '命中項目': 'Matches',
12
+ '段落': 'Paragraph',
8
13
  '儲存': 'Save',
9
14
  '取消': 'Cancel',
10
15
  '有尚未儲存的變更': 'You have unsaved changes',
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes