Helpviewer/HelpTabWidget.py

changeset 638
265c31231d9d
child 641
b06d4df23797
equal deleted inserted replaced
637:4e4c729e86cf 638:265c31231d9d
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2010 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the central widget showing the web pages.
8 """
9
10 import os
11
12 from PyQt4.QtCore import pyqtSignal, Qt, QUrl
13 from PyQt4.QtGui import QWidget, QHBoxLayout, QMenu, QToolButton, QPrinter, \
14 QPrintDialog, QDialog, QIcon
15
16 from E5Gui.E5TabWidget import E5TabWidget
17 from E5Gui import E5MessageBox
18
19 from .HelpTabBar import HelpTabBar
20 from .HelpBrowserWV import HelpBrowser
21
22 import UI.PixmapCache
23
24 import Preferences
25
26 from eric5config import getConfig
27
28 class HelpTabWidget(E5TabWidget):
29 """
30 Class implementing the central widget showing the web pages.
31 """
32 sourceChanged = pyqtSignal(QUrl)
33 titleChanged = pyqtSignal(str)
34 showMessage = pyqtSignal(str)
35
36 def __init__(self, parent):
37 """
38 Constructor
39
40 @param parent reference to the parent widget (QWidget)
41 """
42 E5TabWidget.__init__(self, parent, dnd = True)
43 self.setCustomTabBar(True, HelpTabBar(self))
44
45 self.__mainWindow = parent
46
47 self.__tabContextMenuIndex = -1
48 ## self.currentChanged[int].connect(self.__currentChanged)
49 self.setTabContextMenuPolicy(Qt.CustomContextMenu)
50 self.customTabContextMenuRequested.connect(self.__showContextMenu)
51
52 self.__rightCornerWidget = QWidget(self)
53 self.__rightCornerWidgetLayout = QHBoxLayout(self.__rightCornerWidget)
54 self.__rightCornerWidgetLayout.setMargin(0)
55 self.__rightCornerWidgetLayout.setSpacing(0)
56
57 self.__navigationMenu = QMenu(self)
58 self.__navigationMenu.aboutToShow.connect(self.__showNavigationMenu)
59 self.__navigationMenu.triggered.connect(self.__navigationMenuTriggered)
60
61 self.__navigationButton = QToolButton(self)
62 self.__navigationButton.setIcon(UI.PixmapCache.getIcon("1downarrow.png"))
63 self.__navigationButton.setToolTip(self.trUtf8("Show a navigation menu"))
64 self.__navigationButton.setPopupMode(QToolButton.InstantPopup)
65 self.__navigationButton.setMenu(self.__navigationMenu)
66 self.__navigationButton.setEnabled(False)
67 self.__rightCornerWidgetLayout.addWidget(self.__navigationButton)
68
69 if Preferences.getUI("SingleCloseButton") or \
70 not hasattr(self, 'setTabsClosable'):
71 self.__closeButton = QToolButton(self)
72 self.__closeButton.setIcon(UI.PixmapCache.getIcon("close.png"))
73 self.__closeButton.setToolTip(self.trUtf8("Close the current help window"))
74 self.__closeButton.setEnabled(False)
75 self.__closeButton.clicked[bool].connect(self.closeBrowser)
76 self.__rightCornerWidgetLayout.addWidget(self.__closeButton)
77 else:
78 self.setTabsClosable(True)
79 self.tabCloseRequested.connect(self.closeBrowserAt)
80 self.__closeButton = None
81
82 self.setCornerWidget(self.__rightCornerWidget, Qt.TopRightCorner)
83
84 self.__newTabButton = QToolButton(self)
85 self.__newTabButton.setIcon(UI.PixmapCache.getIcon("new.png"))
86 self.__newTabButton.setToolTip(self.trUtf8("Open a new help window tab"))
87 self.setCornerWidget(self.__newTabButton, Qt.TopLeftCorner)
88 self.__newTabButton.clicked[bool].connect(self.newBrowser)
89
90 self.__initTabContextMenu()
91
92 def __initTabContextMenu(self):
93 """
94 Private mezhod to create the tab context menu.
95 """
96 self.__tabContextMenu = QMenu(self)
97 self.tabContextNewAct = \
98 self.__tabContextMenu.addAction(UI.PixmapCache.getIcon("tabNew.png"),
99 self.trUtf8('New Tab'), self.newBrowser)
100 self.__tabContextMenu.addSeparator()
101 self.leftMenuAct = \
102 self.__tabContextMenu.addAction(UI.PixmapCache.getIcon("1leftarrow.png"),
103 self.trUtf8('Move Left'), self.__tabContextMenuMoveLeft)
104 self.rightMenuAct = \
105 self.__tabContextMenu.addAction(UI.PixmapCache.getIcon("1rightarrow.png"),
106 self.trUtf8('Move Right'), self.__tabContextMenuMoveRight)
107 self.__tabContextMenu.addSeparator()
108 self.tabContextCloneAct = \
109 self.__tabContextMenu.addAction(self.trUtf8("Duplicate Page"),
110 self.__tabContextMenuClone)
111 self.__tabContextMenu.addSeparator()
112 self.tabContextCloseAct = \
113 self.__tabContextMenu.addAction(UI.PixmapCache.getIcon("tabClose.png"),
114 self.trUtf8('Close'), self.__tabContextMenuClose)
115 self.tabContextCloseOthersAct = \
116 self.__tabContextMenu.addAction(UI.PixmapCache.getIcon("tabCloseOther.png"),
117 self.trUtf8("Close Others"), self.__tabContextMenuCloseOthers)
118 self.__tabContextMenu.addAction(self.trUtf8('Close All'),
119 self.closeAllBrowsers)
120 self.__tabContextMenu.addSeparator()
121 self.__tabContextMenu.addAction(UI.PixmapCache.getIcon("printPreview.png"),
122 self.trUtf8('Print Preview'), self.__tabContextMenuPrintPreview)
123 self.__tabContextMenu.addAction(UI.PixmapCache.getIcon("print.png"),
124 self.trUtf8('Print'), self.__tabContextMenuPrint)
125 self.__tabContextMenu.addAction(UI.PixmapCache.getIcon("printPdf.png"),
126 self.trUtf8('Print as PDF'), self.__tabContextMenuPrintPdf)
127 self.__tabContextMenu.addSeparator()
128 self.__tabContextMenu.addAction(self.trUtf8('Bookmark All Tabs'),
129 self.__mainWindow.bookmarkAll)
130
131 def __showContextMenu(self, coord, index):
132 """
133 Private slot to show the tab context menu.
134
135 @param coord the position of the mouse pointer (QPoint)
136 @param index index of the tab the menu is requested for (integer)
137 """
138 self.__tabContextMenuIndex = index
139 self.leftMenuAct.setEnabled(index > 0)
140 self.rightMenuAct.setEnabled(index < self.count() - 1)
141
142 self.tabContextCloseOthersAct.setEnabled(self.count() > 1)
143
144 coord = self.mapToGlobal(coord)
145 self.__tabContextMenu.popup(coord)
146
147 def __tabContextMenuMoveLeft(self):
148 """
149 Private method to move a tab one position to the left.
150 """
151 self.moveTab(self.__tabContextMenuIndex, self.__tabContextMenuIndex - 1)
152
153 def __tabContextMenuMoveRight(self):
154 """
155 Private method to move a tab one position to the right.
156 """
157 self.moveTab(self.__tabContextMenuIndex, self.__tabContextMenuIndex + 1)
158
159 def __tabContextMenuClone(self):
160 """
161 Private method to clone the selected tab.
162 """
163 idx = self.__tabContextMenuIndex
164 if idx < 0:
165 idx = self.currentIndex()
166 if idx < 0 or idx > self.count():
167 return
168
169 self.newBrowser(self.widget(idx).url())
170
171 def __tabContextMenuClose(self):
172 """
173 Private method to close the selected tab.
174 """
175 self.closeBrowserAt(self.__tabContextMenuIndex)
176
177 def __tabContextMenuCloseOthers(self):
178 """
179 Private slot to close all other tabs.
180 """
181 index = self.__tabContextMenuIndex
182 for i in list(range(self.count() - 1, index, -1)) + \
183 list(range(index - 1, -1, -1)):
184 self.closeBrowserAt(i)
185
186 def __tabContextMenuPrint(self):
187 """
188 Private method to print the selected tab.
189 """
190 browser = self.widget(self.__tabContextMenuIndex)
191 self.printBrowser(browser)
192
193 def __tabContextMenuPrintPdf(self):
194 """
195 Private method to print the selected tab as PDF.
196 """
197 browser = self.widget(self.__tabContextMenuIndex)
198 self.printBrowserPdf(browser)
199
200 def __tabContextMenuPrintPreview(self):
201 """
202 Private method to show a print preview of the selected tab.
203 """
204 browser = self.widget(self.__tabContextMenuIndex)
205 self.printPreviewBrowser(browser)
206
207 def newBrowser(self, link = None):
208 """
209 Public method to create a new web browser tab.
210
211 @param link link to be shown (string or QUrl)
212 """
213 if link is None:
214 linkName = ""
215 elif isinstance(link, QUrl):
216 linkName = link.toString()
217 else:
218 linkName = link
219
220 browser = HelpBrowser(self.__mainWindow, self)
221
222 browser.sourceChanged.connect(self.__sourceChanged)
223 browser.titleChanged.connect(self.__titleChanged)
224
225 index = self.addTab(browser, self.trUtf8("..."))
226 self.setCurrentIndex(index)
227
228 if not linkName and Preferences.getHelp("StartupBehavior") == 0:
229 linkName = Preferences.getHelp("HomePage")
230
231 if linkName:
232 browser.setSource(QUrl(linkName))
233 if not browser.documentTitle():
234 self.setTabText(index, self.__elide(linkName, Qt.ElideMiddle))
235 self.setTabToolTip(index, linkName)
236 else:
237 self.setTabText(index,
238 self.__elide(browser.documentTitle().replace("&", "&&")))
239 self.setTabToolTip(index, browser.documentTitle())
240
241 browser.highlighted.connect(self.showMessage)
242 browser.backwardAvailable.connect(self.__mainWindow.setBackwardAvailable)
243 browser.forwardAvailable.connect(self.__mainWindow.setForwardAvailable)
244 browser.loadStarted.connect(self.__loadStarted)
245 browser.loadFinished.connect(self.__loadFinished)
246 browser.iconChanged.connect(self.__iconChanged)
247 browser.page().windowCloseRequested.connect(self.__windowCloseRequested)
248 browser.page().printRequested.connect(self.__printRequested)
249 browser.search.connect(self.newBrowser)
250
251 self.__mainWindow.closeAct.setEnabled(True)
252 self.__mainWindow.closeAllAct.setEnabled(True)
253 self.__closeButton and self.__closeButton.setEnabled(True)
254 self.__navigationButton.setEnabled(True)
255
256 def __showNavigationMenu(self):
257 """
258 Private slot to show the navigation button menu.
259 """
260 self.__navigationMenu.clear()
261 for index in range(self.count()):
262 act = self.__navigationMenu.addAction(
263 self.tabIcon(index), self.tabText(index))
264 act.setData(index)
265
266 def __navigationMenuTriggered(self, act):
267 """
268 Private slot called to handle the navigation button menu selection.
269
270 @param act reference to the selected action (QAction)
271 """
272 index = act.data()
273 if index is not None:
274 self.setCurrentIndex(index)
275
276 def __windowCloseRequested(self):
277 """
278 Private slot to handle the windowCloseRequested signal of a browser.
279 """
280 page = self.sender()
281 if page is None:
282 return
283
284 browser = page.view()
285 if browser is None:
286 return
287
288 index = self.indexOf(browser)
289 self.closeBrowserAt(index)
290
291 def closeBrowser(self):
292 """
293 Public slot called to handle the close action.
294 """
295 self.closeBrowserAt(self.currentIndex())
296
297 def closeAllBrowsers(self):
298 """
299 Public slot called to handle the close all action.
300 """
301 for index in range(self.count() - 1, -1, -1):
302 self.closeBrowserAt(index)
303
304 def closeBrowserAt(self, index):
305 """
306 Public slot to close a browser based on it's index.
307
308 @param index index of browser to close (integer)
309 """
310 browser = self.widget(index)
311 self.removeTab(index)
312 del browser
313 if self.count() == 0:
314 self.newBrowser()
315 else:
316 self.currentChanged[int].emit(self.currentIndex())
317
318 def currentBrowser(self):
319 """
320 Public method to get a reference to the current browser.
321
322 @return reference to the current browser (HelpBrowser)
323 """
324 return self.currentWidget()
325
326 def browserAt(self, index):
327 """
328 Public method to get a reference to the browser with the given index.
329
330 @param index index of the browser to get (integer)
331 @return reference to the indexed browser (HelpBrowser)
332 """
333 return self.widget(index)
334
335 def browsers(self):
336 """
337 Public method to get a list of references to all browsers.
338
339 @return list of references to browsers (list of HelpBrowser)
340 """
341 l = []
342 for index in range(self.count()):
343 l.append(self.widget(index))
344 return l
345
346 def printBrowser(self, browser = None):
347 """
348 Public slot called to print the displayed page.
349
350 @param browser reference to the browser to be printed (HelpBrowser)
351 """
352 if browser is None:
353 browser = self.currentBrowser()
354
355 self.__printRequested(browser.page().mainFrame())
356
357 def __printRequested(self, frame):
358 """
359 Private slot to handle a print request.
360
361 @param frame reference to the frame to be printed (QWebFrame)
362 """
363 printer = QPrinter(mode = QPrinter.HighResolution)
364 if Preferences.getPrinter("ColorMode"):
365 printer.setColorMode(QPrinter.Color)
366 else:
367 printer.setColorMode(QPrinter.GrayScale)
368 if Preferences.getPrinter("FirstPageFirst"):
369 printer.setPageOrder(QPrinter.FirstPageFirst)
370 else:
371 printer.setPageOrder(QPrinter.LastPageFirst)
372 printer.setPrinterName(Preferences.getPrinter("PrinterName"))
373
374 printDialog = QPrintDialog(printer, self)
375 if printDialog.exec_() == QDialog.Accepted:
376 try:
377 frame.print_(printer)
378 except AttributeError:
379 E5MessageBox.critical(self,
380 self.trUtf8("Eric Web Browser"),
381 self.trUtf8("""<p>Printing is not available due to a bug in PyQt4."""
382 """Please upgrade.</p>"""))
383 return
384
385 def printBrowserPdf(self, browser = None):
386 """
387 Public slot called to print the displayed page to PDF.
388
389 @param browser reference to the browser to be printed (HelpBrowser)
390 """
391 if browser is None:
392 browser = self.currentBrowser()
393
394 self.__printPdfRequested(browser.page().mainFrame())
395
396 def __printPdfRequested(self, frame):
397 """
398 Private slot to handle a print to PDF request.
399
400 @param frame reference to the frame to be printed (QWebFrame)
401 """
402 printer = QPrinter(mode = QPrinter.HighResolution)
403 if Preferences.getPrinter("ColorMode"):
404 printer.setColorMode(QPrinter.Color)
405 else:
406 printer.setColorMode(QPrinter.GrayScale)
407 printer.setPrinterName(Preferences.getPrinter("PrinterName"))
408 printer.setOutputFormat(QPrinter.PdfFormat)
409 name = frame.url().path().rsplit('/', 1)[-1]
410 if name:
411 name = name.rsplit('.', 1)[0]
412 name += '.pdf'
413 printer.setOutputFileName(name)
414
415 printDialog = QPrintDialog(printer, self)
416 if printDialog.exec_() == QDialog.Accepted:
417 try:
418 frame.print_(printer)
419 except AttributeError:
420 E5MessageBox.critical(self,
421 self.trUtf8("Eric Web Browser"),
422 self.trUtf8("""<p>Printing is not available due to a bug in PyQt4."""
423 """Please upgrade.</p>"""))
424 return
425
426 def printPreviewBrowser(self, browser = None):
427 """
428 Public slot called to show a print preview of the displayed file.
429
430 @param browser reference to the browser to be printed (HelpBrowserWV)
431 """
432 from PyQt4.QtGui import QPrintPreviewDialog
433
434 if browser is None:
435 browser = self.currentBrowser()
436
437 printer = QPrinter(mode = QPrinter.HighResolution)
438 if Preferences.getPrinter("ColorMode"):
439 printer.setColorMode(QPrinter.Color)
440 else:
441 printer.setColorMode(QPrinter.GrayScale)
442 if Preferences.getPrinter("FirstPageFirst"):
443 printer.setPageOrder(QPrinter.FirstPageFirst)
444 else:
445 printer.setPageOrder(QPrinter.LastPageFirst)
446 printer.setPrinterName(Preferences.getPrinter("PrinterName"))
447
448 self.__printPreviewBrowser = browser
449 preview = QPrintPreviewDialog(printer, self)
450 preview.paintRequested.connect(self.__printPreview)
451 preview.exec_()
452
453 def __printPreview(self, printer):
454 """
455 Private slot to generate a print preview.
456
457 @param printer reference to the printer object (QPrinter)
458 """
459 try:
460 self.__printPreviewBrowser.print_(printer)
461 except AttributeError:
462 E5MessageBox.critical(self,
463 self.trUtf8("Eric Web Browser"),
464 self.trUtf8("""<p>Printing is not available due to a bug in PyQt4."""
465 """Please upgrade.</p>"""))
466 return
467
468 def __sourceChanged(self, url):
469 """
470 Private slot to handle a change of a browsers source.
471
472 @param url URL of the new site (QUrl)
473 """
474 self.sourceChanged.emit(url)
475
476 def __titleChanged(self, title):
477 """
478 Private slot to handle a change of a browsers title.
479
480 @param title new title (string)
481 """
482 if title == "":
483 title = self.currentBrowser().url().toString()
484
485 self.setTabText(self.currentIndex(), self.__elide(title.replace("&", "&&")))
486 self.setTabToolTip(self.currentIndex(), title)
487
488 self.titleChanged.emit(title)
489
490 def __elide(self, txt, mode = Qt.ElideRight, length = 40):
491 """
492 Private method to elide some text.
493
494 @param txt text to be elided (string)
495 @keyparam mode elide mode (Qt.TextElideMode)
496 @keyparam length amount of characters to be used (integer)
497 @return the elided text (string)
498 """
499 if mode == Qt.ElideNone or len(txt) < length:
500 return txt
501 elif mode == Qt.ElideLeft:
502 return "...{0}".format(txt[-length:])
503 elif mode == Qt.ElideMiddle:
504 return "{0}...{1}".format(txt[:length // 2], txt[-(length // 2):])
505 elif mode == Qt.ElideRight:
506 return "{0}...".format(txt[:length])
507 else:
508 # just in case
509 return txt
510
511 def preferencesChanged(self):
512 """
513 Public slot to handle a change of preferences.
514 """
515 for browser in self.browsers():
516 browser.preferencesChanged()
517
518 def __loadStarted(self):
519 """
520 Private method to handle the loadStarted signal.
521 """
522 browser = self.sender()
523
524 if browser is not None:
525 index = self.indexOf(browser)
526 anim = self.animationLabel(
527 index, os.path.join(getConfig("ericPixDir"), "loading.gif"))
528 if not anim:
529 loading = QIcon(os.path.join(getConfig("ericPixDir"), "loading.gif"))
530 self.setTabIcon(index, loading)
531 self.showMessage.emit(self.trUtf8("Loading..."))
532
533 self.__mainWindow.setLoadingActions(True)
534
535 def __loadFinished(self, ok):
536 """
537 Private method to handle the loadFinished signal.
538
539 @param ok flag indicating the result (boolean)
540 """
541 browser = self.sender()
542
543 if browser is not None:
544 index = self.indexOf(browser)
545 self.resetAnimation(index)
546 self.setTabIcon(index, browser.icon())
547 if ok:
548 self.showMessage.emit(self.trUtf8("Finished loading"))
549 else:
550 self.showMessage.emit(self.trUtf8("Failed to load"))
551
552 self.__mainWindow.setLoadingActions(False)
553
554 def __iconChanged(self):
555 """
556 Private slot to handle the icon change.
557 """
558 browser = self.sender()
559
560 if browser is not None:
561 self.__mainWindow.iconChanged(browser.icon())
562 self.setTabIcon(self.indexOf(browser), browser.icon())
563
564 def getSourceFileList(self):
565 """
566 Public method to get a list of all opened source files.
567
568 @return dictionary with tab id as key and host/namespace as value
569 """
570 sourceList = {}
571 for i in range(self.count()):
572 browser = self.widget(i)
573 if browser is not None and \
574 browser.source().isValid():
575 sourceList[i] = browser.source().host()
576
577 return sourceList
578
579 def shallShutDown(self):
580 """
581 Public method to check, if the application should be shut down.
582
583 @return flag indicating a shut down (boolean)
584 """
585 if self.count() > 1:
586 mb = E5MessageBox.E5MessageBox(E5MessageBox.Information,
587 self.trUtf8("Are you sure you want to close the window?"),
588 self.trUtf8("""Are you sure you want to close the window?\n"""
589 """You have %n tab(s) open.""", "", self.count()),
590 modal = True,
591 parent = self)
592 if self.__mainWindow.fromEric:
593 quitButton = mb.addButton(self.trUtf8("&Close"), E5MessageBox.AcceptRole)
594 quitButton.setIcon(UI.PixmapCache.getIcon("close.png"))
595 else:
596 quitButton = mb.addButton(self.trUtf8("&Quit"), E5MessageBox.AcceptRole)
597 quitButton.setIcon(UI.PixmapCache.getIcon("exit.png"))
598 closeTabButton = mb.addButton(self.trUtf8("C&lose Current Tab"),
599 E5MessageBox.AcceptRole)
600 closeTabButton.setIcon(UI.PixmapCache.getIcon("tabClose.png"))
601 mb.addButton(E5MessageBox.Cancel)
602 mb.exec_()
603 if mb.clickedButton() == quitButton:
604 return True
605 else:
606 if mb.clickedButton() == closeTabButton:
607 self.closeBrowser()
608 return False
609
610 return True

eric ide

mercurial