|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2010 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the central widget showing the web pages. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals |
|
11 |
|
12 import os |
|
13 |
|
14 from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QUrl, QDir, QFile, \ |
|
15 QFileDevice, QTemporaryFile |
|
16 from PyQt5.QtGui import QIcon, QPixmap, QPainter |
|
17 from PyQt5.QtWidgets import QWidget, QHBoxLayout, QMenu, QToolButton, \ |
|
18 QDialog, QApplication |
|
19 from PyQt5.QtPrintSupport import QPrinter, QPrintDialog, QAbstractPrintDialog |
|
20 |
|
21 from E5Gui.E5TabWidget import E5TabWidget |
|
22 from E5Gui import E5MessageBox |
|
23 from E5Gui.E5Application import e5App |
|
24 |
|
25 from .WebBrowserView import WebBrowserView |
|
26 from .WebBrowserPage import WebBrowserPage |
|
27 from .Tools import WebBrowserTools |
|
28 from .Tools import FilePrinter |
|
29 from . import WebInspector |
|
30 |
|
31 import UI.PixmapCache |
|
32 |
|
33 import Utilities |
|
34 import Preferences |
|
35 import Globals |
|
36 from Globals import qVersionTuple |
|
37 |
|
38 from eric6config import getConfig |
|
39 |
|
40 |
|
41 class WebBrowserTabWidget(E5TabWidget): |
|
42 """ |
|
43 Class implementing the central widget showing the web pages. |
|
44 |
|
45 @signal sourceChanged(WebBrowserView, QUrl) emitted after the URL of a |
|
46 browser has changed |
|
47 @signal currentUrlChanged(QUrl) emitted after the URL of the current |
|
48 browser has changed |
|
49 @signal titleChanged(WebBrowserView, str) emitted after the title of a |
|
50 browser has changed |
|
51 @signal showMessage(str) emitted to show a message in the main window |
|
52 status bar |
|
53 @signal browserOpened(QWidget) emitted after a new browser was created |
|
54 @signal browserClosed(QWidget) emitted after a browser was closed |
|
55 @signal browserZoomValueChanged(int) emitted to signal a change of the |
|
56 current browser's zoom level |
|
57 """ |
|
58 sourceChanged = pyqtSignal(WebBrowserView, QUrl) |
|
59 currentUrlChanged = pyqtSignal(QUrl) |
|
60 titleChanged = pyqtSignal(WebBrowserView, str) |
|
61 showMessage = pyqtSignal(str) |
|
62 browserOpened = pyqtSignal(QWidget) |
|
63 browserClosed = pyqtSignal(QWidget) |
|
64 browserZoomValueChanged = pyqtSignal(int) |
|
65 |
|
66 def __init__(self, parent): |
|
67 """ |
|
68 Constructor |
|
69 |
|
70 @param parent reference to the parent widget (QWidget) |
|
71 """ |
|
72 super(WebBrowserTabWidget, self).__init__(parent, dnd=True) |
|
73 |
|
74 from .WebBrowserTabBar import WebBrowserTabBar |
|
75 self.__tabBar = WebBrowserTabBar(self) |
|
76 self.setCustomTabBar(True, self.__tabBar) |
|
77 |
|
78 self.__mainWindow = parent |
|
79 |
|
80 self.setUsesScrollButtons(True) |
|
81 self.setDocumentMode(True) |
|
82 self.setElideMode(Qt.ElideNone) |
|
83 |
|
84 from .ClosedTabsManager import ClosedTabsManager |
|
85 self.__closedTabsManager = ClosedTabsManager(self) |
|
86 self.__closedTabsManager.closedTabAvailable.connect( |
|
87 self.__closedTabAvailable) |
|
88 |
|
89 from .UrlBar.StackedUrlBar import StackedUrlBar |
|
90 self.__stackedUrlBar = StackedUrlBar(self) |
|
91 self.__tabBar.tabMoved.connect(self.__stackedUrlBar.moveBar) |
|
92 |
|
93 self.__tabContextMenuIndex = -1 |
|
94 self.currentChanged[int].connect(self.__currentChanged) |
|
95 self.setTabContextMenuPolicy(Qt.CustomContextMenu) |
|
96 self.customTabContextMenuRequested.connect(self.__showContextMenu) |
|
97 |
|
98 self.__rightCornerWidget = QWidget(self) |
|
99 self.__rightCornerWidgetLayout = QHBoxLayout(self.__rightCornerWidget) |
|
100 self.__rightCornerWidgetLayout.setContentsMargins(0, 0, 0, 0) |
|
101 self.__rightCornerWidgetLayout.setSpacing(0) |
|
102 |
|
103 self.__navigationMenu = QMenu(self) |
|
104 self.__navigationMenu.aboutToShow.connect(self.__showNavigationMenu) |
|
105 self.__navigationMenu.triggered.connect(self.__navigationMenuTriggered) |
|
106 |
|
107 self.__navigationButton = QToolButton(self) |
|
108 self.__navigationButton.setIcon( |
|
109 UI.PixmapCache.getIcon("1downarrow.png")) |
|
110 self.__navigationButton.setToolTip( |
|
111 self.tr("Show a navigation menu")) |
|
112 self.__navigationButton.setPopupMode(QToolButton.InstantPopup) |
|
113 self.__navigationButton.setMenu(self.__navigationMenu) |
|
114 self.__navigationButton.setEnabled(False) |
|
115 self.__rightCornerWidgetLayout.addWidget(self.__navigationButton) |
|
116 |
|
117 self.__closedTabsMenu = QMenu(self) |
|
118 self.__closedTabsMenu.aboutToShow.connect( |
|
119 self.__aboutToShowClosedTabsMenu) |
|
120 |
|
121 self.__closedTabsButton = QToolButton(self) |
|
122 self.__closedTabsButton.setIcon(UI.PixmapCache.getIcon("trash.png")) |
|
123 self.__closedTabsButton.setToolTip( |
|
124 self.tr("Show a navigation menu for closed tabs")) |
|
125 self.__closedTabsButton.setPopupMode(QToolButton.InstantPopup) |
|
126 self.__closedTabsButton.setMenu(self.__closedTabsMenu) |
|
127 self.__closedTabsButton.setEnabled(False) |
|
128 self.__rightCornerWidgetLayout.addWidget(self.__closedTabsButton) |
|
129 |
|
130 self.__closeButton = QToolButton(self) |
|
131 self.__closeButton.setIcon(UI.PixmapCache.getIcon("close.png")) |
|
132 self.__closeButton.setToolTip( |
|
133 self.tr("Close the current web browser")) |
|
134 self.__closeButton.setEnabled(False) |
|
135 self.__closeButton.clicked.connect(self.closeBrowser) |
|
136 self.__rightCornerWidgetLayout.addWidget(self.__closeButton) |
|
137 if Preferences.getUI("SingleCloseButton") or \ |
|
138 not hasattr(self, 'setTabsClosable'): |
|
139 self.__closeButton.show() |
|
140 else: |
|
141 self.setTabsClosable(True) |
|
142 self.tabCloseRequested.connect(self.closeBrowserAt) |
|
143 self.__closeButton.hide() |
|
144 |
|
145 self.setCornerWidget(self.__rightCornerWidget, Qt.TopRightCorner) |
|
146 |
|
147 self.__newTabButton = QToolButton(self) |
|
148 self.__newTabButton.setIcon(UI.PixmapCache.getIcon("plus.png")) |
|
149 self.__newTabButton.setToolTip( |
|
150 self.tr("Open a new web browser tab")) |
|
151 self.setCornerWidget(self.__newTabButton, Qt.TopLeftCorner) |
|
152 self.__newTabButton.clicked.connect(self.__newBrowser) |
|
153 |
|
154 self.__initTabContextMenu() |
|
155 |
|
156 self.__historyCompleter = None |
|
157 |
|
158 self.__pdfPrinter = None |
|
159 |
|
160 def __initTabContextMenu(self): |
|
161 """ |
|
162 Private method to create the tab context menu. |
|
163 """ |
|
164 self.__tabContextMenu = QMenu(self) |
|
165 self.tabContextNewAct = self.__tabContextMenu.addAction( |
|
166 UI.PixmapCache.getIcon("tabNew.png"), |
|
167 self.tr('New Tab'), self.newBrowser) |
|
168 self.__tabContextMenu.addSeparator() |
|
169 self.leftMenuAct = self.__tabContextMenu.addAction( |
|
170 UI.PixmapCache.getIcon("1leftarrow.png"), |
|
171 self.tr('Move Left'), self.__tabContextMenuMoveLeft) |
|
172 self.rightMenuAct = self.__tabContextMenu.addAction( |
|
173 UI.PixmapCache.getIcon("1rightarrow.png"), |
|
174 self.tr('Move Right'), self.__tabContextMenuMoveRight) |
|
175 self.__tabContextMenu.addSeparator() |
|
176 self.tabContextCloneAct = self.__tabContextMenu.addAction( |
|
177 self.tr("Duplicate Page"), self.__tabContextMenuClone) |
|
178 self.__tabContextMenu.addSeparator() |
|
179 self.tabContextCloseAct = self.__tabContextMenu.addAction( |
|
180 UI.PixmapCache.getIcon("tabClose.png"), |
|
181 self.tr('Close'), self.__tabContextMenuClose) |
|
182 self.tabContextCloseOthersAct = self.__tabContextMenu.addAction( |
|
183 UI.PixmapCache.getIcon("tabCloseOther.png"), |
|
184 self.tr("Close Others"), self.__tabContextMenuCloseOthers) |
|
185 self.__tabContextMenu.addAction( |
|
186 self.tr('Close All'), self.closeAllBrowsers) |
|
187 self.__tabContextMenu.addSeparator() |
|
188 if qVersionTuple() >= (5, 8, 0) or ( |
|
189 not Globals.isWindowsPlatform() and qVersionTuple() < (5, 7, 0)): |
|
190 self.__tabContextMenu.addAction( |
|
191 UI.PixmapCache.getIcon("printPreview.png"), |
|
192 self.tr('Print Preview'), self.__tabContextMenuPrintPreview) |
|
193 if qVersionTuple() >= (5, 8, 0) or ( |
|
194 not Globals.isWindowsPlatform() or qVersionTuple() >= (5, 7, 0)): |
|
195 self.__tabContextMenu.addAction( |
|
196 UI.PixmapCache.getIcon("print.png"), |
|
197 self.tr('Print'), self.__tabContextMenuPrint) |
|
198 if Globals.isLinuxPlatform() or qVersionTuple() >= (5, 7, 0): |
|
199 self.__tabContextMenu.addAction( |
|
200 UI.PixmapCache.getIcon("printPdf.png"), |
|
201 self.tr('Print as PDF'), self.__tabContextMenuPrintPdf) |
|
202 self.__tabContextMenu.addSeparator() |
|
203 if hasattr(WebBrowserPage, "isAudioMuted"): |
|
204 self.__audioAct = self.__tabContextMenu.addAction( |
|
205 "", self.__tabContextMenuAudioMute) |
|
206 self.__tabContextMenu.addSeparator() |
|
207 else: |
|
208 self.__audioAct = None |
|
209 self.__tabContextMenu.addAction( |
|
210 UI.PixmapCache.getIcon("reload.png"), |
|
211 self.tr('Reload All'), self.reloadAllBrowsers) |
|
212 self.__tabContextMenu.addSeparator() |
|
213 self.__tabContextMenu.addAction( |
|
214 UI.PixmapCache.getIcon("addBookmark.png"), |
|
215 self.tr('Bookmark All Tabs'), self.__mainWindow.bookmarkAll) |
|
216 |
|
217 self.__tabBackContextMenu = QMenu(self) |
|
218 self.__tabBackContextMenu.addAction( |
|
219 self.tr('Close All'), self.closeAllBrowsers) |
|
220 self.__tabBackContextMenu.addAction( |
|
221 UI.PixmapCache.getIcon("reload.png"), |
|
222 self.tr('Reload All'), self.reloadAllBrowsers) |
|
223 self.__tabBackContextMenu.addAction( |
|
224 UI.PixmapCache.getIcon("addBookmark.png"), |
|
225 self.tr('Bookmark All Tabs'), self.__mainWindow.bookmarkAll) |
|
226 self.__tabBackContextMenu.addSeparator() |
|
227 self.__restoreClosedTabAct = self.__tabBackContextMenu.addAction( |
|
228 UI.PixmapCache.getIcon("trash.png"), |
|
229 self.tr('Restore Closed Tab')) |
|
230 self.__restoreClosedTabAct.setEnabled(False) |
|
231 self.__restoreClosedTabAct.setData(0) |
|
232 self.__restoreClosedTabAct.triggered.connect( |
|
233 lambda: self.restoreClosedTab(self.__restoreClosedTabAct)) |
|
234 |
|
235 def __showContextMenu(self, coord, index): |
|
236 """ |
|
237 Private slot to show the tab context menu. |
|
238 |
|
239 @param coord the position of the mouse pointer (QPoint) |
|
240 @param index index of the tab the menu is requested for (integer) |
|
241 """ |
|
242 coord = self.mapToGlobal(coord) |
|
243 if index == -1: |
|
244 self.__tabBackContextMenu.popup(coord) |
|
245 else: |
|
246 self.__tabContextMenuIndex = index |
|
247 self.leftMenuAct.setEnabled(index > 0) |
|
248 self.rightMenuAct.setEnabled(index < self.count() - 1) |
|
249 |
|
250 self.tabContextCloseOthersAct.setEnabled(self.count() > 1) |
|
251 |
|
252 if self.__audioAct is not None: |
|
253 if self.widget(self.__tabContextMenuIndex).page()\ |
|
254 .isAudioMuted(): |
|
255 self.__audioAct.setText(self.tr("Unmute Tab")) |
|
256 self.__audioAct.setIcon( |
|
257 UI.PixmapCache.getIcon("audioVolumeHigh.png")) |
|
258 else: |
|
259 self.__audioAct.setText(self.tr("Mute Tab")) |
|
260 self.__audioAct.setIcon( |
|
261 UI.PixmapCache.getIcon("audioVolumeMuted.png")) |
|
262 |
|
263 self.__tabContextMenu.popup(coord) |
|
264 |
|
265 def __tabContextMenuMoveLeft(self): |
|
266 """ |
|
267 Private method to move a tab one position to the left. |
|
268 """ |
|
269 self.moveTab(self.__tabContextMenuIndex, |
|
270 self.__tabContextMenuIndex - 1) |
|
271 |
|
272 def __tabContextMenuMoveRight(self): |
|
273 """ |
|
274 Private method to move a tab one position to the right. |
|
275 """ |
|
276 self.moveTab(self.__tabContextMenuIndex, |
|
277 self.__tabContextMenuIndex + 1) |
|
278 |
|
279 def __tabContextMenuClone(self): |
|
280 """ |
|
281 Private method to clone the selected tab. |
|
282 """ |
|
283 idx = self.__tabContextMenuIndex |
|
284 if idx < 0: |
|
285 idx = self.currentIndex() |
|
286 if idx < 0 or idx > self.count(): |
|
287 return |
|
288 |
|
289 url = self.widget(idx).url() |
|
290 self.newBrowser(url) |
|
291 |
|
292 def __tabContextMenuClose(self): |
|
293 """ |
|
294 Private method to close the selected tab. |
|
295 """ |
|
296 self.closeBrowserAt(self.__tabContextMenuIndex) |
|
297 |
|
298 def __tabContextMenuCloseOthers(self): |
|
299 """ |
|
300 Private slot to close all other tabs. |
|
301 """ |
|
302 index = self.__tabContextMenuIndex |
|
303 for i in list(range(self.count() - 1, index, -1)) + \ |
|
304 list(range(index - 1, -1, -1)): |
|
305 self.closeBrowserAt(i) |
|
306 |
|
307 def __tabContextMenuPrint(self): |
|
308 """ |
|
309 Private method to print the selected tab. |
|
310 """ |
|
311 browser = self.widget(self.__tabContextMenuIndex) |
|
312 self.printBrowser(browser) |
|
313 |
|
314 def __tabContextMenuPrintPdf(self): |
|
315 """ |
|
316 Private method to print the selected tab as PDF. |
|
317 """ |
|
318 browser = self.widget(self.__tabContextMenuIndex) |
|
319 self.printBrowserPdf(browser) |
|
320 |
|
321 def __tabContextMenuPrintPreview(self): |
|
322 """ |
|
323 Private method to show a print preview of the selected tab. |
|
324 """ |
|
325 browser = self.widget(self.__tabContextMenuIndex) |
|
326 self.printPreviewBrowser(browser) |
|
327 |
|
328 def __tabContextMenuAudioMute(self): |
|
329 """ |
|
330 Private method to mute or unmute the selected tab. |
|
331 """ |
|
332 page = self.widget(self.__tabContextMenuIndex).page() |
|
333 muted = page.isAudioMuted() |
|
334 page.setAudioMuted(not muted) |
|
335 |
|
336 @pyqtSlot(bool) |
|
337 def __recentlyAudibleChanged(self, recentlyAudible, page): |
|
338 """ |
|
339 Private slot to react on the audible state of a page. |
|
340 |
|
341 @param recentlyAudible flag indicating the new audible state |
|
342 @type bool |
|
343 @param page reference to the web page |
|
344 @type WebBrowserPage |
|
345 """ |
|
346 browser = page.view() |
|
347 if browser is None: |
|
348 return |
|
349 |
|
350 index = self.indexOf(browser) |
|
351 icon = page.icon() |
|
352 |
|
353 if page.isAudioMuted() or ( |
|
354 not page.isAudioMuted() and recentlyAudible): |
|
355 pix = QPixmap(32, 32) |
|
356 pix.fill(Qt.transparent) |
|
357 painter = QPainter(pix) |
|
358 icon.paint(painter, 0, 0, 22, 22) |
|
359 if page.isAudioMuted(): |
|
360 audioIcon = UI.PixmapCache.getIcon("audioMuted.png") |
|
361 else: |
|
362 audioIcon = UI.PixmapCache.getIcon("audioPlaying.png") |
|
363 audioIcon.paint(painter, 13, 13, 18, 18) |
|
364 painter.end() |
|
365 self.setTabIcon(index, QIcon(pix)) |
|
366 else: |
|
367 self.setTabIcon(index, icon) |
|
368 |
|
369 @pyqtSlot() |
|
370 def __newBrowser(self): |
|
371 """ |
|
372 Private slot to open a new browser tab. |
|
373 """ |
|
374 self.newBrowser() |
|
375 |
|
376 def newBrowser(self, link=None, position=-1, background=False, |
|
377 restoreSession=False): |
|
378 """ |
|
379 Public method to create a new web browser tab. |
|
380 |
|
381 @param link link to be shown |
|
382 @type str or QUrl |
|
383 @keyparam position position to create the new tab at or -1 to add it |
|
384 to the end |
|
385 @type int |
|
386 @keyparam background flag indicating to open the tab in the |
|
387 background |
|
388 @type bool |
|
389 @keyparam restoreSession flag indicating a restore session action |
|
390 @type bool |
|
391 @return reference to the new browser |
|
392 @rtype WebBrowserView |
|
393 """ |
|
394 if link is None: |
|
395 linkName = "" |
|
396 elif isinstance(link, QUrl): |
|
397 linkName = link.toString() |
|
398 else: |
|
399 linkName = link |
|
400 |
|
401 from .UrlBar.UrlBar import UrlBar |
|
402 urlbar = UrlBar(self.__mainWindow, self) |
|
403 if self.__historyCompleter is None: |
|
404 import WebBrowser.WebBrowserWindow |
|
405 from .History.HistoryCompleter import HistoryCompletionModel, \ |
|
406 HistoryCompleter |
|
407 self.__historyCompletionModel = HistoryCompletionModel(self) |
|
408 self.__historyCompletionModel.setSourceModel( |
|
409 WebBrowser.WebBrowserWindow.WebBrowserWindow.historyManager() |
|
410 .historyFilterModel()) |
|
411 self.__historyCompleter = HistoryCompleter( |
|
412 self.__historyCompletionModel, self) |
|
413 self.__historyCompleter.activated[str].connect(self.__pathSelected) |
|
414 urlbar.setCompleter(self.__historyCompleter) |
|
415 urlbar.returnPressed.connect( |
|
416 lambda: self.__lineEditReturnPressed(urlbar)) |
|
417 if position == -1: |
|
418 self.__stackedUrlBar.addWidget(urlbar) |
|
419 else: |
|
420 self.__stackedUrlBar.insertWidget(position, urlbar) |
|
421 |
|
422 browser = WebBrowserView(self.__mainWindow, self) |
|
423 urlbar.setBrowser(browser) |
|
424 |
|
425 browser.sourceChanged.connect( |
|
426 lambda url: self.__sourceChanged(url, browser)) |
|
427 browser.titleChanged.connect( |
|
428 lambda title: self.__titleChanged(title, browser)) |
|
429 browser.highlighted.connect(self.showMessage) |
|
430 browser.backwardAvailable.connect( |
|
431 self.__mainWindow.setBackwardAvailable) |
|
432 browser.forwardAvailable.connect(self.__mainWindow.setForwardAvailable) |
|
433 browser.loadStarted.connect( |
|
434 lambda: self.__loadStarted(browser)) |
|
435 browser.loadFinished.connect( |
|
436 lambda ok: self.__loadFinished(ok, browser)) |
|
437 browser.faviconChanged.connect( |
|
438 lambda: self.__iconChanged(browser)) |
|
439 browser.search.connect(self.newBrowser) |
|
440 browser.page().windowCloseRequested.connect( |
|
441 lambda: self.__windowCloseRequested(browser.page())) |
|
442 browser.zoomValueChanged.connect(self.browserZoomValueChanged) |
|
443 if hasattr(WebBrowserPage, "recentlyAudibleChanged"): |
|
444 browser.page().recentlyAudibleChanged.connect( |
|
445 lambda audible: self.__recentlyAudibleChanged( |
|
446 audible, browser.page())) |
|
447 try: |
|
448 browser.page().printRequested.connect( |
|
449 lambda: self.printBrowser(browser)) |
|
450 except AttributeError: |
|
451 # pre Qt 5.12 |
|
452 pass |
|
453 |
|
454 if position == -1: |
|
455 index = self.addTab(browser, self.tr("...")) |
|
456 else: |
|
457 index = self.insertTab(position, browser, self.tr("...")) |
|
458 if not background: |
|
459 self.setCurrentIndex(index) |
|
460 |
|
461 self.__mainWindow.closeAct.setEnabled(True) |
|
462 self.__mainWindow.closeAllAct.setEnabled(True) |
|
463 self.__closeButton.setEnabled(True) |
|
464 self.__navigationButton.setEnabled(True) |
|
465 |
|
466 if not restoreSession: |
|
467 if not linkName: |
|
468 if Preferences.getWebBrowser("NewTabBehavior") == 0: |
|
469 linkName = "about:blank" |
|
470 elif Preferences.getWebBrowser("NewTabBehavior") == 1: |
|
471 linkName = Preferences.getWebBrowser("HomePage") |
|
472 elif Preferences.getWebBrowser("NewTabBehavior") == 2: |
|
473 linkName = "eric:speeddial" |
|
474 |
|
475 if linkName == "eric:blank": |
|
476 linkName = "about:blank" |
|
477 |
|
478 if linkName: |
|
479 browser.setSource(QUrl(linkName)) |
|
480 if not browser.documentTitle(): |
|
481 self.setTabText(index, self.__elide(linkName, Qt.ElideMiddle)) |
|
482 self.setTabToolTip(index, linkName) |
|
483 else: |
|
484 self.setTabText( |
|
485 index, |
|
486 self.__elide(browser.documentTitle().replace("&", "&&"))) |
|
487 self.setTabToolTip(index, browser.documentTitle()) |
|
488 |
|
489 self.browserOpened.emit(browser) |
|
490 |
|
491 return browser |
|
492 |
|
493 def newBrowserAfter(self, browser, link=None, background=False): |
|
494 """ |
|
495 Public method to create a new web browser tab after a given one. |
|
496 |
|
497 @param browser reference to the browser to add after (WebBrowserView) |
|
498 @param link link to be shown (string or QUrl) |
|
499 @keyparam background flag indicating to open the tab in the |
|
500 background (bool) |
|
501 @return reference to the new browser |
|
502 @rtype WebBrowserView |
|
503 """ |
|
504 if browser: |
|
505 position = self.indexOf(browser) + 1 |
|
506 else: |
|
507 position = -1 |
|
508 return self.newBrowser(link, position, background) |
|
509 |
|
510 def __showNavigationMenu(self): |
|
511 """ |
|
512 Private slot to show the navigation button menu. |
|
513 """ |
|
514 self.__navigationMenu.clear() |
|
515 for index in range(self.count()): |
|
516 act = self.__navigationMenu.addAction( |
|
517 self.tabIcon(index), self.tabText(index)) |
|
518 act.setData(index) |
|
519 |
|
520 def __navigationMenuTriggered(self, act): |
|
521 """ |
|
522 Private slot called to handle the navigation button menu selection. |
|
523 |
|
524 @param act reference to the selected action (QAction) |
|
525 """ |
|
526 index = act.data() |
|
527 if index is not None: |
|
528 self.setCurrentIndex(index) |
|
529 |
|
530 def __windowCloseRequested(self, page): |
|
531 """ |
|
532 Private slot to handle the windowCloseRequested signal of a browser. |
|
533 |
|
534 @param page reference to the web page |
|
535 @type WebBrowserPage |
|
536 """ |
|
537 browser = page.view() |
|
538 if browser is None: |
|
539 return |
|
540 |
|
541 index = self.indexOf(browser) |
|
542 self.closeBrowserAt(index) |
|
543 |
|
544 def reloadAllBrowsers(self): |
|
545 """ |
|
546 Public slot to reload all browsers. |
|
547 """ |
|
548 for index in range(self.count()): |
|
549 browser = self.widget(index) |
|
550 browser and browser.reload() |
|
551 |
|
552 @pyqtSlot() |
|
553 def closeBrowser(self): |
|
554 """ |
|
555 Public slot called to handle the close action. |
|
556 """ |
|
557 self.closeBrowserAt(self.currentIndex()) |
|
558 |
|
559 def closeAllBrowsers(self, shutdown=False): |
|
560 """ |
|
561 Public slot called to handle the close all action. |
|
562 |
|
563 @param shutdown flag indicating a shutdown action |
|
564 @type bool |
|
565 """ |
|
566 for index in range(self.count() - 1, -1, -1): |
|
567 self.closeBrowserAt(index, shutdown=shutdown) |
|
568 |
|
569 def closeBrowserView(self, browser): |
|
570 """ |
|
571 Public method to close the given browser. |
|
572 |
|
573 @param browser reference to the web browser view to be closed |
|
574 @type WebBrowserView |
|
575 """ |
|
576 index = self.indexOf(browser) |
|
577 self.closeBrowserAt(index) |
|
578 |
|
579 def closeBrowserAt(self, index, shutdown=False): |
|
580 """ |
|
581 Public slot to close a browser based on its index. |
|
582 |
|
583 @param index index of browser to close |
|
584 @type int |
|
585 @param shutdown flag indicating a shutdown action |
|
586 @type bool |
|
587 """ |
|
588 browser = self.widget(index) |
|
589 if browser is None: |
|
590 return |
|
591 |
|
592 urlbar = self.__stackedUrlBar.widget(index) |
|
593 self.__stackedUrlBar.removeWidget(urlbar) |
|
594 urlbar.deleteLater() |
|
595 del urlbar |
|
596 |
|
597 self.__closedTabsManager.recordBrowser(browser, index) |
|
598 |
|
599 browser.closeWebInspector() |
|
600 WebInspector.unregisterView(browser) |
|
601 self.removeTab(index) |
|
602 self.browserClosed.emit(browser) |
|
603 browser.deleteLater() |
|
604 del browser |
|
605 |
|
606 if self.count() == 0 and not shutdown: |
|
607 self.newBrowser() |
|
608 else: |
|
609 self.currentChanged[int].emit(self.currentIndex()) |
|
610 |
|
611 def currentBrowser(self): |
|
612 """ |
|
613 Public method to get a reference to the current browser. |
|
614 |
|
615 @return reference to the current browser (WebBrowserView) |
|
616 """ |
|
617 return self.currentWidget() |
|
618 |
|
619 def browserAt(self, index): |
|
620 """ |
|
621 Public method to get a reference to the browser with the given index. |
|
622 |
|
623 @param index index of the browser to get (integer) |
|
624 @return reference to the indexed browser (WebBrowserView) |
|
625 """ |
|
626 return self.widget(index) |
|
627 |
|
628 def browsers(self): |
|
629 """ |
|
630 Public method to get a list of references to all browsers. |
|
631 |
|
632 @return list of references to browsers (list of WebBrowserView) |
|
633 """ |
|
634 li = [] |
|
635 for index in range(self.count()): |
|
636 li.append(self.widget(index)) |
|
637 return li |
|
638 |
|
639 @pyqtSlot() |
|
640 def printBrowser(self, browser=None): |
|
641 """ |
|
642 Public slot called to print the displayed page. |
|
643 |
|
644 @param browser reference to the browser to be printed (WebBrowserView) |
|
645 """ |
|
646 if browser is None: |
|
647 browser = self.currentBrowser() |
|
648 |
|
649 printer = QPrinter(mode=QPrinter.HighResolution) |
|
650 if Preferences.getPrinter("ColorMode"): |
|
651 printer.setColorMode(QPrinter.Color) |
|
652 else: |
|
653 printer.setColorMode(QPrinter.GrayScale) |
|
654 if Preferences.getPrinter("FirstPageFirst"): |
|
655 printer.setPageOrder(QPrinter.FirstPageFirst) |
|
656 else: |
|
657 printer.setPageOrder(QPrinter.LastPageFirst) |
|
658 printer.setPageMargins( |
|
659 Preferences.getPrinter("LeftMargin") * 10, |
|
660 Preferences.getPrinter("TopMargin") * 10, |
|
661 Preferences.getPrinter("RightMargin") * 10, |
|
662 Preferences.getPrinter("BottomMargin") * 10, |
|
663 QPrinter.Millimeter |
|
664 ) |
|
665 printerName = Preferences.getPrinter("PrinterName") |
|
666 if printerName: |
|
667 printer.setPrinterName(printerName) |
|
668 printer.setResolution(Preferences.getPrinter("Resolution")) |
|
669 documentName = WebBrowserTools.getFileNameFromUrl(browser.url()) |
|
670 printer.setDocName(documentName) |
|
671 |
|
672 printDialog = QPrintDialog(printer, self) |
|
673 printDialog.setOptions(QAbstractPrintDialog.PrintToFile | |
|
674 QAbstractPrintDialog.PrintShowPageSize) |
|
675 if not Globals.isWindowsPlatform(): |
|
676 if FilePrinter.isCupsAvailable(): |
|
677 printDialog.setOption(QAbstractPrintDialog.PrintCollateCopies) |
|
678 printDialog.setOption(QAbstractPrintDialog.PrintPageRange) |
|
679 if printDialog.exec_() == QDialog.Accepted: |
|
680 if hasattr(browser.page(), "print"): |
|
681 # Qt >= 5.8.0 |
|
682 browser.page().execPrintPage(printer, 10 * 1000) |
|
683 elif hasattr(browser.page(), "printToPdf"): |
|
684 # Qt >= 5.7.0 |
|
685 if printer.outputFormat() == QPrinter.PdfFormat: |
|
686 # print to PDF file selected |
|
687 browser.page().printToPdf( |
|
688 lambda pdf: self.__pdfGeneratedForSave( |
|
689 printer.outputFileName(), pdf), |
|
690 printer.pageLayout()) |
|
691 else: |
|
692 # print to printer |
|
693 self.__pdfPrinter = printer |
|
694 browser.page().printToPdf( |
|
695 self.__pdfGeneratedForPrinting, |
|
696 printer.pageLayout()) |
|
697 else: |
|
698 browser.render(printer) |
|
699 |
|
700 @pyqtSlot() |
|
701 def printBrowserPdf(self, browser=None): |
|
702 """ |
|
703 Public slot called to print the displayed page to PDF. |
|
704 |
|
705 @param browser reference to the browser to be printed (HelpBrowser) |
|
706 """ |
|
707 if browser is None: |
|
708 browser = self.currentBrowser() |
|
709 |
|
710 name = WebBrowserTools.getFileNameFromUrl(browser.url()) |
|
711 if name: |
|
712 name = name.rsplit('.', 1)[0] |
|
713 name += '.pdf' |
|
714 if hasattr(browser.page(), "printToPdf"): |
|
715 from .Tools.PrintToPdfDialog import PrintToPdfDialog |
|
716 if not name: |
|
717 name = "printout.pdf" |
|
718 dlg = PrintToPdfDialog(name, self) |
|
719 if dlg.exec_() == QDialog.Accepted: |
|
720 filePath, pageLayout = dlg.getData() |
|
721 if filePath: |
|
722 if os.path.exists(filePath): |
|
723 res = E5MessageBox.warning( |
|
724 self, |
|
725 self.tr("Print to PDF"), |
|
726 self.tr("""<p>The file <b>{0}</b> exists""" |
|
727 """ already. Shall it be""" |
|
728 """ overwritten?</p>""").format(filePath), |
|
729 E5MessageBox.StandardButtons( |
|
730 E5MessageBox.No | |
|
731 E5MessageBox.Yes), |
|
732 E5MessageBox.No) |
|
733 if res == E5MessageBox.No: |
|
734 return |
|
735 browser.page().printToPdf( |
|
736 lambda pdf: self.__pdfGeneratedForSave(filePath, pdf), |
|
737 pageLayout) |
|
738 elif Globals.isLinuxPlatform(): |
|
739 printer = QPrinter(mode=QPrinter.HighResolution) |
|
740 if Preferences.getPrinter("ColorMode"): |
|
741 printer.setColorMode(QPrinter.Color) |
|
742 else: |
|
743 printer.setColorMode(QPrinter.GrayScale) |
|
744 printerName = Preferences.getPrinter("PrinterName") |
|
745 if printerName: |
|
746 printer.setPrinterName(printerName) |
|
747 printer.setOutputFormat(QPrinter.PdfFormat) |
|
748 if name: |
|
749 printer.setOutputFileName(name) |
|
750 printer.setResolution(Preferences.getPrinter("Resolution")) |
|
751 |
|
752 printDialog = QPrintDialog(printer, self) |
|
753 if printDialog.exec_() == QDialog.Accepted: |
|
754 browser.render(printer) |
|
755 |
|
756 def __pdfGeneratedForSave(self, filePath, pdfData): |
|
757 """ |
|
758 Private slot to save the generated PDF data to a file. |
|
759 |
|
760 @param filePath path to save the PDF to |
|
761 @type str |
|
762 @param pdfData generated PDF document |
|
763 @type QByteArray |
|
764 """ |
|
765 if pdfData.size() == 0: |
|
766 return |
|
767 |
|
768 pdfFile = QFile(filePath) |
|
769 if pdfFile.open(QFile.WriteOnly): |
|
770 pdfFile.write(pdfData) |
|
771 pdfFile.close() |
|
772 if pdfFile.error() != QFileDevice.NoError: |
|
773 E5MessageBox.critical( |
|
774 self, |
|
775 self.tr("Print to PDF"), |
|
776 self.tr("""<p>The PDF could not be written to file <b>{0}""" |
|
777 """</b>.</p><p><b>Error:</b> {1}</p>""").format( |
|
778 filePath, pdfFile.errorString()), |
|
779 E5MessageBox.StandardButtons( |
|
780 E5MessageBox.Ok)) |
|
781 |
|
782 def __pdfGeneratedForPrinting(self, pdfData): |
|
783 """ |
|
784 Private slot to print the generated PDF data. |
|
785 |
|
786 @param pdfData generated PDF document |
|
787 @type QByteArray |
|
788 """ |
|
789 if self.__pdfPrinter is None or pdfData.isEmpty(): |
|
790 return |
|
791 |
|
792 tempFile = QTemporaryFile(QDir.tempPath() + "/ericBrowserXXXXXX.pdf") |
|
793 tempFile.setAutoRemove(False) |
|
794 if tempFile.open(): |
|
795 bytesWritten = tempFile.write(pdfData) |
|
796 tempFile.close() |
|
797 if bytesWritten == pdfData.size(): |
|
798 if Globals.isWindowsPlatform(): |
|
799 printerName = self.__pdfPrinter.printerName() |
|
800 import ctypes |
|
801 ctypes.windll.shell32.ShellExecuteW( |
|
802 None, "printto", tempFile.fileName(), |
|
803 '"{0}"'.format(printerName), None, 0) |
|
804 else: |
|
805 FilePrinter.printFile( |
|
806 self.__pdfPrinter, tempFile.fileName(), |
|
807 FilePrinter.FilePrinter.SystemDeletesFiles, |
|
808 FilePrinter.FilePrinter.SystemSelectsPages) |
|
809 else: |
|
810 tempFile.remove() |
|
811 |
|
812 self.__pdfPrinter = None |
|
813 |
|
814 @pyqtSlot() |
|
815 def printPreviewBrowser(self, browser=None): |
|
816 """ |
|
817 Public slot called to show a print preview of the displayed file. |
|
818 |
|
819 @param browser reference to the browser to be printed (WebBrowserView) |
|
820 """ |
|
821 from PyQt5.QtPrintSupport import QPrintPreviewDialog |
|
822 |
|
823 if browser is None: |
|
824 browser = self.currentBrowser() |
|
825 |
|
826 printer = QPrinter(mode=QPrinter.HighResolution) |
|
827 if Preferences.getPrinter("ColorMode"): |
|
828 printer.setColorMode(QPrinter.Color) |
|
829 else: |
|
830 printer.setColorMode(QPrinter.GrayScale) |
|
831 if Preferences.getPrinter("FirstPageFirst"): |
|
832 printer.setPageOrder(QPrinter.FirstPageFirst) |
|
833 else: |
|
834 printer.setPageOrder(QPrinter.LastPageFirst) |
|
835 printer.setPageMargins( |
|
836 Preferences.getPrinter("LeftMargin") * 10, |
|
837 Preferences.getPrinter("TopMargin") * 10, |
|
838 Preferences.getPrinter("RightMargin") * 10, |
|
839 Preferences.getPrinter("BottomMargin") * 10, |
|
840 QPrinter.Millimeter |
|
841 ) |
|
842 printerName = Preferences.getPrinter("PrinterName") |
|
843 if printerName: |
|
844 printer.setPrinterName(printerName) |
|
845 printer.setResolution(Preferences.getPrinter("Resolution")) |
|
846 |
|
847 preview = QPrintPreviewDialog(printer, self) |
|
848 preview.resize(800, 750) |
|
849 if qVersionTuple() >= (5, 8, 0): |
|
850 preview.paintRequested.connect( |
|
851 lambda p: self.__printPreviewRequested(p, browser)) |
|
852 else: |
|
853 preview.paintRequested.connect(lambda p: browser.render(p)) |
|
854 preview.exec_() |
|
855 |
|
856 def __printPreviewRequested(self, printer, browser): |
|
857 """ |
|
858 Private slot to generate the print preview. |
|
859 |
|
860 @param printer reference to the printer object |
|
861 @type QPrinter |
|
862 @param browser reference to the browser to be printed |
|
863 @type WebBrowserView |
|
864 """ |
|
865 QApplication.setOverrideCursor(Qt.WaitCursor) |
|
866 browser.page().execPrintPage(printer, 10 * 1000) |
|
867 QApplication.restoreOverrideCursor() |
|
868 |
|
869 def __sourceChanged(self, url, browser): |
|
870 """ |
|
871 Private slot to handle a change of a browsers source. |
|
872 |
|
873 @param url URL of the new site |
|
874 @type QUrl |
|
875 @param browser reference to the web browser |
|
876 @type WebBrowserView |
|
877 """ |
|
878 self.sourceChanged.emit(browser, url) |
|
879 |
|
880 if browser == self.currentBrowser(): |
|
881 self.currentUrlChanged.emit(url) |
|
882 |
|
883 def __titleChanged(self, title, browser): |
|
884 """ |
|
885 Private slot to handle a change of a browsers title. |
|
886 |
|
887 @param title new title |
|
888 @type str |
|
889 @param browser reference to the web browser |
|
890 @type WebBrowserView |
|
891 """ |
|
892 index = self.indexOf(browser) |
|
893 if title == "": |
|
894 title = browser.url().toString() |
|
895 |
|
896 self.setTabText(index, self.__elide(title.replace("&", "&&"))) |
|
897 self.setTabToolTip(index, title) |
|
898 |
|
899 self.titleChanged.emit(browser, title) |
|
900 |
|
901 def __elide(self, txt, mode=Qt.ElideRight, length=40): |
|
902 """ |
|
903 Private method to elide some text. |
|
904 |
|
905 @param txt text to be elided (string) |
|
906 @keyparam mode elide mode (Qt.TextElideMode) |
|
907 @keyparam length amount of characters to be used (integer) |
|
908 @return the elided text (string) |
|
909 """ |
|
910 if mode == Qt.ElideNone or len(txt) < length: |
|
911 return txt |
|
912 elif mode == Qt.ElideLeft: |
|
913 return "...{0}".format(txt[-length:]) |
|
914 elif mode == Qt.ElideMiddle: |
|
915 return "{0}...{1}".format(txt[:length // 2], txt[-(length // 2):]) |
|
916 elif mode == Qt.ElideRight: |
|
917 return "{0}...".format(txt[:length]) |
|
918 else: |
|
919 # just in case |
|
920 return txt |
|
921 |
|
922 def preferencesChanged(self): |
|
923 """ |
|
924 Public slot to handle a change of preferences. |
|
925 """ |
|
926 for browser in self.browsers(): |
|
927 browser.preferencesChanged() |
|
928 |
|
929 for urlbar in self.__stackedUrlBar.urlBars(): |
|
930 urlbar.preferencesChanged() |
|
931 |
|
932 if Preferences.getUI("SingleCloseButton"): |
|
933 self.setTabsClosable(False) |
|
934 try: |
|
935 self.tabCloseRequested.disconnect(self.closeBrowserAt) |
|
936 except TypeError: |
|
937 pass |
|
938 self.__closeButton.show() |
|
939 else: |
|
940 self.setTabsClosable(True) |
|
941 self.tabCloseRequested.connect(self.closeBrowserAt) |
|
942 self.__closeButton.hide() |
|
943 |
|
944 def __loadStarted(self, browser): |
|
945 """ |
|
946 Private method to handle the loadStarted signal. |
|
947 |
|
948 @param browser reference to the web browser |
|
949 @type WebBrowserView |
|
950 """ |
|
951 index = self.indexOf(browser) |
|
952 anim = self.animationLabel( |
|
953 index, os.path.join(getConfig("ericPixDir"), "loading.gif"), |
|
954 100) |
|
955 if not anim: |
|
956 loading = QIcon(os.path.join(getConfig("ericPixDir"), |
|
957 "loading.gif")) |
|
958 self.setTabIcon(index, loading) |
|
959 else: |
|
960 self.setTabIcon(index, QIcon()) |
|
961 self.setTabText(index, self.tr("Loading...")) |
|
962 self.setTabToolTip(index, self.tr("Loading...")) |
|
963 self.showMessage.emit(self.tr("Loading...")) |
|
964 |
|
965 self.__mainWindow.setLoadingActions(True) |
|
966 |
|
967 def __loadFinished(self, ok, browser): |
|
968 """ |
|
969 Private method to handle the loadFinished signal. |
|
970 |
|
971 @param ok flag indicating the result |
|
972 @type bool |
|
973 @param browser reference to the web browser |
|
974 @type WebBrowserView |
|
975 """ |
|
976 import WebBrowser.WebBrowserWindow |
|
977 index = self.indexOf(browser) |
|
978 self.resetAnimation(index) |
|
979 self.setTabIcon( |
|
980 index, WebBrowser.WebBrowserWindow.WebBrowserWindow.icon( |
|
981 browser.url())) |
|
982 if ok: |
|
983 self.showMessage.emit(self.tr("Finished loading")) |
|
984 else: |
|
985 self.showMessage.emit(self.tr("Failed to load")) |
|
986 |
|
987 self.__mainWindow.setLoadingActions(False) |
|
988 |
|
989 def __iconChanged(self, browser): |
|
990 """ |
|
991 Private slot to handle a change of the web site icon. |
|
992 |
|
993 @param browser reference to the web browser |
|
994 @type WebBrowserView |
|
995 """ |
|
996 self.setTabIcon( |
|
997 self.indexOf(browser), |
|
998 browser.icon()) |
|
999 self.__mainWindow.bookmarksManager().faviconChanged(browser.url()) |
|
1000 |
|
1001 def getSourceFileList(self): |
|
1002 """ |
|
1003 Public method to get a list of all opened Qt help files. |
|
1004 |
|
1005 @return dictionary with tab id as key and host/namespace as value |
|
1006 """ |
|
1007 sourceList = {} |
|
1008 for i in range(self.count()): |
|
1009 browser = self.widget(i) |
|
1010 if browser is not None and \ |
|
1011 browser.source().isValid(): |
|
1012 sourceList[i] = browser.source().host() |
|
1013 |
|
1014 return sourceList |
|
1015 |
|
1016 def shallShutDown(self): |
|
1017 """ |
|
1018 Public method to check, if the application should be shut down. |
|
1019 |
|
1020 @return flag indicating a shut down (boolean) |
|
1021 """ |
|
1022 if self.count() > 1 and Preferences.getWebBrowser( |
|
1023 "WarnOnMultipleClose"): |
|
1024 mb = E5MessageBox.E5MessageBox( |
|
1025 E5MessageBox.Information, |
|
1026 self.tr("Are you sure you want to close the window?"), |
|
1027 self.tr("""Are you sure you want to close the window?\n""" |
|
1028 """You have %n tab(s) open.""", "", self.count()), |
|
1029 modal=True, |
|
1030 parent=self) |
|
1031 quitButton = mb.addButton( |
|
1032 self.tr("&Quit"), E5MessageBox.AcceptRole) |
|
1033 quitButton.setIcon(UI.PixmapCache.getIcon("exit.png")) |
|
1034 closeTabButton = mb.addButton( |
|
1035 self.tr("C&lose Current Tab"), E5MessageBox.AcceptRole) |
|
1036 closeTabButton.setIcon(UI.PixmapCache.getIcon("tabClose.png")) |
|
1037 mb.addButton(E5MessageBox.Cancel) |
|
1038 mb.exec_() |
|
1039 if mb.clickedButton() == quitButton: |
|
1040 return True |
|
1041 else: |
|
1042 if mb.clickedButton() == closeTabButton: |
|
1043 self.closeBrowser() |
|
1044 return False |
|
1045 |
|
1046 return True |
|
1047 |
|
1048 def stackedUrlBar(self): |
|
1049 """ |
|
1050 Public method to get a reference to the stacked url bar. |
|
1051 |
|
1052 @return reference to the stacked url bar (StackedUrlBar) |
|
1053 """ |
|
1054 return self.__stackedUrlBar |
|
1055 |
|
1056 def currentUrlBar(self): |
|
1057 """ |
|
1058 Public method to get a reference to the current url bar. |
|
1059 |
|
1060 @return reference to the current url bar (UrlBar) |
|
1061 """ |
|
1062 return self.__stackedUrlBar.currentWidget() |
|
1063 |
|
1064 def urlBarForView(self, view): |
|
1065 """ |
|
1066 Public method to get a reference to the UrlBar associated with the |
|
1067 given view. |
|
1068 |
|
1069 @param view reference to the view to get the urlbar for |
|
1070 @type WebBrowserView |
|
1071 @return reference to the associated urlbar |
|
1072 @rtype UrlBar |
|
1073 """ |
|
1074 for urlbar in self.__stackedUrlBar.urlBars(): |
|
1075 if urlbar.browser() is view: |
|
1076 return urlbar |
|
1077 |
|
1078 return None |
|
1079 |
|
1080 def __lineEditReturnPressed(self, edit): |
|
1081 """ |
|
1082 Private slot to handle the entering of an URL. |
|
1083 |
|
1084 @param edit reference to the line edit |
|
1085 @type UrlBar |
|
1086 """ |
|
1087 url = self.__guessUrlFromPath(edit.text()) |
|
1088 if e5App().keyboardModifiers() == Qt.AltModifier: |
|
1089 self.newBrowser(url) |
|
1090 else: |
|
1091 self.currentBrowser().setSource(url) |
|
1092 self.currentBrowser().setFocus() |
|
1093 |
|
1094 def __pathSelected(self, path): |
|
1095 """ |
|
1096 Private slot called when a URL is selected from the completer. |
|
1097 |
|
1098 @param path path to be shown (string) |
|
1099 """ |
|
1100 url = self.__guessUrlFromPath(path) |
|
1101 self.currentBrowser().setSource(url) |
|
1102 |
|
1103 def __guessUrlFromPath(self, path): |
|
1104 """ |
|
1105 Private method to guess an URL given a path string. |
|
1106 |
|
1107 @param path path string to guess an URL for (string) |
|
1108 @return guessed URL (QUrl) |
|
1109 """ |
|
1110 manager = self.__mainWindow.openSearchManager() |
|
1111 path = Utilities.fromNativeSeparators(path) |
|
1112 url = manager.convertKeywordSearchToUrl(path) |
|
1113 if url.isValid(): |
|
1114 return url |
|
1115 |
|
1116 try: |
|
1117 url = QUrl.fromUserInput(path) |
|
1118 except AttributeError: |
|
1119 url = QUrl(path) |
|
1120 |
|
1121 if url.scheme() == "about" and \ |
|
1122 url.path() == "home": |
|
1123 url = QUrl("eric:home") |
|
1124 |
|
1125 if url.scheme() in ["s", "search"]: |
|
1126 url = manager.currentEngine().searchUrl(url.path().strip()) |
|
1127 |
|
1128 if url.scheme() != "" and \ |
|
1129 (url.host() != "" or url.path() != ""): |
|
1130 return url |
|
1131 |
|
1132 urlString = Preferences.getWebBrowser("DefaultScheme") + path.strip() |
|
1133 url = QUrl.fromEncoded(urlString.encode("utf-8"), QUrl.TolerantMode) |
|
1134 |
|
1135 return url |
|
1136 |
|
1137 def __currentChanged(self, index): |
|
1138 """ |
|
1139 Private slot to handle an index change. |
|
1140 |
|
1141 @param index new index (integer) |
|
1142 """ |
|
1143 self.__stackedUrlBar.setCurrentIndex(index) |
|
1144 |
|
1145 browser = self.browserAt(index) |
|
1146 if browser is not None: |
|
1147 if browser.url() == "" and browser.hasFocus(): |
|
1148 self.__stackedUrlBar.currentWidget.setFocus() |
|
1149 elif browser.url() != "": |
|
1150 browser.setFocus() |
|
1151 |
|
1152 def restoreClosedTab(self, act): |
|
1153 """ |
|
1154 Public slot to restore the most recently closed tab. |
|
1155 |
|
1156 @param act reference to the action that triggered |
|
1157 @type QAction |
|
1158 """ |
|
1159 if not self.canRestoreClosedTab(): |
|
1160 return |
|
1161 |
|
1162 tab = self.__closedTabsManager.getClosedTabAt(act.data()) |
|
1163 |
|
1164 self.newBrowser(tab.url.toString(), position=tab.position) |
|
1165 |
|
1166 def canRestoreClosedTab(self): |
|
1167 """ |
|
1168 Public method to check, if closed tabs can be restored. |
|
1169 |
|
1170 @return flag indicating that closed tabs can be restored (boolean) |
|
1171 """ |
|
1172 return self.__closedTabsManager.isClosedTabAvailable() |
|
1173 |
|
1174 def restoreAllClosedTabs(self): |
|
1175 """ |
|
1176 Public slot to restore all closed tabs. |
|
1177 """ |
|
1178 if not self.canRestoreClosedTab(): |
|
1179 return |
|
1180 |
|
1181 for tab in self.__closedTabsManager.allClosedTabs(): |
|
1182 self.newBrowser(tab.url.toString(), position=tab.position) |
|
1183 self.__closedTabsManager.clearList() |
|
1184 |
|
1185 def clearClosedTabsList(self): |
|
1186 """ |
|
1187 Public slot to clear the list of closed tabs. |
|
1188 """ |
|
1189 self.__closedTabsManager.clearList() |
|
1190 |
|
1191 def __aboutToShowClosedTabsMenu(self): |
|
1192 """ |
|
1193 Private slot to populate the closed tabs menu. |
|
1194 """ |
|
1195 fm = self.__closedTabsMenu.fontMetrics() |
|
1196 maxWidth = fm.width('m') * 40 |
|
1197 |
|
1198 self.__closedTabsMenu.clear() |
|
1199 index = 0 |
|
1200 for tab in self.__closedTabsManager.allClosedTabs(): |
|
1201 title = fm.elidedText(tab.title, Qt.ElideRight, maxWidth) |
|
1202 act = self.__closedTabsMenu.addAction( |
|
1203 self.__mainWindow.icon(tab.url), title) |
|
1204 act.setData(index) |
|
1205 act.triggered.connect(lambda: self.restoreClosedTab(act)) |
|
1206 index += 1 |
|
1207 self.__closedTabsMenu.addSeparator() |
|
1208 self.__closedTabsMenu.addAction( |
|
1209 self.tr("Restore All Closed Tabs"), self.restoreAllClosedTabs) |
|
1210 self.__closedTabsMenu.addAction( |
|
1211 self.tr("Clear List"), self.clearClosedTabsList) |
|
1212 |
|
1213 def closedTabsManager(self): |
|
1214 """ |
|
1215 Public slot to get a reference to the closed tabs manager. |
|
1216 |
|
1217 @return reference to the closed tabs manager (ClosedTabsManager) |
|
1218 """ |
|
1219 return self.__closedTabsManager |
|
1220 |
|
1221 def __closedTabAvailable(self, avail): |
|
1222 """ |
|
1223 Private slot to handle changes of the availability of closed tabs. |
|
1224 |
|
1225 @param avail flag indicating the availability of closed tabs (boolean) |
|
1226 """ |
|
1227 self.__closedTabsButton.setEnabled(avail) |
|
1228 self.__restoreClosedTabAct.setEnabled(avail) |
|
1229 |
|
1230 #################################################### |
|
1231 ## Methods below implement session related functions |
|
1232 #################################################### |
|
1233 |
|
1234 def getSessionData(self): |
|
1235 """ |
|
1236 Public method to populate the session data. |
|
1237 |
|
1238 @return dictionary containing the session data |
|
1239 @rtype dict |
|
1240 """ |
|
1241 sessionData = {} |
|
1242 |
|
1243 # 1. current index |
|
1244 sessionData["CurrentTabIndex"] = self.currentIndex() |
|
1245 |
|
1246 # 2. tab data |
|
1247 sessionData["Tabs"] = [] |
|
1248 for index in range(self.count()): |
|
1249 browser = self.widget(index) |
|
1250 data = browser.getSessionData() |
|
1251 sessionData["Tabs"].append(data) |
|
1252 |
|
1253 return sessionData |
|
1254 |
|
1255 def loadFromSessionData(self, sessionData): |
|
1256 """ |
|
1257 Public method to load the session data. |
|
1258 |
|
1259 @param sessionData dictionary containing the session data as |
|
1260 generated by getSessionData() |
|
1261 @type dict |
|
1262 """ |
|
1263 tabCount = self.count() |
|
1264 |
|
1265 # 1. load tab data |
|
1266 if "Tabs" in sessionData: |
|
1267 loadTabOnActivate = \ |
|
1268 Preferences.getWebBrowser("LoadTabOnActivation") |
|
1269 for data in sessionData["Tabs"]: |
|
1270 browser = self.newBrowser(restoreSession=True) |
|
1271 if loadTabOnActivate: |
|
1272 browser.storeSessionData(data) |
|
1273 title, urlStr, icon = browser.extractSessionMetaData(data) |
|
1274 index = self.indexOf(browser) |
|
1275 self.setTabText(index, title) |
|
1276 self.setTabIcon(index, icon) |
|
1277 else: |
|
1278 browser.loadFromSessionData(data) |
|
1279 |
|
1280 # 2. set tab index |
|
1281 if "CurrentTabIndex" in sessionData and \ |
|
1282 sessionData["CurrentTabIndex"] >= 0: |
|
1283 index = tabCount + sessionData["CurrentTabIndex"] |
|
1284 self.setCurrentIndex(index) |
|
1285 self.browserAt(index).activateSession() |