home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 January / maximum-cd-2011-01.iso / DiscContents / calibre-0.7.26.msi / file_1401 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-10-31  |  30.3 KB  |  728 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. __license__ = 'GPL v3'
  5. __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
  6. import os
  7. import sys
  8. import Queue
  9. import threading
  10. from threading import RLock
  11. from urllib import unquote
  12. from PyQt4.Qt import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, QByteArray, QTranslator, QCoreApplication, QThread, QEvent, QTimer, pyqtSignal, QDate, QDesktopServices, QFileDialog, QMessageBox, QPixmap, QFileIconProvider, QIcon, QApplication, QDialog, QPushButton, QUrl
  13. ORG_NAME = 'KovidsBrain'
  14. APP_UID = 'libprs500'
  15. from calibre.constants import islinux, iswindows, isosx, isfreebsd, isfrozen
  16. from calibre.utils.config import Config, ConfigProxy, dynamic, JSONConfig
  17. from calibre.utils.localization import set_qt_translator
  18. from calibre.ebooks.metadata.meta import get_metadata, metadata_from_formats
  19. from calibre.ebooks.metadata import MetaInformation
  20. from calibre.utils.date import UNDEFINED_DATE
  21. gprefs = JSONConfig('gui')
  22. gprefs.defaults['action-layout-toolbar'] = ('Add Books', 'Edit Metadata', None, 'Convert Books', 'View', None, 'Choose Library', 'Donate', None, 'Fetch News', 'Save To Disk', 'Connect Share', None, 'Remove Books', None, 'Help', 'Preferences')
  23. gprefs.defaults['action-layout-toolbar-device'] = ('Add Books', 'Edit Metadata', None, 'Convert Books', 'View', 'Send To Device', None, None, 'Location Manager', None, None, 'Fetch News', 'Save To Disk', 'Connect Share', None, 'Remove Books', None, 'Help', 'Preferences')
  24. gprefs.defaults['action-layout-context-menu'] = ('Edit Metadata', 'Send To Device', 'Save To Disk', 'Connect Share', 'Copy To Library', None, 'Convert Books', 'View', 'Open Folder', 'Show Book Details', 'Similar Books', 'Tweak ePub', None, 'Remove Books')
  25. gprefs.defaults['action-layout-context-menu-device'] = ('View', 'Save To Disk', None, 'Remove Books', None, 'Add To Library', 'Edit Collections')
  26. gprefs.defaults['show_splash_screen'] = True
  27. gprefs.defaults['toolbar_icon_size'] = 'medium'
  28. gprefs.defaults['toolbar_text'] = 'auto'
  29. gprefs.defaults['show_child_bar'] = False
  30. NONE = QVariant()
  31. UNDEFINED_QDATE = QDate(UNDEFINED_DATE)
  32. ALL_COLUMNS = [
  33.     'title',
  34.     'ondevice',
  35.     'authors',
  36.     'size',
  37.     'timestamp',
  38.     'rating',
  39.     'publisher',
  40.     'tags',
  41.     'series',
  42.     'pubdate']
  43.  
  44. def _config():
  45.     c = Config('gui', 'preferences for the calibre GUI')
  46.     c.add_opt('send_to_storage_card_by_default', default = False, help = _('Send file to storage card instead of main memory by default'))
  47.     c.add_opt('confirm_delete', default = False, help = _('Confirm before deleting'))
  48.     c.add_opt('main_window_geometry', default = None, help = _('Main window geometry'))
  49.     c.add_opt('new_version_notification', default = True, help = _('Notify when a new version is available'))
  50.     c.add_opt('use_roman_numerals_for_series_number', default = True, help = _('Use Roman numerals for series number'))
  51.     c.add_opt('sort_tags_by', default = 'name', help = _('Sort tags list by name, popularity, or rating'))
  52.     c.add_opt('cover_flow_queue_length', default = 6, help = _('Number of covers to show in the cover browsing mode'))
  53.     c.add_opt('LRF_conversion_defaults', default = [], help = _('Defaults for conversion to LRF'))
  54.     c.add_opt('LRF_ebook_viewer_options', default = None, help = _('Options for the LRF ebook viewer'))
  55.     c.add_opt('internally_viewed_formats', default = [
  56.         'LRF',
  57.         'EPUB',
  58.         'LIT',
  59.         'MOBI',
  60.         'PRC',
  61.         'HTML',
  62.         'FB2',
  63.         'PDB',
  64.         'RB'], help = _('Formats that are viewed using the internal viewer'))
  65.     c.add_opt('column_map', default = ALL_COLUMNS, help = _('Columns to be displayed in the book list'))
  66.     c.add_opt('autolaunch_server', default = False, help = _('Automatically launch content server on application startup'))
  67.     c.add_opt('oldest_news', default = 60, help = _('Oldest news kept in database'))
  68.     c.add_opt('systray_icon', default = False, help = _('Show system tray icon'))
  69.     c.add_opt('upload_news_to_device', default = True, help = _('Upload downloaded news to device'))
  70.     c.add_opt('delete_news_from_library_on_upload', default = False, help = _('Delete books from library after uploading to device'))
  71.     c.add_opt('separate_cover_flow', default = False, help = _('Show the cover flow in a separate window instead of in the main calibre window'))
  72.     c.add_opt('disable_tray_notification', default = False, help = _('Disable notifications from the system tray icon'))
  73.     c.add_opt('default_send_to_device_action', default = None, help = _('Default action to perform when send to device button is clicked'))
  74.     c.add_opt('asked_library_thing_password', default = False, help = 'Asked library thing password at least once.')
  75.     c.add_opt('search_as_you_type', default = True, help = 'Start searching as you type. If this is disabled then search will only take place when the Enter or Return key is pressed.')
  76.     c.add_opt('save_to_disk_template_history', default = [], help = 'Previously used Save to Disk templates')
  77.     c.add_opt('send_to_device_template_history', default = [], help = 'Previously used Send to Device templates')
  78.     c.add_opt('main_search_history', default = [], help = 'Search history for the main GUI')
  79.     c.add_opt('viewer_search_history', default = [], help = 'Search history for the ebook viewer')
  80.     c.add_opt('lrf_viewer_search_history', default = [], help = 'Search history for the LRF viewer')
  81.     c.add_opt('scheduler_search_history', default = [], help = 'Search history for the recipe scheduler')
  82.     c.add_opt('worker_limit', default = 6, help = _('Maximum number of waiting worker processes'))
  83.     c.add_opt('get_social_metadata', default = True, help = _('Download social metadata (tags/rating/etc.)'))
  84.     c.add_opt('overwrite_author_title_metadata', default = True, help = _('Overwrite author and title with new metadata'))
  85.     c.add_opt('enforce_cpu_limit', default = True, help = _('Limit max simultaneous jobs to number of CPUs'))
  86.     c.add_opt('tag_browser_hidden_categories', default = set(), help = _('tag browser categories not to display'))
  87.     c.add_opt('gui_layout', choices = [
  88.         'wide',
  89.         'narrow'], help = _('The layout of the user interface'), default = 'wide')
  90.     c.add_opt('show_avg_rating', default = True, help = _('Show the average rating per item indication in the tag browser'))
  91.     c.add_opt('disable_animations', default = False, help = _('Disable UI animations'))
  92.     return ConfigProxy(c)
  93.  
  94. config = _config()
  95. if iswindows:
  96.     import warnings
  97.     warnings.simplefilter('ignore', DeprecationWarning)
  98.  
  99.  
  100. def available_heights():
  101.     desktop = QCoreApplication.instance().desktop()
  102.     return map((lambda x: x.height()), map(desktop.availableGeometry, range(desktop.numScreens())))
  103.  
  104.  
  105. def available_height():
  106.     desktop = QCoreApplication.instance().desktop()
  107.     return desktop.availableGeometry().height()
  108.  
  109.  
  110. def max_available_height():
  111.     return max(available_heights())
  112.  
  113.  
  114. def min_available_height():
  115.     return min(available_heights())
  116.  
  117.  
  118. def available_width():
  119.     desktop = QCoreApplication.instance().desktop()
  120.     return desktop.availableGeometry().width()
  121.  
  122. _is_widescreen = None
  123.  
  124. def is_widescreen():
  125.     global _is_widescreen, _is_widescreen
  126.     if _is_widescreen is None:
  127.         
  128.         try:
  129.             _is_widescreen = float(available_width()) / available_height() > 1.4
  130.         _is_widescreen = False
  131.  
  132.     
  133.     return _is_widescreen
  134.  
  135.  
  136. def extension(path):
  137.     return os.path.splitext(path)[1][1:].lower()
  138.  
  139.  
  140. class CopyButton(QPushButton):
  141.     ACTION_KEYS = [
  142.         Qt.Key_Enter,
  143.         Qt.Key_Return,
  144.         Qt.Key_Space]
  145.     
  146.     def copied(self):
  147.         self.emit(SIGNAL('copy()'))
  148.         self.setDisabled(True)
  149.         self.setText(_('Copied'))
  150.  
  151.     
  152.     def keyPressEvent(self, ev):
  153.         
  154.         try:
  155.             if ev.key() in self.ACTION_KEYS:
  156.                 self.copied()
  157.                 return None
  158.         except:
  159.             pass
  160.  
  161.         QPushButton.keyPressEvent(self, ev)
  162.  
  163.     
  164.     def keyReleaseEvent(self, ev):
  165.         
  166.         try:
  167.             if ev.key() in self.ACTION_KEYS:
  168.                 return None
  169.         except:
  170.             pass
  171.  
  172.         QPushButton.keyReleaseEvent(self, ev)
  173.  
  174.     
  175.     def mouseReleaseEvent(self, ev):
  176.         ev.accept()
  177.         self.copied()
  178.  
  179.  
  180.  
  181. class MessageBox(QMessageBox):
  182.     
  183.     def __init__(self, type_, title, msg, buttons, parent, det_msg = ''):
  184.         QMessageBox.__init__(self, type_, title, msg, buttons, parent)
  185.         self.title = title
  186.         self.msg = msg
  187.         self.det_msg = det_msg
  188.         self.setDetailedText(det_msg)
  189.         self.cb = None(CopyButton if isosx else _('Copy to Clipboard'))
  190.         self.connect(self.cb, SIGNAL('copy()'), self.copy_to_clipboard)
  191.         self.addButton(self.cb, QMessageBox.ActionRole)
  192.         default_button = self.button(self.Ok)
  193.         if default_button is None:
  194.             default_button = self.button(self.Yes)
  195.         
  196.         if default_button is not None:
  197.             self.setDefaultButton(default_button)
  198.         
  199.  
  200.     
  201.     def copy_to_clipboard(self):
  202.         QApplication.clipboard().setText('%s: %s\n\n%s' % (self.title, self.msg, self.det_msg))
  203.  
  204.  
  205.  
  206. def warning_dialog(parent, title, msg, det_msg = '', show = False, show_copy_button = True):
  207.     d = MessageBox(QMessageBox.Warning, 'WARNING: ' + title, msg, QMessageBox.Ok, parent, det_msg)
  208.     d.setEscapeButton(QMessageBox.Ok)
  209.     d.setIconPixmap(QPixmap(I('dialog_warning.png')))
  210.     if not show_copy_button:
  211.         d.cb.setVisible(False)
  212.     
  213.     if show:
  214.         return d.exec_()
  215.     return d
  216.  
  217.  
  218. def error_dialog(parent, title, msg, det_msg = '', show = False, show_copy_button = True):
  219.     d = MessageBox(QMessageBox.Critical, 'ERROR: ' + title, msg, QMessageBox.Ok, parent, det_msg)
  220.     d.setIconPixmap(QPixmap(I('dialog_error.png')))
  221.     d.setEscapeButton(QMessageBox.Ok)
  222.     if not show_copy_button:
  223.         d.cb.setVisible(False)
  224.     
  225.     if show:
  226.         return d.exec_()
  227.     return d
  228.  
  229.  
  230. def question_dialog(parent, title, msg, det_msg = '', show_copy_button = True, buttons = QMessageBox.Yes | QMessageBox.No, yes_button = QMessageBox.Yes):
  231.     d = MessageBox(QMessageBox.Question, title, msg, buttons, parent, det_msg)
  232.     d.setIconPixmap(QPixmap(I('dialog_question.png')))
  233.     d.setEscapeButton(QMessageBox.No)
  234.     if not show_copy_button:
  235.         d.cb.setVisible(False)
  236.     
  237.     return d.exec_() == yes_button
  238.  
  239.  
  240. def info_dialog(parent, title, msg, det_msg = '', show = False):
  241.     d = MessageBox(QMessageBox.Information, title, msg, QMessageBox.Ok, parent, det_msg)
  242.     d.setIconPixmap(QPixmap(I('dialog_information.png')))
  243.     if show:
  244.         return d.exec_()
  245.     return d
  246.  
  247.  
  248. class Dispatcher(QObject):
  249.     dispatch_signal = pyqtSignal(object, object)
  250.     
  251.     def __init__(self, func, queued = True, parent = None):
  252.         QObject.__init__(self, parent)
  253.         self.func = func
  254.         typ = Qt.QueuedConnection
  255.         if not queued:
  256.             typ = None if queued is None else Qt.DirectConnection
  257.         
  258.         self.dispatch_signal.connect(self.dispatch, type = typ)
  259.  
  260.     
  261.     def __call__(self, *args, **kwargs):
  262.         self.dispatch_signal.emit(args, kwargs)
  263.  
  264.     
  265.     def dispatch(self, args, kwargs):
  266.         self.func(*args, **kwargs)
  267.  
  268.  
  269.  
  270. class FunctionDispatcher(QObject):
  271.     dispatch_signal = pyqtSignal(object, object, object)
  272.     
  273.     def __init__(self, func, queued = True, parent = None):
  274.         QObject.__init__(self, parent)
  275.         self.func = func
  276.         typ = Qt.QueuedConnection
  277.         if not queued:
  278.             typ = None if queued is None else Qt.DirectConnection
  279.         
  280.         self.dispatch_signal.connect(self.dispatch, type = typ)
  281.         self.q = Queue.Queue()
  282.         self.lock = threading.Lock()
  283.  
  284.     
  285.     def __call__(self, *args, **kwargs):
  286.         self.lock.__enter__()
  287.         
  288.         try:
  289.             self.dispatch_signal.emit(self.q, args, kwargs)
  290.             res = self.q.get()
  291.         finally:
  292.             pass
  293.  
  294.         return res
  295.  
  296.     
  297.     def dispatch(self, q, args, kwargs):
  298.         
  299.         try:
  300.             res = self.func(*args, **kwargs)
  301.         except:
  302.             res = None
  303.  
  304.         q.put(res)
  305.  
  306.  
  307.  
  308. class GetMetadata(QObject):
  309.     
  310.     def __init__(self):
  311.         QObject.__init__(self)
  312.         self.connect(self, SIGNAL('edispatch(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), self._get_metadata, Qt.QueuedConnection)
  313.         self.connect(self, SIGNAL('idispatch(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), self._from_formats, Qt.QueuedConnection)
  314.  
  315.     
  316.     def __call__(self, id, *args, **kwargs):
  317.         self.emit(SIGNAL('edispatch(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), id, args, kwargs)
  318.  
  319.     
  320.     def from_formats(self, id, *args, **kwargs):
  321.         self.emit(SIGNAL('idispatch(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), id, args, kwargs)
  322.  
  323.     
  324.     def _from_formats(self, id, args, kwargs):
  325.         
  326.         try:
  327.             mi = metadata_from_formats(*args, **kwargs)
  328.         except:
  329.             mi = MetaInformation('', [
  330.                 _('Unknown')])
  331.  
  332.         self.emit(SIGNAL('metadataf(PyQt_PyObject, PyQt_PyObject)'), id, mi)
  333.  
  334.     
  335.     def _get_metadata(self, id, args, kwargs):
  336.         
  337.         try:
  338.             mi = get_metadata(*args, **kwargs)
  339.         except:
  340.             mi = MetaInformation('', [
  341.                 _('Unknown')])
  342.  
  343.         self.emit(SIGNAL('metadata(PyQt_PyObject, PyQt_PyObject)'), id, mi)
  344.  
  345.  
  346.  
  347. class FileIconProvider(QFileIconProvider):
  348.     ICONS = {
  349.         'default': 'unknown',
  350.         'dir': 'dir',
  351.         'zero': 'zero',
  352.         'jpeg': 'jpeg',
  353.         'jpg': 'jpeg',
  354.         'gif': 'gif',
  355.         'png': 'png',
  356.         'bmp': 'bmp',
  357.         'svg': 'svg',
  358.         'html': 'html',
  359.         'htm': 'html',
  360.         'xhtml': 'html',
  361.         'xhtm': 'html',
  362.         'lit': 'lit',
  363.         'lrf': 'lrf',
  364.         'lrx': 'lrx',
  365.         'pdf': 'pdf',
  366.         'pdr': 'zero',
  367.         'rar': 'rar',
  368.         'zip': 'zip',
  369.         'txt': 'txt',
  370.         'prc': 'mobi',
  371.         'azw': 'mobi',
  372.         'mobi': 'mobi',
  373.         'mbp': 'zero',
  374.         'azw1': 'mobi',
  375.         'tpz': 'mobi',
  376.         'tan': 'zero',
  377.         'epub': 'epub',
  378.         'fb2': 'fb2',
  379.         'rtf': 'rtf',
  380.         'odt': 'odt',
  381.         'snb': 'snb' }
  382.     
  383.     def __init__(self):
  384.         QFileIconProvider.__init__(self)
  385.         self.icons = { }
  386.         for key in self.__class__.ICONS.keys():
  387.             self.icons[key] = I('mimetypes/') + self.__class__.ICONS[key] + '.png'
  388.         
  389.         for i in ('dir', 'default', 'zero'):
  390.             self.icons[i] = QIcon(self.icons[i])
  391.         
  392.  
  393.     
  394.     def key_from_ext(self, ext):
  395.         key = None if ext in self.icons.keys() else 'default'
  396.         if key == 'default' and ext.count('.') > 0:
  397.             ext = ext.rpartition('.')[2]
  398.             key = None if ext in self.icons.keys() else 'default'
  399.         
  400.         return key
  401.  
  402.     
  403.     def cached_icon(self, key):
  404.         candidate = self.icons[key]
  405.         if isinstance(candidate, QIcon):
  406.             return candidate
  407.         icon = QIcon(candidate)
  408.         self.icons[key] = icon
  409.         return icon
  410.  
  411.     
  412.     def icon_from_ext(self, ext):
  413.         key = None(self.key_from_ext if ext else '')
  414.         return self.cached_icon(key)
  415.  
  416.     
  417.     def load_icon(self, fileinfo):
  418.         key = 'default'
  419.         icons = self.icons
  420.         if fileinfo.isSymLink():
  421.             if not fileinfo.exists():
  422.                 return icons['zero']
  423.             fileinfo = QFileInfo(fileinfo.readLink())
  424.         
  425.         if fileinfo.isDir():
  426.             key = 'dir'
  427.         else:
  428.             ext = unicode(fileinfo.completeSuffix()).lower()
  429.             key = self.key_from_ext(ext)
  430.         return self.cached_icon(key)
  431.  
  432.     
  433.     def icon(self, arg):
  434.         if isinstance(arg, QFileInfo):
  435.             return self.load_icon(arg)
  436.         if arg == QFileIconProvider.Folder:
  437.             return self.icons['dir']
  438.         if arg == QFileIconProvider.File:
  439.             return self.icons['default']
  440.         return QFileIconProvider.icon(self, arg)
  441.  
  442.  
  443. _file_icon_provider = None
  444.  
  445. def initialize_file_icon_provider():
  446.     global _file_icon_provider
  447.     if _file_icon_provider is None:
  448.         _file_icon_provider = FileIconProvider()
  449.     
  450.  
  451.  
  452. def file_icon_provider():
  453.     initialize_file_icon_provider()
  454.     return _file_icon_provider
  455.  
  456.  
  457. class FileDialog(QObject):
  458.     
  459.     def __init__(self, title = _('Choose Files'), filters = [], add_all_files_filter = True, parent = None, modal = True, name = '', mode = QFileDialog.ExistingFiles, default_dir = '~'):
  460.         QObject.__init__(self)
  461.         ftext = ''
  462.         if filters:
  463.             for filter in filters:
  464.                 (text, extensions) = filter
  465.                 extensions = [ _[1] + '*' if i.startswith('.') else '.' + i for i in extensions ]
  466.                 ftext += '%s (%s);;' % (text, ' '.join(extensions))
  467.             
  468.         
  469.         if add_all_files_filter or not ftext:
  470.             ftext += 'All files (*)'
  471.         
  472.         if ftext.endswith(';;'):
  473.             ftext = ftext[:-2]
  474.         
  475.         self.dialog_name = None if name else 'dialog_' + title
  476.         self.selected_files = None
  477.         self.fd = None
  478.         initial_dir = dynamic.get(self.dialog_name, os.path.expanduser(default_dir))
  479.         if not isinstance(initial_dir, basestring):
  480.             initial_dir = os.path.expanduser(default_dir)
  481.         
  482.         self.selected_files = []
  483.         if mode == QFileDialog.AnyFile:
  484.             f = unicode(QFileDialog.getSaveFileName(parent, title, initial_dir, ftext, ''))
  485.             if f and os.path.exists(f):
  486.                 self.selected_files.append(f)
  487.             
  488.         elif mode == QFileDialog.ExistingFile:
  489.             f = unicode(QFileDialog.getOpenFileName(parent, title, initial_dir, ftext, ''))
  490.             if f and os.path.exists(f):
  491.                 self.selected_files.append(f)
  492.             
  493.         elif mode == QFileDialog.ExistingFiles:
  494.             fs = QFileDialog.getOpenFileNames(parent, title, initial_dir, ftext, '')
  495.             for f in fs:
  496.                 f = unicode(f)
  497.                 if not f:
  498.                     continue
  499.                 
  500.                 if not os.path.exists(f):
  501.                     f = unquote(f)
  502.                 
  503.                 if f and os.path.exists(f):
  504.                     self.selected_files.append(f)
  505.                     continue
  506.             
  507.         elif mode == QFileDialog.Directory:
  508.             pass
  509.         
  510.         opts = QFileDialog.Option()
  511.         f = unicode(QFileDialog.getExistingDirectory(parent, title, initial_dir, opts))
  512.         if os.path.exists(f):
  513.             self.selected_files.append(f)
  514.         
  515.         if self.selected_files:
  516.             self.selected_files = [ unicode(q) for q in self.selected_files ]
  517.             saved_loc = self.selected_files[0]
  518.             dynamic[self.dialog_name] = saved_loc
  519.         
  520.         self.accepted = bool(self.selected_files)
  521.  
  522.     
  523.     def get_files(self):
  524.         if self.selected_files is None:
  525.             return tuple((lambda .0: for i in .0:
  526. os.path.abspath(unicode(i)))(self.fd.selectedFiles()))
  527.         return tuple(self.selected_files)
  528.  
  529.  
  530.  
  531. def choose_dir(window, name, title, default_dir = '~'):
  532.     fd = FileDialog(title = title, filters = [], add_all_files_filter = False, parent = window, name = name, mode = QFileDialog.Directory, default_dir = default_dir)
  533.     dir = fd.get_files()
  534.     if dir:
  535.         return dir[0]
  536.  
  537.  
  538. def choose_files(window, name, title, filters = [], all_files = True, select_only_single_file = False):
  539.     mode = None if select_only_single_file else QFileDialog.ExistingFiles
  540.     fd = FileDialog(title = title, name = name, filters = filters, parent = window, add_all_files_filter = all_files, mode = mode)
  541.     if fd.accepted:
  542.         return fd.get_files()
  543.  
  544.  
  545. def choose_images(window, name, title, select_only_single_file = True):
  546.     mode = None if select_only_single_file else QFileDialog.ExistingFiles
  547.     fd = FileDialog(title = title, name = name, filters = [
  548.         ('Images', [
  549.             'png',
  550.             'gif',
  551.             'jpeg',
  552.             'jpg',
  553.             'svg'])], parent = window, add_all_files_filter = False, mode = mode)
  554.     if fd.accepted:
  555.         return fd.get_files()
  556.  
  557.  
  558. def pixmap_to_data(pixmap, format = 'JPEG'):
  559.     ba = QByteArray()
  560.     buf = QBuffer(ba)
  561.     buf.open(QBuffer.WriteOnly)
  562.     pixmap.save(buf, format)
  563.     return bytes(ba.data())
  564.  
  565.  
  566. class ResizableDialog(QDialog):
  567.     
  568.     def __init__(self, *args, **kwargs):
  569.         QDialog.__init__(self, *args)
  570.         self.setupUi(self)
  571.         nh = min_available_height() - 25
  572.         nw = available_width() - 10
  573.         if nh < 0:
  574.             nh = 800
  575.         
  576.         if nw < 0:
  577.             nw = 600
  578.         
  579.         nh = min(self.height(), nh)
  580.         nw = min(self.width(), nw)
  581.         self.resize(nw, nh)
  582.  
  583.  
  584. gui_thread = None
  585. qt_app = None
  586.  
  587. class Application(QApplication):
  588.     
  589.     def __init__(self, args):
  590.         global gui_thread, qt_app
  591.         qargs = [ _[1] if isinstance(i, unicode) else i for i in args ]
  592.         QApplication.__init__(self, qargs)
  593.         self.file_event_hook = None
  594.         gui_thread = QThread.currentThread()
  595.         self._translator = None
  596.         self.load_translations()
  597.         qt_app = self
  598.         self._file_open_paths = []
  599.         self._file_open_lock = RLock()
  600.  
  601.     
  602.     def _send_file_open_events(self):
  603.         self._file_open_lock.__enter__()
  604.         
  605.         try:
  606.             if self._file_open_paths:
  607.                 self.file_event_hook(self._file_open_paths)
  608.                 self._file_open_paths = []
  609.         finally:
  610.             pass
  611.  
  612.  
  613.     
  614.     def load_translations(self):
  615.         if self._translator is not None:
  616.             self.removeTranslator(self._translator)
  617.         
  618.         self._translator = QTranslator(self)
  619.         if set_qt_translator(self._translator):
  620.             self.installTranslator(self._translator)
  621.         
  622.  
  623.     
  624.     def event(self, e):
  625.         if callable(self.file_event_hook) and e.type() == QEvent.FileOpen:
  626.             path = unicode(e.file())
  627.             return True
  628.         return QApplication.event(self, e)
  629.  
  630.  
  631. _store_app = None
  632.  
  633. def open_url(qurl):
  634.     paths = os.environ.get('LD_LIBRARY_PATH', '').split(os.pathsep)
  635.     paths = _[1]
  636.     QDesktopServices.openUrl(qurl)
  637.  
  638.  
  639. def open_local_file(path):
  640.     if iswindows:
  641.         os.startfile(os.path.normpath(path))
  642.     else:
  643.         url = QUrl.fromLocalFile(path)
  644.         open_url(url)
  645.  
  646.  
  647. def is_ok_to_use_qt():
  648.     global _store_app, gui_thread
  649.     if (islinux or isfreebsd) and ':' not in os.environ.get('DISPLAY', ''):
  650.         return False
  651.     if _store_app is None and QApplication.instance() is None:
  652.         _store_app = QApplication([])
  653.     
  654.     if gui_thread is None:
  655.         gui_thread = QThread.currentThread()
  656.     
  657.     return gui_thread is QThread.currentThread()
  658.  
  659.  
  660. def is_gui_thread():
  661.     return gui_thread is QThread.currentThread()
  662.  
  663.  
  664. def find_forms(srcdir):
  665.     base = os.path.join(srcdir, 'calibre', 'gui2')
  666.     forms = []
  667.     for root, _, files in os.walk(base):
  668.         for name in files:
  669.             if name.endswith('.ui'):
  670.                 forms.append(os.path.abspath(os.path.join(root, name)))
  671.                 continue
  672.         
  673.     
  674.     return forms
  675.  
  676.  
  677. def form_to_compiled_form(form):
  678.     return form.rpartition('.')[0] + '_ui.py'
  679.  
  680.  
  681. def build_forms(srcdir, info = None):
  682.     import re
  683.     import cStringIO
  684.     compileUi = compileUi
  685.     import PyQt4.uic
  686.     forms = find_forms(srcdir)
  687.     if info is None:
  688.         prints = prints
  689.         import calibre
  690.         info = prints
  691.     
  692.     pat = re.compile('([\'"]):/images/([^\'"]+)\\1')
  693.     
  694.     def sub(match):
  695.         ans = 'I(%s%s%s)' % (match.group(1), match.group(2), match.group(1))
  696.         return ans
  697.  
  698.     for form in forms:
  699.         compiled_form = form_to_compiled_form(form)
  700.         if not os.path.exists(compiled_form) or os.stat(form).st_mtime > os.stat(compiled_form).st_mtime:
  701.             info('\tCompiling form', form)
  702.             buf = cStringIO.StringIO()
  703.             compileUi(form, buf)
  704.             dat = buf.getvalue()
  705.             dat = dat.replace('__appname__', 'calibre')
  706.             dat = dat.replace('import images_rc', '')
  707.             dat = dat.replace('from library import', 'from calibre.gui2.library import')
  708.             dat = dat.replace('from widgets import', 'from calibre.gui2.widgets import')
  709.             dat = dat.replace('from convert.xpath_wizard import', 'from calibre.gui2.convert.xpath_wizard import')
  710.             dat = re.compile('QtGui.QApplication.translate\\(.+?,\\s+"(.+?)(?<!\\\\)",.+?\\)', re.DOTALL).sub('_("\\1")', dat)
  711.             dat = dat.replace('_("MMM yyyy")', '"MMM yyyy"')
  712.             dat = pat.sub(sub, dat)
  713.             if form.endswith('viewer%smain.ui' % os.sep):
  714.                 info('\t\tPromoting WebView')
  715.                 dat = dat.replace('self.view = QtWebKit.QWebView(', 'self.view = DocumentView(')
  716.                 dat = dat.replace('self.view = QWebView(', 'self.view = DocumentView(')
  717.                 dat = dat.replace('from QtWebKit.QWebView import QWebView', 'from PyQt4 import QtWebKit\nfrom PyQt4.QtWebKit import QWebView')
  718.                 dat += '\n\nfrom calibre.gui2.viewer.documentview import DocumentView'
  719.             
  720.             open(compiled_form, 'wb').write(dat)
  721.             continue
  722.     
  723.  
  724. _df = os.environ.get('CALIBRE_DEVELOP_FROM', None)
  725. if _df and os.path.exists(_df):
  726.     build_forms(_df)
  727.  
  728.