Skip to content

Commit c9e9158

Browse files
authored
add navigable tree view
1 parent 302b45a commit c9e9158

File tree

1 file changed

+94
-21
lines changed

1 file changed

+94
-21
lines changed

pyqt6_pdf_viewer.py

Lines changed: 94 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,121 @@
1-
from PyQt6.QtCore import QUrl, Qt
2-
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QLineEdit, QFileDialog, QPushButton
3-
from PyQt6.QtGui import QAction
1+
from PyQt6.QtCore import QUrl, Qt, QDir, QFileInfo
2+
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QLineEdit, QFileDialog, QPushButton, QHBoxLayout, QTreeView, QSplitter, QLabel, QSizePolicy
3+
from PyQt6.QtGui import QAction, QStandardItemModel, QStandardItem, QIcon
44
from PyQt6.QtWebEngineWidgets import QWebEngineView
55
from PyQt6.QtWebEngineCore import QWebEnginePage
6+
import os
7+
8+
class PDFFileSystemModel(QStandardItemModel):
9+
def __init__(self, parent=None):
10+
super().__init__(parent)
11+
self.setHorizontalHeaderLabels(["PDF Files and Folders"])
12+
self.root_path = os.path.dirname(os.path.abspath(__file__))
13+
self.current_path = self.root_path
14+
self.populate_model(self.invisibleRootItem(), self.current_path)
15+
16+
def populate_model(self, parent_item, directory_path):
17+
parent_item.removeRows(0, parent_item.rowCount())
18+
directory = QDir(directory_path)
19+
up_item = QStandardItem("")
20+
up_item.setData(os.path.dirname(directory_path), Qt.ItemDataRole.UserRole)
21+
up_item.setIcon(QIcon.fromTheme("go-up"))
22+
parent_item.appendRow(up_item)
23+
directories = directory.entryInfoList(QDir.Filter.Dirs | QDir.Filter.NoDotAndDotDot, QDir.SortFlag.Name)
24+
for dir_info in directories:
25+
dir_item = QStandardItem(dir_info.fileName())
26+
dir_item.setData(dir_info.filePath(), Qt.ItemDataRole.UserRole)
27+
dir_item.setIcon(QIcon.fromTheme("folder"))
28+
parent_item.appendRow(dir_item)
29+
placeholder = QStandardItem("Loading...")
30+
dir_item.appendRow(placeholder)
31+
pdf_files = directory.entryInfoList(["*.pdf"], QDir.Filter.Files, QDir.SortFlag.Name)
32+
for file_info in pdf_files:
33+
file_item = QStandardItem(file_info.fileName())
34+
file_item.setData(file_info.filePath(), Qt.ItemDataRole.UserRole)
35+
file_item.setIcon(QIcon.fromTheme("application-pdf"))
36+
parent_item.appendRow(file_item)
37+
38+
def navigate_to(self, path):
39+
self.current_path = path
40+
self.populate_model(self.invisibleRootItem(), path)
641

742
class MainWindow(QMainWindow):
843
def __init__(self):
9-
super(QMainWindow, self).__init__()
10-
44+
super().__init__()
1145
self.setWindowTitle("PDF Viewer")
12-
self.setGeometry(0, 28, 1000, 750)
13-
46+
self.setGeometry(0, 28, 1200, 750)
1447
self.central_widget = QWidget()
1548
self.setCentralWidget(self.central_widget)
16-
17-
self.layout = QVBoxLayout()
18-
self.central_widget.setLayout(self.layout)
19-
49+
self.main_layout = QVBoxLayout(self.central_widget)
50+
self.tree_model = PDFFileSystemModel()
51+
self.path_label = QLabel()
52+
self.path_label.setText(self.tree_model.current_path)
53+
self.path_label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
54+
self.main_layout.addWidget(self.path_label)
55+
self.splitter = QSplitter(Qt.Orientation.Horizontal)
56+
self.main_layout.addWidget(self.splitter)
57+
self.nav_widget = QWidget()
58+
self.nav_layout = QVBoxLayout(self.nav_widget)
59+
self.tree_view = QTreeView()
60+
self.tree_view.setModel(self.tree_model)
61+
self.tree_view.setHeaderHidden(True)
62+
self.tree_view.clicked.connect(self.on_tree_clicked)
63+
self.tree_view.expanded.connect(self.on_tree_expanded)
64+
self.nav_layout.addWidget(self.tree_view)
65+
self.pdf_widget = QWidget()
66+
self.pdf_layout = QVBoxLayout(self.pdf_widget)
2067
self.webView = QWebEngineView()
2168
self.webView.settings().setAttribute(self.webView.settings().WebAttribute.PluginsEnabled, True)
2269
self.webView.settings().setAttribute(self.webView.settings().WebAttribute.PdfViewerEnabled, True)
23-
self.layout.addWidget(self.webView)
24-
25-
self.search_input = QLineEdit(self)
70+
self.pdf_layout.addWidget(self.webView)
71+
self.search_input = QLineEdit()
2672
self.search_input.setPlaceholderText("Enter text to search...")
2773
self.search_input.returnPressed.connect(lambda: self.search_text(self.search_input.text()))
28-
self.layout.addWidget(self.search_input)
29-
74+
self.pdf_layout.addWidget(self.search_input)
75+
self.splitter.addWidget(self.nav_widget)
76+
self.splitter.addWidget(self.pdf_widget)
77+
self.splitter.setSizes([250, 750])
3078
self.create_file_menu()
31-
79+
80+
def on_tree_clicked(self, index):
81+
item = self.tree_model.itemFromIndex(index)
82+
file_path = item.data(Qt.ItemDataRole.UserRole)
83+
if item.text() == "":
84+
self.tree_model.navigate_to(file_path)
85+
self.path_label.setText(file_path)
86+
return
87+
if os.path.isdir(file_path):
88+
self.tree_model.navigate_to(file_path)
89+
self.path_label.setText(file_path)
90+
return
91+
if file_path and file_path.lower().endswith('.pdf'):
92+
self.path_label.setText(file_path)
93+
pdf_url = QUrl.fromLocalFile(file_path)
94+
pdf_url.setFragment("zoom=page-width")
95+
self.webView.setUrl(pdf_url)
96+
97+
def on_tree_expanded(self, index):
98+
item = self.tree_model.itemFromIndex(index)
99+
file_path = item.data(Qt.ItemDataRole.UserRole)
100+
if item.rowCount() == 1 and item.child(0).text() == "Loading...":
101+
item.removeRow(0)
102+
self.tree_model.populate_model(item, file_path)
103+
32104
def create_file_menu(self):
33105
menubar = self.menuBar()
34106
file_menu = menubar.addMenu('Choose PDF')
35-
36107
open_action = QAction('Open', self)
37108
open_action.triggered.connect(self.open_file_dialog)
38109
file_menu.addAction(open_action)
39-
110+
40111
def open_file_dialog(self):
41112
file_dialog = QFileDialog()
42113
filename, _ = file_dialog.getOpenFileName(self, "Open PDF", "", "PDF Files (*.pdf)")
43114
if filename:
44-
self.webView.setUrl(QUrl.fromLocalFile(filename))
45-
115+
pdf_url = QUrl.fromLocalFile(filename)
116+
pdf_url.setFragment("zoom=page-width")
117+
self.webView.setUrl(pdf_url)
118+
46119
def search_text(self, text):
47120
flag = QWebEnginePage.FindFlag.FindCaseSensitively
48121
if text:

0 commit comments

Comments
 (0)