mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Use a custom QDialog for error/warning/ingo/question dialogs. This allows for clickable links in the dialog messages
This commit is contained in:
parent
a16f4a4b2c
commit
a290e0f1ba
@ -8,12 +8,12 @@ from urllib import unquote
|
|||||||
from PyQt4.Qt import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, \
|
from PyQt4.Qt import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, \
|
||||||
QByteArray, QTranslator, QCoreApplication, QThread, \
|
QByteArray, QTranslator, QCoreApplication, QThread, \
|
||||||
QEvent, QTimer, pyqtSignal, QDate, QDesktopServices, \
|
QEvent, QTimer, pyqtSignal, QDate, QDesktopServices, \
|
||||||
QFileDialog, QMessageBox, QPixmap, QFileIconProvider, \
|
QFileDialog, QFileIconProvider, \
|
||||||
QIcon, QApplication, QDialog, QPushButton, QUrl, QFont
|
QIcon, QApplication, QDialog, QUrl, QFont
|
||||||
|
|
||||||
ORG_NAME = 'KovidsBrain'
|
ORG_NAME = 'KovidsBrain'
|
||||||
APP_UID = 'libprs500'
|
APP_UID = 'libprs500'
|
||||||
from calibre.constants import islinux, iswindows, isosx, isfreebsd, isfrozen
|
from calibre.constants import islinux, iswindows, isfreebsd, isfrozen
|
||||||
from calibre.utils.config import Config, ConfigProxy, dynamic, JSONConfig
|
from calibre.utils.config import Config, ConfigProxy, dynamic, JSONConfig
|
||||||
from calibre.utils.localization import set_qt_translator
|
from calibre.utils.localization import set_qt_translator
|
||||||
from calibre.ebooks.metadata.meta import get_metadata, metadata_from_formats
|
from calibre.ebooks.metadata.meta import get_metadata, metadata_from_formats
|
||||||
@ -178,104 +178,40 @@ def is_widescreen():
|
|||||||
def extension(path):
|
def extension(path):
|
||||||
return os.path.splitext(path)[1][1:].lower()
|
return os.path.splitext(path)[1][1:].lower()
|
||||||
|
|
||||||
class CopyButton(QPushButton):
|
|
||||||
|
|
||||||
ACTION_KEYS = [Qt.Key_Enter, Qt.Key_Return, Qt.Key_Space]
|
|
||||||
|
|
||||||
def copied(self):
|
|
||||||
self.emit(SIGNAL('copy()'))
|
|
||||||
self.setDisabled(True)
|
|
||||||
self.setText(_('Copied'))
|
|
||||||
|
|
||||||
|
|
||||||
def keyPressEvent(self, ev):
|
|
||||||
try:
|
|
||||||
if ev.key() in self.ACTION_KEYS:
|
|
||||||
self.copied()
|
|
||||||
return
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
QPushButton.keyPressEvent(self, ev)
|
|
||||||
|
|
||||||
|
|
||||||
def keyReleaseEvent(self, ev):
|
|
||||||
try:
|
|
||||||
if ev.key() in self.ACTION_KEYS:
|
|
||||||
return
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
QPushButton.keyReleaseEvent(self, ev)
|
|
||||||
|
|
||||||
def mouseReleaseEvent(self, ev):
|
|
||||||
ev.accept()
|
|
||||||
self.copied()
|
|
||||||
|
|
||||||
class MessageBox(QMessageBox):
|
|
||||||
|
|
||||||
def __init__(self, type_, title, msg, buttons, parent, det_msg=''):
|
|
||||||
QMessageBox.__init__(self, type_, title, msg, buttons, parent)
|
|
||||||
self.title = title
|
|
||||||
self.msg = msg
|
|
||||||
self.det_msg = det_msg
|
|
||||||
self.setDetailedText(det_msg)
|
|
||||||
# Cannot set keyboard shortcut as the event is not easy to filter
|
|
||||||
self.cb = CopyButton(_('Copy') if isosx else _('Copy to Clipboard'))
|
|
||||||
self.connect(self.cb, SIGNAL('copy()'), self.copy_to_clipboard)
|
|
||||||
self.addButton(self.cb, QMessageBox.ActionRole)
|
|
||||||
default_button = self.button(self.Ok)
|
|
||||||
if default_button is None:
|
|
||||||
default_button = self.button(self.Yes)
|
|
||||||
if default_button is not None:
|
|
||||||
self.setDefaultButton(default_button)
|
|
||||||
|
|
||||||
def copy_to_clipboard(self):
|
|
||||||
QApplication.clipboard().setText('%s: %s\n\n%s' %
|
|
||||||
(self.title, self.msg, self.det_msg))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def warning_dialog(parent, title, msg, det_msg='', show=False,
|
def warning_dialog(parent, title, msg, det_msg='', show=False,
|
||||||
show_copy_button=True):
|
show_copy_button=True):
|
||||||
d = MessageBox(QMessageBox.Warning, 'WARNING: '+title, msg, QMessageBox.Ok,
|
from calibre.gui2.dialogs.message_box import MessageBox
|
||||||
parent, det_msg)
|
d = MessageBox(MessageBox.WARNING, 'WARNING: '+title, msg, det_msg, parent=parent,
|
||||||
d.setEscapeButton(QMessageBox.Ok)
|
show_copy_button=show_copy_button)
|
||||||
d.setIconPixmap(QPixmap(I('dialog_warning.png')))
|
|
||||||
if not show_copy_button:
|
|
||||||
d.cb.setVisible(False)
|
|
||||||
if show:
|
if show:
|
||||||
return d.exec_()
|
return d.exec_()
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def error_dialog(parent, title, msg, det_msg='', show=False,
|
def error_dialog(parent, title, msg, det_msg='', show=False,
|
||||||
show_copy_button=True):
|
show_copy_button=True):
|
||||||
d = MessageBox(QMessageBox.Critical, 'ERROR: '+title, msg, QMessageBox.Ok,
|
from calibre.gui2.dialogs.message_box import MessageBox
|
||||||
parent, det_msg)
|
d = MessageBox(MessageBox.ERROR, 'ERROR: '+title, msg, det_msg, parent=parent,
|
||||||
d.setIconPixmap(QPixmap(I('dialog_error.png')))
|
show_copy_button=show_copy_button)
|
||||||
d.setEscapeButton(QMessageBox.Ok)
|
|
||||||
if not show_copy_button:
|
|
||||||
d.cb.setVisible(False)
|
|
||||||
if show:
|
if show:
|
||||||
return d.exec_()
|
return d.exec_()
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def question_dialog(parent, title, msg, det_msg='', show_copy_button=True,
|
def question_dialog(parent, title, msg, det_msg='', show_copy_button=False,
|
||||||
buttons=QMessageBox.Yes|QMessageBox.No, yes_button=QMessageBox.Yes):
|
buttons=None, yes_button=None):
|
||||||
d = MessageBox(QMessageBox.Question, title, msg, buttons,
|
from calibre.gui2.dialogs.message_box import MessageBox
|
||||||
parent, det_msg)
|
d = MessageBox(MessageBox.QUESTION, title, msg, det_msg, parent=parent,
|
||||||
d.setIconPixmap(QPixmap(I('dialog_question.png')))
|
show_copy_button=show_copy_button)
|
||||||
d.setEscapeButton(QMessageBox.No)
|
if buttons is not None:
|
||||||
if not show_copy_button:
|
d.bb.setStandardButtons(buttons)
|
||||||
d.cb.setVisible(False)
|
|
||||||
|
|
||||||
return d.exec_() == yes_button
|
return d.exec_() == d.Accepted
|
||||||
|
|
||||||
def info_dialog(parent, title, msg, det_msg='', show=False,
|
def info_dialog(parent, title, msg, det_msg='', show=False,
|
||||||
show_copy_button=True):
|
show_copy_button=True):
|
||||||
d = MessageBox(QMessageBox.Information, title, msg, QMessageBox.Ok,
|
from calibre.gui2.dialogs.message_box import MessageBox
|
||||||
parent, det_msg)
|
d = MessageBox(MessageBox.INFO, title, msg, det_msg, parent=parent,
|
||||||
d.setIconPixmap(QPixmap(I('dialog_information.png')))
|
show_copy_button=show_copy_button)
|
||||||
if not show_copy_button:
|
|
||||||
d.cb.setVisible(False)
|
|
||||||
|
|
||||||
if show:
|
if show:
|
||||||
return d.exec_()
|
return d.exec_()
|
||||||
|
104
src/calibre/gui2/dialogs/message_box.py
Normal file
104
src/calibre/gui2/dialogs/message_box.py
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
|
||||||
|
from PyQt4.Qt import QDialog, QIcon, QApplication, QSize, QKeySequence, \
|
||||||
|
QAction, Qt
|
||||||
|
|
||||||
|
from calibre.constants import __version__
|
||||||
|
from calibre.gui2.dialogs.message_box_ui import Ui_Dialog
|
||||||
|
|
||||||
|
class MessageBox(QDialog, Ui_Dialog):
|
||||||
|
|
||||||
|
ERROR = 0
|
||||||
|
WARNING = 1
|
||||||
|
INFO = 2
|
||||||
|
QUESTION = 3
|
||||||
|
|
||||||
|
def __init__(self, type_, title, msg, det_msg='', show_copy_button=True,
|
||||||
|
parent=None):
|
||||||
|
QDialog.__init__(self, parent)
|
||||||
|
icon = {
|
||||||
|
self.ERROR : 'error',
|
||||||
|
self.WARNING: 'warning',
|
||||||
|
self.INFO: 'information',
|
||||||
|
self.QUESTION: 'question',
|
||||||
|
}[type_]
|
||||||
|
icon = 'dialog_%s.png'%icon
|
||||||
|
self.icon = QIcon(I(icon))
|
||||||
|
self.setupUi(self)
|
||||||
|
|
||||||
|
self.setWindowTitle(title)
|
||||||
|
self.setWindowIcon(self.icon)
|
||||||
|
self.icon_label.setPixmap(self.icon.pixmap(128, 128))
|
||||||
|
self.msg.setText(msg)
|
||||||
|
self.det_msg.setPlainText(det_msg)
|
||||||
|
self.det_msg.setVisible(False)
|
||||||
|
|
||||||
|
if det_msg:
|
||||||
|
self.show_det_msg = _('Show &details')
|
||||||
|
self.hide_det_msg = _('Hide &details')
|
||||||
|
self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole)
|
||||||
|
self.det_msg_toggle.clicked.connect(self.toggle_det_msg)
|
||||||
|
self.det_msg_toggle.setToolTip(
|
||||||
|
_('Show detailed information about this error'))
|
||||||
|
|
||||||
|
if show_copy_button:
|
||||||
|
self.ctc_button = self.bb.addButton(_('&Copy to clipboard'),
|
||||||
|
self.bb.ActionRole)
|
||||||
|
self.ctc_button.clicked.connect(self.copy_to_clipboard)
|
||||||
|
|
||||||
|
|
||||||
|
self.copy_action = QAction(self)
|
||||||
|
self.addAction(self.copy_action)
|
||||||
|
self.copy_action.setShortcuts(QKeySequence.Copy)
|
||||||
|
self.copy_action.triggered.connect(self.copy_to_clipboard)
|
||||||
|
|
||||||
|
self.is_question = type_ == self.QUESTION
|
||||||
|
if self.is_question:
|
||||||
|
self.bb.setStandardButtons(self.bb.Yes|self.bb.No)
|
||||||
|
self.bb.button(self.bb.Yes).setDefault(True)
|
||||||
|
else:
|
||||||
|
self.bb.button(self.bb.Ok).setDefault(True)
|
||||||
|
|
||||||
|
self.do_resize()
|
||||||
|
|
||||||
|
def toggle_det_msg(self, *args):
|
||||||
|
vis = self.det_msg.isVisible()
|
||||||
|
self.det_msg_toggle.setText(self.show_det_msg if vis else
|
||||||
|
self.hide_det_msg)
|
||||||
|
self.det_msg.setVisible(not vis)
|
||||||
|
self.do_resize()
|
||||||
|
|
||||||
|
def do_resize(self):
|
||||||
|
sz = self.sizeHint() + QSize(100, 0)
|
||||||
|
sz.setWidth(min(500, sz.width()))
|
||||||
|
sz.setHeight(min(500, sz.height()))
|
||||||
|
self.resize(sz)
|
||||||
|
|
||||||
|
def copy_to_clipboard(self, *args):
|
||||||
|
QApplication.clipboard().setText(
|
||||||
|
'calibre, version %s\n%s: %s\n\n%s' %
|
||||||
|
(__version__, unicode(self.windowTitle()),
|
||||||
|
unicode(self.msg.text()),
|
||||||
|
unicode(self.det_msg.toPlainText())))
|
||||||
|
self.ctc_button.setText(_('Copied'))
|
||||||
|
|
||||||
|
def showEvent(self, ev):
|
||||||
|
ret = QDialog.showEvent(self, ev)
|
||||||
|
if self.is_question:
|
||||||
|
self.bb.button(self.bb.Yes).setFocus(Qt.OtherFocusReason)
|
||||||
|
else:
|
||||||
|
self.bb.button(self.bb.Ok).setFocus(Qt.OtherFocusReason)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app = QApplication([])
|
||||||
|
from calibre.gui2 import question_dialog
|
||||||
|
print question_dialog(None, 'title', 'msg <a href="http://google.com">goog</a> ',
|
||||||
|
det_msg='det '*1000,
|
||||||
|
show_copy_button=True)
|
105
src/calibre/gui2/dialogs/message_box.ui
Normal file
105
src/calibre/gui2/dialogs/message_box.ui
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Dialog</class>
|
||||||
|
<widget class="QDialog" name="Dialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>497</width>
|
||||||
|
<height>235</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="icon_label">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>68</width>
|
||||||
|
<height>68</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="../../../../resources/images.qrc">:/images/dialog_warning.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="msg">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QPlainTextEdit" name="det_msg">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QDialogButtonBox" name="bb">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../../../../resources/images.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>bb</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>bb</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
Loading…
x
Reference in New Issue
Block a user