|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2010 - 2016 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 |
|
15 from PyQt5.QtGui import QIcon |
|
16 from PyQt5.QtWidgets import QWidget, QHBoxLayout, QMenu, QToolButton, QDialog |
|
17 ##from PyQt5.QtPrintSupport import QPrinter, QPrintDialog |
|
18 ##from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest |
|
19 |
|
20 from E5Gui.E5TabWidget import E5TabWidget |
|
21 from E5Gui import E5MessageBox |
|
22 from E5Gui.E5Application import e5App |
|
23 |
|
24 # TODO: implement this |
|
25 from .WebBrowserView import WebBrowserView |
|
26 |
|
27 import UI.PixmapCache |
|
28 |
|
29 import Utilities |
|
30 import Preferences |
|
31 |
|
32 from eric6config import getConfig |
|
33 |
|
34 |
|
35 class WebBrowserTabWidget(E5TabWidget): |
|
36 """ |
|
37 Class implementing the central widget showing the web pages. |
|
38 |
|
39 @signal sourceChanged(WebBrowserView, QUrl) emitted after the URL of a |
|
40 browser has changed |
|
41 @signal titleChanged(WebBrowserView, str) emitted after the title of a |
|
42 browser has changed |
|
43 @signal showMessage(str) emitted to show a message in the main window |
|
44 status bar |
|
45 @signal browserClosed(QWidget) emitted after a browser was closed |
|
46 @signal browserZoomValueChanged(int) emitted to signal a change of the |
|
47 current browser's zoom level |
|
48 """ |
|
49 sourceChanged = pyqtSignal(WebBrowserView, QUrl) |
|
50 titleChanged = pyqtSignal(WebBrowserView, str) |
|
51 showMessage = pyqtSignal(str) |
|
52 browserClosed = pyqtSignal(QWidget) |
|
53 browserZoomValueChanged = pyqtSignal(int) |
|
54 |
|
55 def __init__(self, parent): |
|
56 """ |
|
57 Constructor |
|
58 |
|
59 @param parent reference to the parent widget (QWidget) |
|
60 """ |
|
61 super(WebBrowserTabWidget, self).__init__(self, parent, dnd=True) |
|
62 |
|
63 # TODO: implement this |
|
64 from .WebBrowserTabBar import WebBrowserTabBar |
|
65 self.__tabBar = WebBrowserTabBar(self) |
|
66 self.setCustomTabBar(True, self.__tabBar) |
|
67 |
|
68 self.__mainWindow = parent |
|
69 |
|
70 self.setUsesScrollButtons(True) |
|
71 self.setDocumentMode(True) |
|
72 self.setElideMode(Qt.ElideNone) |
|
73 |
|
74 # TODO: re-enable once Closed Tabs Manager is done |
|
75 ## from .ClosedTabsManager import ClosedTabsManager |
|
76 ## self.__closedTabsManager = ClosedTabsManager(self) |
|
77 ## self.__closedTabsManager.closedTabAvailable.connect( |
|
78 ## self.__closedTabAvailable) |
|
79 |
|
80 from .UrlBar.StackedUrlBar import StackedUrlBar |
|
81 self.__stackedUrlBar = StackedUrlBar(self) |
|
82 self.__tabBar.tabMoved.connect(self.__stackedUrlBar.moveBar) |
|
83 |
|
84 self.__tabContextMenuIndex = -1 |
|
85 self.currentChanged[int].connect(self.__currentChanged) |
|
86 self.setTabContextMenuPolicy(Qt.CustomContextMenu) |
|
87 self.customTabContextMenuRequested.connect(self.__showContextMenu) |
|
88 |
|
89 self.__rightCornerWidget = QWidget(self) |
|
90 self.__rightCornerWidgetLayout = QHBoxLayout(self.__rightCornerWidget) |
|
91 self.__rightCornerWidgetLayout.setContentsMargins(0, 0, 0, 0) |
|
92 self.__rightCornerWidgetLayout.setSpacing(0) |
|
93 |
|
94 self.__navigationMenu = QMenu(self) |
|
95 self.__navigationMenu.aboutToShow.connect(self.__showNavigationMenu) |
|
96 self.__navigationMenu.triggered.connect(self.__navigationMenuTriggered) |
|
97 |
|
98 self.__navigationButton = QToolButton(self) |
|
99 self.__navigationButton.setIcon( |
|
100 UI.PixmapCache.getIcon("1downarrow.png")) |
|
101 self.__navigationButton.setToolTip( |
|
102 self.tr("Show a navigation menu")) |
|
103 self.__navigationButton.setPopupMode(QToolButton.InstantPopup) |
|
104 self.__navigationButton.setMenu(self.__navigationMenu) |
|
105 self.__navigationButton.setEnabled(False) |
|
106 self.__rightCornerWidgetLayout.addWidget(self.__navigationButton) |
|
107 |
|
108 # TODO: re-enable once Closed Tabs Manager is done |
|
109 ## self.__closedTabsMenu = QMenu(self) |
|
110 ## self.__closedTabsMenu.aboutToShow.connect( |
|
111 ## self.__aboutToShowClosedTabsMenu) |
|
112 ## |
|
113 ## self.__closedTabsButton = QToolButton(self) |
|
114 ## self.__closedTabsButton.setIcon(UI.PixmapCache.getIcon("trash.png")) |
|
115 ## self.__closedTabsButton.setToolTip( |
|
116 ## self.tr("Show a navigation menu for closed tabs")) |
|
117 ## self.__closedTabsButton.setPopupMode(QToolButton.InstantPopup) |
|
118 ## self.__closedTabsButton.setMenu(self.__closedTabsMenu) |
|
119 ## self.__closedTabsButton.setEnabled(False) |
|
120 ## self.__rightCornerWidgetLayout.addWidget(self.__closedTabsButton) |
|
121 ## |
|
122 self.__closeButton = QToolButton(self) |
|
123 self.__closeButton.setIcon(UI.PixmapCache.getIcon("close.png")) |
|
124 self.__closeButton.setToolTip( |
|
125 self.tr("Close the current web browser")) |
|
126 self.__closeButton.setEnabled(False) |
|
127 self.__closeButton.clicked.connect(self.closeBrowser) |
|
128 self.__rightCornerWidgetLayout.addWidget(self.__closeButton) |
|
129 if Preferences.getUI("SingleCloseButton") or \ |
|
130 not hasattr(self, 'setTabsClosable'): |
|
131 self.__closeButton.show() |
|
132 else: |
|
133 self.setTabsClosable(True) |
|
134 self.tabCloseRequested.connect(self.closeBrowserAt) |
|
135 self.__closeButton.hide() |
|
136 |
|
137 self.setCornerWidget(self.__rightCornerWidget, Qt.TopRightCorner) |
|
138 |
|
139 self.__newTabButton = QToolButton(self) |
|
140 self.__newTabButton.setIcon(UI.PixmapCache.getIcon("plus.png")) |
|
141 self.__newTabButton.setToolTip( |
|
142 self.tr("Open a new web browser tab")) |
|
143 self.setCornerWidget(self.__newTabButton, Qt.TopLeftCorner) |
|
144 self.__newTabButton.clicked.connect(self.__newBrowser) |
|
145 |
|
146 self.__initTabContextMenu() |
|
147 |
|
148 self.__historyCompleter = None |
|
149 |
|
150 def __initTabContextMenu(self): |
|
151 """ |
|
152 Private method to create the tab context menu. |
|
153 """ |
|
154 self.__tabContextMenu = QMenu(self) |
|
155 self.tabContextNewAct = self.__tabContextMenu.addAction( |
|
156 UI.PixmapCache.getIcon("tabNew.png"), |
|
157 self.tr('New Tab'), self.newBrowser) |
|
158 self.__tabContextMenu.addSeparator() |
|
159 self.leftMenuAct = self.__tabContextMenu.addAction( |
|
160 UI.PixmapCache.getIcon("1leftarrow.png"), |
|
161 self.tr('Move Left'), self.__tabContextMenuMoveLeft) |
|
162 self.rightMenuAct = self.__tabContextMenu.addAction( |
|
163 UI.PixmapCache.getIcon("1rightarrow.png"), |
|
164 self.tr('Move Right'), self.__tabContextMenuMoveRight) |
|
165 self.__tabContextMenu.addSeparator() |
|
166 self.tabContextCloneAct = self.__tabContextMenu.addAction( |
|
167 self.tr("Duplicate Page"), self.__tabContextMenuClone) |
|
168 self.__tabContextMenu.addSeparator() |
|
169 self.tabContextCloseAct = self.__tabContextMenu.addAction( |
|
170 UI.PixmapCache.getIcon("tabClose.png"), |
|
171 self.tr('Close'), self.__tabContextMenuClose) |
|
172 self.tabContextCloseOthersAct = self.__tabContextMenu.addAction( |
|
173 UI.PixmapCache.getIcon("tabCloseOther.png"), |
|
174 self.tr("Close Others"), self.__tabContextMenuCloseOthers) |
|
175 self.__tabContextMenu.addAction( |
|
176 self.tr('Close All'), self.closeAllBrowsers) |
|
177 ## self.__tabContextMenu.addSeparator() |
|
178 ## self.__tabContextMenu.addAction( |
|
179 ## UI.PixmapCache.getIcon("printPreview.png"), |
|
180 ## self.tr('Print Preview'), self.__tabContextMenuPrintPreview) |
|
181 ## self.__tabContextMenu.addAction( |
|
182 ## UI.PixmapCache.getIcon("print.png"), |
|
183 ## self.tr('Print'), self.__tabContextMenuPrint) |
|
184 ## self.__tabContextMenu.addAction( |
|
185 ## UI.PixmapCache.getIcon("printPdf.png"), |
|
186 ## self.tr('Print as PDF'), self.__tabContextMenuPrintPdf) |
|
187 self.__tabContextMenu.addSeparator() |
|
188 self.__tabContextMenu.addAction( |
|
189 UI.PixmapCache.getIcon("reload.png"), |
|
190 self.tr('Reload All'), self.reloadAllBrowsers) |
|
191 ## self.__tabContextMenu.addSeparator() |
|
192 ## self.__tabContextMenu.addAction( |
|
193 ## UI.PixmapCache.getIcon("addBookmark.png"), |
|
194 ## self.tr('Bookmark All Tabs'), self.__mainWindow.bookmarkAll) |
|
195 |
|
196 self.__tabBackContextMenu = QMenu(self) |
|
197 self.__tabBackContextMenu.addAction( |
|
198 self.tr('Close All'), self.closeAllBrowsers) |
|
199 self.__tabBackContextMenu.addAction( |
|
200 UI.PixmapCache.getIcon("reload.png"), |
|
201 self.tr('Reload All'), self.reloadAllBrowsers) |
|
202 ## self.__tabBackContextMenu.addAction( |
|
203 ## UI.PixmapCache.getIcon("addBookmark.png"), |
|
204 ## self.tr('Bookmark All Tabs'), self.__mainWindow.bookmarkAll) |
|
205 ## self.__tabBackContextMenu.addSeparator() |
|
206 ## self.__restoreClosedTabAct = self.__tabBackContextMenu.addAction( |
|
207 ## UI.PixmapCache.getIcon("trash.png"), |
|
208 ## self.tr('Restore Closed Tab'), self.restoreClosedTab) |
|
209 ## self.__restoreClosedTabAct.setEnabled(False) |
|
210 ## self.__restoreClosedTabAct.setData(0) |
|
211 |
|
212 def __showContextMenu(self, coord, index): |
|
213 """ |
|
214 Private slot to show the tab context menu. |
|
215 |
|
216 @param coord the position of the mouse pointer (QPoint) |
|
217 @param index index of the tab the menu is requested for (integer) |
|
218 """ |
|
219 coord = self.mapToGlobal(coord) |
|
220 if index == -1: |
|
221 self.__tabBackContextMenu.popup(coord) |
|
222 else: |
|
223 self.__tabContextMenuIndex = index |
|
224 self.leftMenuAct.setEnabled(index > 0) |
|
225 self.rightMenuAct.setEnabled(index < self.count() - 1) |
|
226 |
|
227 self.tabContextCloseOthersAct.setEnabled(self.count() > 1) |
|
228 |
|
229 self.__tabContextMenu.popup(coord) |
|
230 |
|
231 def __tabContextMenuMoveLeft(self): |
|
232 """ |
|
233 Private method to move a tab one position to the left. |
|
234 """ |
|
235 self.moveTab(self.__tabContextMenuIndex, |
|
236 self.__tabContextMenuIndex - 1) |
|
237 |
|
238 def __tabContextMenuMoveRight(self): |
|
239 """ |
|
240 Private method to move a tab one position to the right. |
|
241 """ |
|
242 self.moveTab(self.__tabContextMenuIndex, |
|
243 self.__tabContextMenuIndex + 1) |
|
244 |
|
245 def __tabContextMenuClone(self): |
|
246 """ |
|
247 Private method to clone the selected tab. |
|
248 """ |
|
249 idx = self.__tabContextMenuIndex |
|
250 if idx < 0: |
|
251 idx = self.currentIndex() |
|
252 if idx < 0 or idx > self.count(): |
|
253 return |
|
254 |
|
255 ## req = QNetworkRequest(self.widget(idx).url()) |
|
256 ## req.setRawHeader(b"X-Eric6-UserLoadAction", b"1") |
|
257 ## self.newBrowser(None, (req, QNetworkAccessManager.GetOperation, b"")) |
|
258 url = self.widget(idx).url() |
|
259 self.newBrowser(url) |
|
260 |
|
261 def __tabContextMenuClose(self): |
|
262 """ |
|
263 Private method to close the selected tab. |
|
264 """ |
|
265 self.closeBrowserAt(self.__tabContextMenuIndex) |
|
266 |
|
267 def __tabContextMenuCloseOthers(self): |
|
268 """ |
|
269 Private slot to close all other tabs. |
|
270 """ |
|
271 index = self.__tabContextMenuIndex |
|
272 for i in list(range(self.count() - 1, index, -1)) + \ |
|
273 list(range(index - 1, -1, -1)): |
|
274 self.closeBrowserAt(i) |
|
275 |
|
276 ## def __tabContextMenuPrint(self): |
|
277 ## """ |
|
278 ## Private method to print the selected tab. |
|
279 ## """ |
|
280 ## browser = self.widget(self.__tabContextMenuIndex) |
|
281 ## self.printBrowser(browser) |
|
282 ## |
|
283 ## def __tabContextMenuPrintPdf(self): |
|
284 ## """ |
|
285 ## Private method to print the selected tab as PDF. |
|
286 ## """ |
|
287 ## browser = self.widget(self.__tabContextMenuIndex) |
|
288 ## self.printBrowserPdf(browser) |
|
289 ## |
|
290 ## def __tabContextMenuPrintPreview(self): |
|
291 ## """ |
|
292 ## Private method to show a print preview of the selected tab. |
|
293 ## """ |
|
294 ## browser = self.widget(self.__tabContextMenuIndex) |
|
295 ## self.printPreviewBrowser(browser) |
|
296 ## |
|
297 @pyqtSlot() |
|
298 def __newBrowser(self): |
|
299 """ |
|
300 Private slot to open a new browser tab. |
|
301 """ |
|
302 self.newBrowser() |
|
303 |
|
304 # TODO: remove requestData from signature |
|
305 def newBrowser(self, link=None, requestData=None, position=-1): |
|
306 """ |
|
307 Public method to create a new web browser tab. |
|
308 |
|
309 @param link link to be shown (string or QUrl) |
|
310 @param requestData tuple containing the request data (QNetworkRequest, |
|
311 QNetworkAccessManager.Operation, QByteArray) |
|
312 @keyparam position position to create the new tab at or -1 to add it |
|
313 to the end (integer) |
|
314 """ |
|
315 if link is None: |
|
316 linkName = "" |
|
317 elif isinstance(link, QUrl): |
|
318 linkName = link.toString() |
|
319 else: |
|
320 linkName = link |
|
321 |
|
322 from .UrlBar.UrlBar import UrlBar |
|
323 urlbar = UrlBar(self.__mainWindow, self) |
|
324 ## if self.__historyCompleter is None: |
|
325 ## import Helpviewer.HelpWindow |
|
326 ## from .History.HistoryCompleter import HistoryCompletionModel, \ |
|
327 ## HistoryCompleter |
|
328 ## self.__historyCompletionModel = HistoryCompletionModel(self) |
|
329 ## self.__historyCompletionModel.setSourceModel( |
|
330 ## Helpviewer.HelpWindow.HelpWindow.historyManager() |
|
331 ## .historyFilterModel()) |
|
332 ## self.__historyCompleter = HistoryCompleter( |
|
333 ## self.__historyCompletionModel, self) |
|
334 ## self.__historyCompleter.activated[str].connect(self.__pathSelected) |
|
335 ## urlbar.setCompleter(self.__historyCompleter) |
|
336 urlbar.returnPressed.connect(self.__lineEditReturnPressed) |
|
337 if position == -1: |
|
338 self.__stackedUrlBar.addWidget(urlbar) |
|
339 else: |
|
340 self.__stackedUrlBar.insertWidget(position, urlbar) |
|
341 |
|
342 browser = WebBrowserView(self.__mainWindow, self) |
|
343 urlbar.setBrowser(browser) |
|
344 |
|
345 browser.sourceChanged.connect(self.__sourceChanged) |
|
346 browser.titleChanged.connect(self.__titleChanged) |
|
347 browser.highlighted.connect(self.showMessage) |
|
348 browser.backwardAvailable.connect( |
|
349 self.__mainWindow.setBackwardAvailable) |
|
350 browser.forwardAvailable.connect(self.__mainWindow.setForwardAvailable) |
|
351 browser.loadStarted.connect(self.__loadStarted) |
|
352 browser.loadFinished.connect(self.__loadFinished) |
|
353 browser.iconUrlChanged.connect(self.__iconUrlChanged) |
|
354 browser.search.connect(self.newBrowser) |
|
355 browser.page().windowCloseRequested.connect( |
|
356 self.__windowCloseRequested) |
|
357 ## browser.page().printRequested.connect(self.__printRequested) |
|
358 browser.zoomValueChanged.connect(self.browserZoomValueChanged) |
|
359 |
|
360 if position == -1: |
|
361 index = self.addTab(browser, self.tr("...")) |
|
362 else: |
|
363 index = self.insertTab(position, browser, self.tr("...")) |
|
364 self.setCurrentIndex(index) |
|
365 |
|
366 self.__mainWindow.closeAct.setEnabled(True) |
|
367 self.__mainWindow.closeAllAct.setEnabled(True) |
|
368 self.__closeButton.setEnabled(True) |
|
369 self.__navigationButton.setEnabled(True) |
|
370 |
|
371 ## if not linkName and not requestData: |
|
372 if not linkName: |
|
373 if Preferences.getWebBrowser("StartupBehavior") == 0: |
|
374 linkName = Preferences.getWebBrowser("HomePage") |
|
375 elif Preferences.getWebBrowser("StartupBehavior") == 1: |
|
376 linkName = "eric:speeddial" |
|
377 |
|
378 if linkName: |
|
379 browser.setSource(QUrl(linkName)) |
|
380 if not browser.documentTitle(): |
|
381 self.setTabText(index, self.__elide(linkName, Qt.ElideMiddle)) |
|
382 self.setTabToolTip(index, linkName) |
|
383 else: |
|
384 self.setTabText( |
|
385 index, |
|
386 self.__elide(browser.documentTitle().replace("&", "&&"))) |
|
387 self.setTabToolTip(index, browser.documentTitle()) |
|
388 ## elif requestData: |
|
389 ## browser.load(*requestData) |
|
390 |
|
391 # TODO: remove requestData from signature |
|
392 def newBrowserAfter(self, browser, link=None, requestData=None): |
|
393 """ |
|
394 Public method to create a new web browser tab after a given one. |
|
395 |
|
396 @param browser reference to the browser to add after (WebBrowserView) |
|
397 @param link link to be shown (string or QUrl) |
|
398 @param requestData tuple containing the request data (QNetworkRequest, |
|
399 QNetworkAccessManager.Operation, QByteArray) |
|
400 """ |
|
401 if browser: |
|
402 position = self.indexOf(browser) + 1 |
|
403 else: |
|
404 position = -1 |
|
405 self.newBrowser(link, requestData, position) |
|
406 |
|
407 def __showNavigationMenu(self): |
|
408 """ |
|
409 Private slot to show the navigation button menu. |
|
410 """ |
|
411 self.__navigationMenu.clear() |
|
412 for index in range(self.count()): |
|
413 act = self.__navigationMenu.addAction( |
|
414 self.tabIcon(index), self.tabText(index)) |
|
415 act.setData(index) |
|
416 |
|
417 def __navigationMenuTriggered(self, act): |
|
418 """ |
|
419 Private slot called to handle the navigation button menu selection. |
|
420 |
|
421 @param act reference to the selected action (QAction) |
|
422 """ |
|
423 index = act.data() |
|
424 if index is not None: |
|
425 self.setCurrentIndex(index) |
|
426 |
|
427 def __windowCloseRequested(self): |
|
428 """ |
|
429 Private slot to handle the windowCloseRequested signal of a browser. |
|
430 """ |
|
431 page = self.sender() |
|
432 if page is None: |
|
433 return |
|
434 |
|
435 browser = page.view() |
|
436 if browser is None: |
|
437 return |
|
438 |
|
439 index = self.indexOf(browser) |
|
440 self.closeBrowserAt(index) |
|
441 |
|
442 def reloadAllBrowsers(self): |
|
443 """ |
|
444 Public slot to reload all browsers. |
|
445 """ |
|
446 for index in range(self.count()): |
|
447 browser = self.widget(index) |
|
448 browser and browser.reload() |
|
449 |
|
450 @pyqtSlot() |
|
451 def closeBrowser(self): |
|
452 """ |
|
453 Public slot called to handle the close action. |
|
454 """ |
|
455 self.closeBrowserAt(self.currentIndex()) |
|
456 |
|
457 def closeAllBrowsers(self): |
|
458 """ |
|
459 Public slot called to handle the close all action. |
|
460 """ |
|
461 for index in range(self.count() - 1, -1, -1): |
|
462 self.closeBrowserAt(index) |
|
463 |
|
464 def closeBrowserAt(self, index): |
|
465 """ |
|
466 Public slot to close a browser based on its index. |
|
467 |
|
468 @param index index of browser to close (integer) |
|
469 """ |
|
470 browser = self.widget(index) |
|
471 if browser is None: |
|
472 return |
|
473 |
|
474 ## if browser.isModified(): |
|
475 ## ok = E5MessageBox.yesNo( |
|
476 ## self, |
|
477 ## self.tr("Do you really want to close this page?"), |
|
478 ## self.tr("""You have modified this page and when closing it""" |
|
479 ## """ you would lose the modification.\nDo you really""" |
|
480 ## """ want to close this page?""")) |
|
481 ## if not ok: |
|
482 ## return |
|
483 ## |
|
484 urlbar = self.__stackedUrlBar.widget(index) |
|
485 self.__stackedUrlBar.removeWidget(urlbar) |
|
486 urlbar.deleteLater() |
|
487 del urlbar |
|
488 |
|
489 ## self.__closedTabsManager.recordBrowser(browser, index) |
|
490 ## |
|
491 ## browser.closeWebInspector() |
|
492 browser.home() |
|
493 self.removeTab(index) |
|
494 self.browserClosed.emit(browser) |
|
495 browser.deleteLater() |
|
496 del browser |
|
497 |
|
498 if self.count() == 0: |
|
499 self.newBrowser() |
|
500 else: |
|
501 self.currentChanged[int].emit(self.currentIndex()) |
|
502 |
|
503 def currentBrowser(self): |
|
504 """ |
|
505 Public method to get a reference to the current browser. |
|
506 |
|
507 @return reference to the current browser (WebBrowserView) |
|
508 """ |
|
509 return self.currentWidget() |
|
510 |
|
511 def browserAt(self, index): |
|
512 """ |
|
513 Public method to get a reference to the browser with the given index. |
|
514 |
|
515 @param index index of the browser to get (integer) |
|
516 @return reference to the indexed browser (WebBrowserView) |
|
517 """ |
|
518 return self.widget(index) |
|
519 |
|
520 def browsers(self): |
|
521 """ |
|
522 Public method to get a list of references to all browsers. |
|
523 |
|
524 @return list of references to browsers (list of WebBrowserView) |
|
525 """ |
|
526 li = [] |
|
527 for index in range(self.count()): |
|
528 li.append(self.widget(index)) |
|
529 return li |
|
530 |
|
531 ## @pyqtSlot() |
|
532 ## def printBrowser(self, browser=None): |
|
533 ## """ |
|
534 ## Public slot called to print the displayed page. |
|
535 ## |
|
536 ## @param browser reference to the browser to be printed (WebBrowserView) |
|
537 ## """ |
|
538 ## if browser is None: |
|
539 ## browser = self.currentBrowser() |
|
540 ## |
|
541 ## self.__printRequested(browser.page().mainFrame()) |
|
542 ## |
|
543 ## def __printRequested(self, frame): |
|
544 ## """ |
|
545 ## Private slot to handle a print request. |
|
546 ## |
|
547 ## @param frame reference to the frame to be printed (QWebFrame) |
|
548 ## """ |
|
549 ## printer = QPrinter(mode=QPrinter.HighResolution) |
|
550 ## if Preferences.getPrinter("ColorMode"): |
|
551 ## printer.setColorMode(QPrinter.Color) |
|
552 ## else: |
|
553 ## printer.setColorMode(QPrinter.GrayScale) |
|
554 ## if Preferences.getPrinter("FirstPageFirst"): |
|
555 ## printer.setPageOrder(QPrinter.FirstPageFirst) |
|
556 ## else: |
|
557 ## printer.setPageOrder(QPrinter.LastPageFirst) |
|
558 ## printer.setPageMargins( |
|
559 ## Preferences.getPrinter("LeftMargin") * 10, |
|
560 ## Preferences.getPrinter("TopMargin") * 10, |
|
561 ## Preferences.getPrinter("RightMargin") * 10, |
|
562 ## Preferences.getPrinter("BottomMargin") * 10, |
|
563 ## QPrinter.Millimeter |
|
564 ## ) |
|
565 ## printerName = Preferences.getPrinter("PrinterName") |
|
566 ## if printerName: |
|
567 ## printer.setPrinterName(printerName) |
|
568 ## |
|
569 ## printDialog = QPrintDialog(printer, self) |
|
570 ## if printDialog.exec_() == QDialog.Accepted: |
|
571 ## try: |
|
572 ## frame.print_(printer) |
|
573 ## except AttributeError: |
|
574 ## E5MessageBox.critical( |
|
575 ## self, |
|
576 ## self.tr("eric6 Web Browser"), |
|
577 ## self.tr( |
|
578 ## """<p>Printing is not available due to a bug in""" |
|
579 ## """ PyQt5. Please upgrade.</p>""")) |
|
580 ## return |
|
581 ## |
|
582 ## @pyqtSlot() |
|
583 ## def printBrowserPdf(self, browser=None): |
|
584 ## """ |
|
585 ## Public slot called to print the displayed page to PDF. |
|
586 ## |
|
587 ## @param browser reference to the browser to be printed (HelpBrowser) |
|
588 ## """ |
|
589 ## if browser is None: |
|
590 ## browser = self.currentBrowser() |
|
591 ## |
|
592 ## self.__printPdfRequested(browser.page().mainFrame()) |
|
593 ## |
|
594 ## def __printPdfRequested(self, frame): |
|
595 ## """ |
|
596 ## Private slot to handle a print to PDF request. |
|
597 ## |
|
598 ## @param frame reference to the frame to be printed (QWebFrame) |
|
599 ## """ |
|
600 ## printer = QPrinter(mode=QPrinter.HighResolution) |
|
601 ## if Preferences.getPrinter("ColorMode"): |
|
602 ## printer.setColorMode(QPrinter.Color) |
|
603 ## else: |
|
604 ## printer.setColorMode(QPrinter.GrayScale) |
|
605 ## printerName = Preferences.getPrinter("PrinterName") |
|
606 ## if printerName: |
|
607 ## printer.setPrinterName(printerName) |
|
608 ## printer.setOutputFormat(QPrinter.PdfFormat) |
|
609 ## name = frame.url().path().rsplit('/', 1)[-1] |
|
610 ## if name: |
|
611 ## name = name.rsplit('.', 1)[0] |
|
612 ## name += '.pdf' |
|
613 ## printer.setOutputFileName(name) |
|
614 ## |
|
615 ## printDialog = QPrintDialog(printer, self) |
|
616 ## if printDialog.exec_() == QDialog.Accepted: |
|
617 ## try: |
|
618 ## frame.print_(printer) |
|
619 ## except AttributeError: |
|
620 ## E5MessageBox.critical( |
|
621 ## self, |
|
622 ## self.tr("eric6 Web Browser"), |
|
623 ## self.tr( |
|
624 ## """<p>Printing is not available due to a bug in""" |
|
625 ## """ PyQt5. Please upgrade.</p>""")) |
|
626 ## return |
|
627 ## |
|
628 ## @pyqtSlot() |
|
629 ## def printPreviewBrowser(self, browser=None): |
|
630 ## """ |
|
631 ## Public slot called to show a print preview of the displayed file. |
|
632 ## |
|
633 ## @param browser reference to the browser to be printed (HelpBrowserWV) |
|
634 ## """ |
|
635 ## from PyQt5.QtPrintSupport import QPrintPreviewDialog |
|
636 ## |
|
637 ## if browser is None: |
|
638 ## browser = self.currentBrowser() |
|
639 ## |
|
640 ## printer = QPrinter(mode=QPrinter.HighResolution) |
|
641 ## if Preferences.getPrinter("ColorMode"): |
|
642 ## printer.setColorMode(QPrinter.Color) |
|
643 ## else: |
|
644 ## printer.setColorMode(QPrinter.GrayScale) |
|
645 ## if Preferences.getPrinter("FirstPageFirst"): |
|
646 ## printer.setPageOrder(QPrinter.FirstPageFirst) |
|
647 ## else: |
|
648 ## printer.setPageOrder(QPrinter.LastPageFirst) |
|
649 ## printer.setPageMargins( |
|
650 ## Preferences.getPrinter("LeftMargin") * 10, |
|
651 ## Preferences.getPrinter("TopMargin") * 10, |
|
652 ## Preferences.getPrinter("RightMargin") * 10, |
|
653 ## Preferences.getPrinter("BottomMargin") * 10, |
|
654 ## QPrinter.Millimeter |
|
655 ## ) |
|
656 ## printerName = Preferences.getPrinter("PrinterName") |
|
657 ## if printerName: |
|
658 ## printer.setPrinterName(printerName) |
|
659 ## |
|
660 ## self.__printPreviewBrowser = browser |
|
661 ## preview = QPrintPreviewDialog(printer, self) |
|
662 ## preview.paintRequested.connect(self.__printPreview) |
|
663 ## preview.exec_() |
|
664 ## |
|
665 ## def __printPreview(self, printer): |
|
666 ## """ |
|
667 ## Private slot to generate a print preview. |
|
668 ## |
|
669 ## @param printer reference to the printer object (QPrinter) |
|
670 ## """ |
|
671 ## try: |
|
672 ## self.__printPreviewBrowser.print_(printer) |
|
673 ## except AttributeError: |
|
674 ## E5MessageBox.critical( |
|
675 ## self, |
|
676 ## self.tr("eric6 Web Browser"), |
|
677 ## self.tr( |
|
678 ## """<p>Printing is not available due to a bug in PyQt5.""" |
|
679 ## """Please upgrade.</p>""")) |
|
680 ## return |
|
681 ## |
|
682 def __sourceChanged(self, url): |
|
683 """ |
|
684 Private slot to handle a change of a browsers source. |
|
685 |
|
686 @param url URL of the new site (QUrl) |
|
687 """ |
|
688 browser = self.sender() |
|
689 |
|
690 if browser is not None: |
|
691 self.sourceChanged.emit(browser, url) |
|
692 |
|
693 def __titleChanged(self, title): |
|
694 """ |
|
695 Private slot to handle a change of a browsers title. |
|
696 |
|
697 @param title new title (string) |
|
698 """ |
|
699 browser = self.sender() |
|
700 |
|
701 if browser is not None and isinstance(browser, QWidget): |
|
702 index = self.indexOf(browser) |
|
703 if title == "": |
|
704 title = browser.url().toString() |
|
705 |
|
706 self.setTabText(index, self.__elide(title.replace("&", "&&"))) |
|
707 self.setTabToolTip(index, title) |
|
708 |
|
709 self.titleChanged.emit(browser, title) |
|
710 |
|
711 def __elide(self, txt, mode=Qt.ElideRight, length=40): |
|
712 """ |
|
713 Private method to elide some text. |
|
714 |
|
715 @param txt text to be elided (string) |
|
716 @keyparam mode elide mode (Qt.TextElideMode) |
|
717 @keyparam length amount of characters to be used (integer) |
|
718 @return the elided text (string) |
|
719 """ |
|
720 if mode == Qt.ElideNone or len(txt) < length: |
|
721 return txt |
|
722 elif mode == Qt.ElideLeft: |
|
723 return "...{0}".format(txt[-length:]) |
|
724 elif mode == Qt.ElideMiddle: |
|
725 return "{0}...{1}".format(txt[:length // 2], txt[-(length // 2):]) |
|
726 elif mode == Qt.ElideRight: |
|
727 return "{0}...".format(txt[:length]) |
|
728 else: |
|
729 # just in case |
|
730 return txt |
|
731 |
|
732 def preferencesChanged(self): |
|
733 """ |
|
734 Public slot to handle a change of preferences. |
|
735 """ |
|
736 for browser in self.browsers(): |
|
737 browser.preferencesChanged() |
|
738 |
|
739 for urlbar in self.__stackedUrlBar.urlBars(): |
|
740 urlbar.preferencesChanged() |
|
741 |
|
742 if Preferences.getUI("SingleCloseButton"): |
|
743 self.setTabsClosable(False) |
|
744 try: |
|
745 self.tabCloseRequested.disconnect(self.closeBrowserAt) |
|
746 except TypeError: |
|
747 pass |
|
748 self.__closeButton.show() |
|
749 else: |
|
750 self.setTabsClosable(True) |
|
751 self.tabCloseRequested.connect(self.closeBrowserAt) |
|
752 self.__closeButton.hide() |
|
753 |
|
754 def __loadStarted(self): |
|
755 """ |
|
756 Private method to handle the loadStarted signal. |
|
757 """ |
|
758 browser = self.sender() |
|
759 |
|
760 if browser is not None: |
|
761 index = self.indexOf(browser) |
|
762 anim = self.animationLabel( |
|
763 index, os.path.join(getConfig("ericPixDir"), "loading.gif"), |
|
764 100) |
|
765 if not anim: |
|
766 loading = QIcon(os.path.join(getConfig("ericPixDir"), |
|
767 "loading.gif")) |
|
768 self.setTabIcon(index, loading) |
|
769 else: |
|
770 self.setTabIcon(index, QIcon()) |
|
771 self.setTabText(index, self.tr("Loading...")) |
|
772 self.setTabToolTip(index, self.tr("Loading...")) |
|
773 self.showMessage.emit(self.tr("Loading...")) |
|
774 |
|
775 self.__mainWindow.setLoadingActions(True) |
|
776 |
|
777 def __loadFinished(self, ok): |
|
778 """ |
|
779 Private method to handle the loadFinished signal. |
|
780 |
|
781 @param ok flag indicating the result (boolean) |
|
782 """ |
|
783 browser = self.sender() |
|
784 if not isinstance(browser, WebBrowserView): |
|
785 return |
|
786 |
|
787 if browser is not None: |
|
788 import WebBrowser.WebBrowserWindow |
|
789 index = self.indexOf(browser) |
|
790 self.resetAnimation(index) |
|
791 self.setTabIcon( |
|
792 index, WebBrowser.WebBrowserWindow.WebBrowserWindow.icon( |
|
793 browser.url())) |
|
794 if ok: |
|
795 self.showMessage.emit(self.tr("Finished loading")) |
|
796 else: |
|
797 self.showMessage.emit(self.tr("Failed to load")) |
|
798 |
|
799 self.__mainWindow.setLoadingActions(False) |
|
800 |
|
801 def __iconUrlChanged(self, url): |
|
802 """ |
|
803 Private slot to handle a change of the icon URL. |
|
804 |
|
805 @param url URL of the icon |
|
806 @type QUrl |
|
807 """ |
|
808 browser = self.sender() |
|
809 |
|
810 if browser is not None and isinstance(browser, QWidget): |
|
811 import WebBrowser.WebBrowserWindow |
|
812 self.setTabIcon( |
|
813 self.indexOf(browser), |
|
814 WebBrowser.WebBrowserWindow.WebBrowserWindow.icon(url)) |
|
815 WebBrowser.WebBrowserWindow.WebBrowserWindow.bookmarksManager()\ |
|
816 .iconChanged(url) |
|
817 |
|
818 def getSourceFileList(self): |
|
819 """ |
|
820 Public method to get a list of all opened Qt help files. |
|
821 |
|
822 @return dictionary with tab id as key and host/namespace as value |
|
823 """ |
|
824 sourceList = {} |
|
825 for i in range(self.count()): |
|
826 browser = self.widget(i) |
|
827 if browser is not None and \ |
|
828 browser.source().isValid(): |
|
829 sourceList[i] = browser.source().host() |
|
830 |
|
831 return sourceList |
|
832 |
|
833 def shallShutDown(self): |
|
834 """ |
|
835 Public method to check, if the application should be shut down. |
|
836 |
|
837 @return flag indicating a shut down (boolean) |
|
838 """ |
|
839 if self.count() > 1 and Preferences.getHelp("WarnOnMultipleClose"): |
|
840 mb = E5MessageBox.E5MessageBox( |
|
841 E5MessageBox.Information, |
|
842 self.tr("Are you sure you want to close the window?"), |
|
843 self.tr("""Are you sure you want to close the window?\n""" |
|
844 """You have %n tab(s) open.""", "", self.count()), |
|
845 modal=True, |
|
846 parent=self) |
|
847 if self.__mainWindow.fromEric: |
|
848 quitButton = mb.addButton( |
|
849 self.tr("&Close"), E5MessageBox.AcceptRole) |
|
850 quitButton.setIcon(UI.PixmapCache.getIcon("close.png")) |
|
851 else: |
|
852 quitButton = mb.addButton( |
|
853 self.tr("&Quit"), E5MessageBox.AcceptRole) |
|
854 quitButton.setIcon(UI.PixmapCache.getIcon("exit.png")) |
|
855 closeTabButton = mb.addButton( |
|
856 self.tr("C&lose Current Tab"), E5MessageBox.AcceptRole) |
|
857 closeTabButton.setIcon(UI.PixmapCache.getIcon("tabClose.png")) |
|
858 mb.addButton(E5MessageBox.Cancel) |
|
859 mb.exec_() |
|
860 if mb.clickedButton() == quitButton: |
|
861 return True |
|
862 else: |
|
863 if mb.clickedButton() == closeTabButton: |
|
864 self.closeBrowser() |
|
865 return False |
|
866 |
|
867 return True |
|
868 |
|
869 def stackedUrlBar(self): |
|
870 """ |
|
871 Public method to get a reference to the stacked url bar. |
|
872 |
|
873 @return reference to the stacked url bar (StackedUrlBar) |
|
874 """ |
|
875 return self.__stackedUrlBar |
|
876 |
|
877 def currentUrlBar(self): |
|
878 """ |
|
879 Public method to get a reference to the current url bar. |
|
880 |
|
881 @return reference to the current url bar (UrlBar) |
|
882 """ |
|
883 return self.__stackedUrlBar.currentWidget() |
|
884 |
|
885 def __lineEditReturnPressed(self): |
|
886 """ |
|
887 Private slot to handle the entering of an URL. |
|
888 """ |
|
889 edit = self.sender() |
|
890 url = self.__guessUrlFromPath(edit.text()) |
|
891 ## request = QNetworkRequest(url) |
|
892 ## request.setRawHeader(b"X-Eric6-UserLoadAction", b"1") |
|
893 if e5App().keyboardModifiers() == Qt.AltModifier: |
|
894 self.newBrowser(url) |
|
895 ## self.newBrowser( |
|
896 ## None, (request, QNetworkAccessManager.GetOperation, b"")) |
|
897 else: |
|
898 self.currentBrowser().setSource(url) |
|
899 ## self.currentBrowser().setSource( |
|
900 ## None, (request, QNetworkAccessManager.GetOperation, b"")) |
|
901 self.currentBrowser().setFocus() |
|
902 |
|
903 ## def __pathSelected(self, path): |
|
904 ## """ |
|
905 ## Private slot called when a URL is selected from the completer. |
|
906 ## |
|
907 ## @param path path to be shown (string) |
|
908 ## """ |
|
909 ## url = self.__guessUrlFromPath(path) |
|
910 ## self.currentBrowser().setSource(url) |
|
911 |
|
912 def __guessUrlFromPath(self, path): |
|
913 """ |
|
914 Private method to guess an URL given a path string. |
|
915 |
|
916 @param path path string to guess an URL for (string) |
|
917 @return guessed URL (QUrl) |
|
918 """ |
|
919 # TODO: re-enable once Open Search is done |
|
920 ## manager = self.__mainWindow.openSearchManager() |
|
921 ## path = Utilities.fromNativeSeparators(path) |
|
922 ## url = manager.convertKeywordSearchToUrl(path) |
|
923 ## if url.isValid(): |
|
924 ## return url |
|
925 |
|
926 try: |
|
927 url = QUrl.fromUserInput(path) |
|
928 except AttributeError: |
|
929 url = QUrl(path) |
|
930 |
|
931 if url.scheme() == "about" and \ |
|
932 url.path() == "home": |
|
933 url = QUrl("eric:home") |
|
934 |
|
935 # TODO: extend this logic to about:config (open config dialog) |
|
936 |
|
937 ## if url.scheme() in ["s", "search"]: |
|
938 ## url = manager.currentEngine().searchUrl(url.path().strip()) |
|
939 |
|
940 if url.scheme() != "" and \ |
|
941 (url.host() != "" or url.path() != ""): |
|
942 return url |
|
943 |
|
944 urlString = Preferences.getWebBrowser("DefaultScheme") + path.strip() |
|
945 url = QUrl.fromEncoded(urlString.encode("utf-8"), QUrl.TolerantMode) |
|
946 |
|
947 return url |
|
948 |
|
949 def __currentChanged(self, index): |
|
950 """ |
|
951 Private slot to handle an index change. |
|
952 |
|
953 @param index new index (integer) |
|
954 """ |
|
955 self.__stackedUrlBar.setCurrentIndex(index) |
|
956 |
|
957 browser = self.browserAt(index) |
|
958 if browser is not None: |
|
959 if browser.url() == "" and browser.hasFocus(): |
|
960 self.__stackedUrlBar.currentWidget.setFocus() |
|
961 elif browser.url() != "": |
|
962 browser.setFocus() |
|
963 |
|
964 # TODO: re-enable once Closed Tabs Manager is done |
|
965 ## def restoreClosedTab(self): |
|
966 ## """ |
|
967 ## Public slot to restore the most recently closed tab. |
|
968 ## """ |
|
969 ## if not self.canRestoreClosedTab(): |
|
970 ## return |
|
971 ## |
|
972 ## act = self.sender() |
|
973 ## tab = self.__closedTabsManager.getClosedTabAt(act.data()) |
|
974 ## |
|
975 ## self.newBrowser(tab.url.toString(), position=tab.position) |
|
976 ## |
|
977 ## def canRestoreClosedTab(self): |
|
978 ## """ |
|
979 ## Public method to check, if closed tabs can be restored. |
|
980 ## |
|
981 ## @return flag indicating that closed tabs can be restored (boolean) |
|
982 ## """ |
|
983 ## return self.__closedTabsManager.isClosedTabAvailable() |
|
984 ## |
|
985 ## def restoreAllClosedTabs(self): |
|
986 ## """ |
|
987 ## Public slot to restore all closed tabs. |
|
988 ## """ |
|
989 ## if not self.canRestoreClosedTab(): |
|
990 ## return |
|
991 ## |
|
992 ## for tab in self.__closedTabsManager.allClosedTabs(): |
|
993 ## self.newBrowser(tab.url.toString(), position=tab.position) |
|
994 ## self.__closedTabsManager.clearList() |
|
995 ## |
|
996 ## def clearClosedTabsList(self): |
|
997 ## """ |
|
998 ## Public slot to clear the list of closed tabs. |
|
999 ## """ |
|
1000 ## self.__closedTabsManager.clearList() |
|
1001 ## |
|
1002 ## def __aboutToShowClosedTabsMenu(self): |
|
1003 ## """ |
|
1004 ## Private slot to populate the closed tabs menu. |
|
1005 ## """ |
|
1006 ## fm = self.__closedTabsMenu.fontMetrics() |
|
1007 ## maxWidth = fm.width('m') * 40 |
|
1008 ## |
|
1009 ## self.__closedTabsMenu.clear() |
|
1010 ## index = 0 |
|
1011 ## for tab in self.__closedTabsManager.allClosedTabs(): |
|
1012 ## title = fm.elidedText(tab.title, Qt.ElideRight, maxWidth) |
|
1013 ## self.__closedTabsMenu.addAction( |
|
1014 ## self.__mainWindow.icon(tab.url), title, |
|
1015 ## self.restoreClosedTab).setData(index) |
|
1016 ## index += 1 |
|
1017 ## self.__closedTabsMenu.addSeparator() |
|
1018 ## self.__closedTabsMenu.addAction( |
|
1019 ## self.tr("Restore All Closed Tabs"), self.restoreAllClosedTabs) |
|
1020 ## self.__closedTabsMenu.addAction( |
|
1021 ## self.tr("Clear List"), self.clearClosedTabsList) |
|
1022 ## |
|
1023 ## def closedTabsManager(self): |
|
1024 ## """ |
|
1025 ## Public slot to get a reference to the closed tabs manager. |
|
1026 ## |
|
1027 ## @return reference to the closed tabs manager (ClosedTabsManager) |
|
1028 ## """ |
|
1029 ## return self.__closedTabsManager |
|
1030 ## |
|
1031 ## def __closedTabAvailable(self, avail): |
|
1032 ## """ |
|
1033 ## Private slot to handle changes of the availability of closed tabs. |
|
1034 ## |
|
1035 ## @param avail flag indicating the availability of closed tabs (boolean) |
|
1036 ## """ |
|
1037 ## self.__closedTabsButton.setEnabled(avail) |
|
1038 ## self.__restoreClosedTabAct.setEnabled(avail) |