|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2009 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the bookmarks menu. |
|
8 """ |
|
9 |
|
10 from PyQt6.QtCore import pyqtSignal, Qt, QUrl |
|
11 from PyQt6.QtGui import QCursor |
|
12 from PyQt6.QtWidgets import QMenu |
|
13 |
|
14 from EricWidgets.EricModelMenu import EricModelMenu |
|
15 |
|
16 from .BookmarksModel import BookmarksModel |
|
17 from .BookmarkNode import BookmarkNode |
|
18 |
|
19 |
|
20 class BookmarksMenu(EricModelMenu): |
|
21 """ |
|
22 Class implementing the bookmarks menu base class. |
|
23 |
|
24 @signal openUrl(QUrl, str) emitted to open a URL with the given title in |
|
25 the current tab |
|
26 @signal newTab(QUrl, str) emitted to open a URL with the given title in a |
|
27 new tab |
|
28 @signal newWindow(QUrl, str) emitted to open a URL with the given title in |
|
29 a new window |
|
30 """ |
|
31 openUrl = pyqtSignal(QUrl, str) |
|
32 newTab = pyqtSignal(QUrl, str) |
|
33 newWindow = pyqtSignal(QUrl, str) |
|
34 |
|
35 def __init__(self, parent=None): |
|
36 """ |
|
37 Constructor |
|
38 |
|
39 @param parent reference to the parent widget (QWidget) |
|
40 """ |
|
41 EricModelMenu.__init__(self, parent) |
|
42 |
|
43 self.activated.connect(self.__activated) |
|
44 self.setStatusBarTextRole(BookmarksModel.UrlStringRole) |
|
45 self.setSeparatorRole(BookmarksModel.SeparatorRole) |
|
46 |
|
47 self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) |
|
48 self.customContextMenuRequested.connect(self.__contextMenuRequested) |
|
49 |
|
50 def createBaseMenu(self): |
|
51 """ |
|
52 Public method to get the menu that is used to populate sub menu's. |
|
53 |
|
54 @return reference to the menu (BookmarksMenu) |
|
55 """ |
|
56 menu = BookmarksMenu(self) |
|
57 menu.openUrl.connect(self.openUrl) |
|
58 menu.newTab.connect(self.newTab) |
|
59 menu.newWindow.connect(self.newWindow) |
|
60 return menu |
|
61 |
|
62 def __updateVisitCount(self, idx): |
|
63 """ |
|
64 Private method to update the visit count of a bookmark. |
|
65 |
|
66 @param idx index of the bookmark item (QModelIndex) |
|
67 """ |
|
68 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
|
69 |
|
70 bookmarkNode = self.model().node(idx) |
|
71 manager = WebBrowserWindow.bookmarksManager() |
|
72 manager.incVisitCount(bookmarkNode) |
|
73 |
|
74 def __activated(self, idx): |
|
75 """ |
|
76 Private slot handling the activated signal. |
|
77 |
|
78 @param idx index of the activated item (QModelIndex) |
|
79 """ |
|
80 if self._keyboardModifiers & Qt.KeyboardModifier.ControlModifier: |
|
81 self.newTab.emit( |
|
82 idx.data(BookmarksModel.UrlRole), |
|
83 idx.data(Qt.ItemDataRole.DisplayRole)) |
|
84 elif self._keyboardModifiers & Qt.KeyboardModifier.ShiftModifier: |
|
85 self.newWindow.emit( |
|
86 idx.data(BookmarksModel.UrlRole), |
|
87 idx.data(Qt.ItemDataRole.DisplayRole)) |
|
88 else: |
|
89 self.openUrl.emit( |
|
90 idx.data(BookmarksModel.UrlRole), |
|
91 idx.data(Qt.ItemDataRole.DisplayRole)) |
|
92 self.__updateVisitCount(idx) |
|
93 |
|
94 def postPopulated(self): |
|
95 """ |
|
96 Public method to add any actions after the tree. |
|
97 """ |
|
98 if self.isEmpty(): |
|
99 return |
|
100 |
|
101 parent = self.rootIndex() |
|
102 |
|
103 hasBookmarks = False |
|
104 |
|
105 for i in range(parent.model().rowCount(parent)): |
|
106 child = parent.model().index(i, 0, parent) |
|
107 |
|
108 if child.data(BookmarksModel.TypeRole) == BookmarkNode.Bookmark: |
|
109 hasBookmarks = True |
|
110 break |
|
111 |
|
112 if not hasBookmarks: |
|
113 return |
|
114 |
|
115 self.addSeparator() |
|
116 act = self.addAction(self.tr("Open all in Tabs")) |
|
117 act.triggered.connect(lambda: self.openAll(act)) |
|
118 |
|
119 def openAll(self, act): |
|
120 """ |
|
121 Public slot to open all the menu's items. |
|
122 |
|
123 @param act reference to the action object |
|
124 @type QAction |
|
125 """ |
|
126 menu = act.parent() |
|
127 if menu is None: |
|
128 return |
|
129 |
|
130 parent = menu.rootIndex() |
|
131 if not parent.isValid(): |
|
132 return |
|
133 |
|
134 for i in range(parent.model().rowCount(parent)): |
|
135 child = parent.model().index(i, 0, parent) |
|
136 |
|
137 if child.data(BookmarksModel.TypeRole) != BookmarkNode.Bookmark: |
|
138 continue |
|
139 |
|
140 if i == 0: |
|
141 self.openUrl.emit( |
|
142 child.data(BookmarksModel.UrlRole), |
|
143 child.data(Qt.ItemDataRole.DisplayRole)) |
|
144 else: |
|
145 self.newTab.emit( |
|
146 child.data(BookmarksModel.UrlRole), |
|
147 child.data(Qt.ItemDataRole.DisplayRole)) |
|
148 self.__updateVisitCount(child) |
|
149 |
|
150 def __contextMenuRequested(self, pos): |
|
151 """ |
|
152 Private slot to handle the context menu request. |
|
153 |
|
154 @param pos position the context menu shall be shown (QPoint) |
|
155 """ |
|
156 act = self.actionAt(pos) |
|
157 |
|
158 if ( |
|
159 act is not None and |
|
160 act not in self.menuActions and |
|
161 self.index(act).isValid() |
|
162 ): |
|
163 menu = QMenu() |
|
164 v = act.data() |
|
165 |
|
166 act2 = menu.addAction(self.tr("Open")) |
|
167 act2.setData(v) |
|
168 act2.triggered.connect( |
|
169 lambda: self.__openBookmark(act2)) |
|
170 act2 = menu.addAction(self.tr("Open in New Tab\tCtrl+LMB")) |
|
171 act2.setData(v) |
|
172 act2.triggered.connect( |
|
173 lambda: self.__openBookmarkInNewTab(act2)) |
|
174 act2 = menu.addAction(self.tr("Open in New Window")) |
|
175 act2.setData(v) |
|
176 act2.triggered.connect( |
|
177 lambda: self.__openBookmarkInNewWindow(act2)) |
|
178 act2 = menu.addAction(self.tr("Open in New Private Window")) |
|
179 act2.setData(v) |
|
180 act2.triggered.connect( |
|
181 lambda: self.__openBookmarkInPrivateWindow(act2)) |
|
182 menu.addSeparator() |
|
183 |
|
184 act2 = menu.addAction(self.tr("Remove")) |
|
185 act2.setData(v) |
|
186 act2.triggered.connect(lambda: self.__removeBookmark(act2)) |
|
187 menu.addSeparator() |
|
188 |
|
189 act2 = menu.addAction(self.tr("Properties...")) |
|
190 act2.setData(v) |
|
191 act2.triggered.connect(lambda: self.__edit(act2)) |
|
192 |
|
193 execAct = menu.exec(QCursor.pos()) |
|
194 if execAct is not None: |
|
195 self.close() |
|
196 parent = self.parent() |
|
197 while parent is not None and isinstance(parent, QMenu): |
|
198 parent.close() |
|
199 parent = parent.parent() |
|
200 |
|
201 def __openBookmark(self, act): |
|
202 """ |
|
203 Private slot to open a bookmark in the current browser tab. |
|
204 |
|
205 @param act reference to the triggering action |
|
206 @type QAction |
|
207 """ |
|
208 idx = self.index(act) |
|
209 |
|
210 self.openUrl.emit( |
|
211 idx.data(BookmarksModel.UrlRole), |
|
212 idx.data(Qt.ItemDataRole.DisplayRole)) |
|
213 self.__updateVisitCount(idx) |
|
214 |
|
215 def __openBookmarkInNewTab(self, act): |
|
216 """ |
|
217 Private slot to open a bookmark in a new browser tab. |
|
218 |
|
219 @param act reference to the triggering action |
|
220 @type QAction |
|
221 """ |
|
222 idx = self.index(act) |
|
223 |
|
224 self.newTab.emit( |
|
225 idx.data(BookmarksModel.UrlRole), |
|
226 idx.data(Qt.ItemDataRole.DisplayRole)) |
|
227 self.__updateVisitCount(idx) |
|
228 |
|
229 def __openBookmarkInNewWindow(self, act): |
|
230 """ |
|
231 Private slot to open a bookmark in a new window. |
|
232 |
|
233 @param act reference to the triggering action |
|
234 @type QAction |
|
235 """ |
|
236 idx = self.index(act) |
|
237 url = idx.data(BookmarksModel.UrlRole) |
|
238 |
|
239 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
|
240 WebBrowserWindow.mainWindow().newWindow(url) |
|
241 self.__updateVisitCount(idx) |
|
242 |
|
243 def __openBookmarkInPrivateWindow(self, act): |
|
244 """ |
|
245 Private slot to open a bookmark in a new private window. |
|
246 |
|
247 @param act reference to the triggering action |
|
248 @type QAction |
|
249 """ |
|
250 idx = self.index(act) |
|
251 url = idx.data(BookmarksModel.UrlRole) |
|
252 |
|
253 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
|
254 WebBrowserWindow.mainWindow().newPrivateWindow(url) |
|
255 self.__updateVisitCount(idx) |
|
256 |
|
257 def __removeBookmark(self, act): |
|
258 """ |
|
259 Private slot to remove a bookmark. |
|
260 |
|
261 @param act reference to the triggering action |
|
262 @type QAction |
|
263 """ |
|
264 idx = self.index(act) |
|
265 self.removeEntry(idx) |
|
266 |
|
267 def __edit(self, act): |
|
268 """ |
|
269 Private slot to edit a bookmarks properties. |
|
270 |
|
271 @param act reference to the triggering action |
|
272 @type QAction |
|
273 """ |
|
274 from .BookmarkPropertiesDialog import BookmarkPropertiesDialog |
|
275 |
|
276 idx = self.index(act) |
|
277 node = self.model().node(idx) |
|
278 dlg = BookmarkPropertiesDialog(node) |
|
279 dlg.exec() |
|
280 |
|
281 ############################################################################## |
|
282 |
|
283 |
|
284 class BookmarksMenuBarMenu(BookmarksMenu): |
|
285 """ |
|
286 Class implementing a dynamically populated menu for bookmarks. |
|
287 |
|
288 @signal openUrl(QUrl, str) emitted to open a URL with the given title in |
|
289 the current tab |
|
290 """ |
|
291 openUrl = pyqtSignal(QUrl, str) |
|
292 |
|
293 def __init__(self, parent=None): |
|
294 """ |
|
295 Constructor |
|
296 |
|
297 @param parent reference to the parent widget (QWidget) |
|
298 """ |
|
299 BookmarksMenu.__init__(self, parent) |
|
300 |
|
301 self.__initialActions = [] |
|
302 |
|
303 def prePopulated(self): |
|
304 """ |
|
305 Public method to add any actions before the tree. |
|
306 |
|
307 @return flag indicating if any actions were added (boolean) |
|
308 """ |
|
309 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
|
310 |
|
311 manager = WebBrowserWindow.bookmarksManager() |
|
312 self.setModel(manager.bookmarksModel()) |
|
313 self.setRootIndex(manager.bookmarksModel().nodeIndex(manager.menu())) |
|
314 |
|
315 # initial actions |
|
316 for act in self.__initialActions: |
|
317 if act == "--SEPARATOR--": |
|
318 self.addSeparator() |
|
319 else: |
|
320 self.addAction(act) |
|
321 if len(self.__initialActions) != 0: |
|
322 self.addSeparator() |
|
323 |
|
324 self.createMenu( |
|
325 manager.bookmarksModel().nodeIndex(manager.toolbar()), |
|
326 1, self) |
|
327 return True |
|
328 |
|
329 def postPopulated(self): |
|
330 """ |
|
331 Public method to add any actions after the tree. |
|
332 """ |
|
333 if self.isEmpty(): |
|
334 return |
|
335 |
|
336 parent = self.rootIndex() |
|
337 |
|
338 hasBookmarks = False |
|
339 |
|
340 for i in range(parent.model().rowCount(parent)): |
|
341 child = parent.model().index(i, 0, parent) |
|
342 |
|
343 if child.data(BookmarksModel.TypeRole) == BookmarkNode.Bookmark: |
|
344 hasBookmarks = True |
|
345 break |
|
346 |
|
347 if not hasBookmarks: |
|
348 return |
|
349 |
|
350 self.addSeparator() |
|
351 act_1 = self.addAction(self.tr("Default Home Page")) |
|
352 act_1.setData("eric:home") |
|
353 act_1.triggered.connect( |
|
354 lambda: self.__defaultBookmarkTriggered(act_1)) |
|
355 act_2 = self.addAction(self.tr("Speed Dial")) |
|
356 act_2.setData("eric:speeddial") |
|
357 act_2.triggered.connect( |
|
358 lambda: self.__defaultBookmarkTriggered(act_2)) |
|
359 self.addSeparator() |
|
360 act_3 = self.addAction(self.tr("Open all in Tabs")) |
|
361 act_3.triggered.connect(lambda: self.openAll(act_3)) |
|
362 |
|
363 def setInitialActions(self, actions): |
|
364 """ |
|
365 Public method to set the list of actions that should appear first in |
|
366 the menu. |
|
367 |
|
368 @param actions list of initial actions (list of QAction) |
|
369 """ |
|
370 self.__initialActions = actions[:] |
|
371 for act in self.__initialActions: |
|
372 self.addAction(act) |
|
373 |
|
374 def __defaultBookmarkTriggered(self, act): |
|
375 """ |
|
376 Private slot handling the default bookmark menu entries. |
|
377 |
|
378 @param act reference to the action object |
|
379 @type QAction |
|
380 """ |
|
381 urlStr = act.data() |
|
382 if urlStr.startswith("eric:"): |
|
383 self.openUrl.emit(QUrl(urlStr), "") |