home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_1156 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  13.2 KB  |  302 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. __license__ = 'GPL v3'
  5. __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
  6. __docformat__ = 'restructuredtext en'
  7. import os
  8. import collections
  9. from PyQt4.Qt import QLabel, QPixmap, QSize, QWidget, Qt, pyqtSignal, QVBoxLayout, QScrollArea, QPropertyAnimation, QEasingCurve, QSizePolicy, QPainter, QRect, pyqtProperty
  10. from calibre import fit_image, prepare_string_for_xml
  11. from calibre.gui2.widgets import IMAGE_EXTENSIONS
  12. from calibre.ebooks import BOOK_EXTENSIONS
  13. from calibre.constants import preferred_encoding
  14. from calibre.library.comments import comments_to_html
  15. from calibre.gui2 import config, open_local_file
  16. WEIGHTS = collections.defaultdict((lambda : 100))
  17. WEIGHTS[_('Path')] = 5
  18. WEIGHTS[_('Formats')] = 1
  19. WEIGHTS[_('Collections')] = 2
  20. WEIGHTS[_('Series')] = 3
  21. WEIGHTS[_('Tags')] = 4
  22.  
  23. def render_rows(data):
  24.     keys = data.keys()
  25.     keys.sort(cmp = (lambda x, y: cmp(WEIGHTS[x], WEIGHTS[y])))
  26.     rows = []
  27.     for key in keys:
  28.         txt = data[key]
  29.         if key in ('id', _('Comments')) and not hasattr(txt, 'strip') and not txt.strip() or txt == 'None':
  30.             continue
  31.         
  32.         if isinstance(key, str):
  33.             key = key.decode(preferred_encoding, 'replace')
  34.         
  35.         if isinstance(txt, str):
  36.             txt = txt.decode(preferred_encoding, 'replace')
  37.         
  38.         if '</font>' not in txt:
  39.             txt = prepare_string_for_xml(txt)
  40.         
  41.         if 'id' in data:
  42.             if key == _('Path'):
  43.                 txt = u'<a href="path:%s" title="%s">%s</a>' % (data['id'], txt, _('Click to open'))
  44.             
  45.             if key == _('Formats') and txt and txt != _('None'):
  46.                 fmts = [ x.strip() for x in txt.split(',') ]
  47.                 fmts = [ u'<a href="format:%s:%s">%s</a>' % (data['id'], x, x) for x in fmts ]
  48.                 txt = ', '.join(fmts)
  49.             
  50.         elif key == _('Path'):
  51.             txt = u'<a href="devpath:%s">%s</a>' % (txt, _('Click to open'))
  52.         
  53.         rows.append((key, txt))
  54.     
  55.     return rows
  56.  
  57.  
  58. class CoverView(QWidget):
  59.     
  60.     def __init__(self, vertical, parent = None):
  61.         QWidget.__init__(self, parent)
  62.         self.setMaximumSize(QSize(120, 120))
  63.         None(None(self.setMinimumSize, QSize if vertical else 20 if vertical else 20))
  64.         self._current_pixmap_size = self.maximumSize()
  65.         self.vertical = vertical
  66.         self.animation = QPropertyAnimation(self, 'current_pixmap_size', self)
  67.         self.animation.setEasingCurve(QEasingCurve(QEasingCurve.OutExpo))
  68.         self.animation.setDuration(1000)
  69.         self.animation.setStartValue(QSize(0, 0))
  70.         self.animation.valueChanged.connect(self.value_changed)
  71.         None(self.setSizePolicy if vertical else QSizePolicy.Minimum, QSizePolicy.Expanding)
  72.         self.default_pixmap = QPixmap(I('book.svg'))
  73.         self.pixmap = self.default_pixmap
  74.         self.pwidth = None
  75.         self.pheight = None
  76.         self.data = { }
  77.         self.do_layout()
  78.  
  79.     
  80.     def value_changed(self, val):
  81.         self.update()
  82.  
  83.     
  84.     def setCurrentPixmapSize(self, val):
  85.         self._current_pixmap_size = val
  86.  
  87.     
  88.     def do_layout(self):
  89.         if self.rect().width() == 0 or self.rect().height() == 0:
  90.             return None
  91.         pixmap = self.pixmap
  92.         pwidth = pixmap.width()
  93.         pheight = pixmap.height()
  94.         
  95.         try:
  96.             (self.pwidth, self.pheight) = fit_image(pwidth, pheight, self.rect().width(), self.rect().height())[1:]
  97.         except:
  98.             self.rect().height() == 0
  99.             self.pwidth = self.rect().width() - 1
  100.             self.pheight = self.rect().height() - 1
  101.  
  102.         self.current_pixmap_size = QSize(self.pwidth, self.pheight)
  103.         self.animation.setEndValue(self.current_pixmap_size)
  104.  
  105.     
  106.     def relayout(self, parent_size):
  107.         if self.vertical:
  108.             self.setMaximumSize(parent_size.width(), min(int(parent_size.height() / 2), int((4 / 3) * parent_size.width()) + 1))
  109.         else:
  110.             self.setMaximumSize(1 + int((3 / 4) * parent_size.height()), parent_size.height())
  111.         self.resize(self.maximumSize())
  112.         self.animation.stop()
  113.         self.do_layout()
  114.  
  115.     
  116.     def sizeHint(self):
  117.         return self.maximumSize()
  118.  
  119.     
  120.     def show_data(self, data):
  121.         self.animation.stop()
  122.         same_item = data.get('id', True) == self.data.get('id', False)
  123.         self.data = {
  124.             'id': data.get('id', None) }
  125.         if data.has_key('cover'):
  126.             self.pixmap = QPixmap.fromImage(data.pop('cover'))
  127.             if self.pixmap.isNull() and self.pixmap.width() < 5 or self.pixmap.height() < 5:
  128.                 self.pixmap = self.default_pixmap
  129.             
  130.         else:
  131.             self.pixmap = self.default_pixmap
  132.         self.do_layout()
  133.         self.update()
  134.         if not same_item and not config['disable_animations']:
  135.             self.animation.start()
  136.         
  137.  
  138.     
  139.     def paintEvent(self, event):
  140.         canvas_size = self.rect()
  141.         width = self.current_pixmap_size.width()
  142.         extrax = canvas_size.width() - width
  143.         if extrax < 0:
  144.             extrax = 0
  145.         
  146.         x = int(extrax / 2)
  147.         height = self.current_pixmap_size.height()
  148.         extray = canvas_size.height() - height
  149.         if extray < 0:
  150.             extray = 0
  151.         
  152.         y = int(extray / 2)
  153.         target = QRect(x, y, width, height)
  154.         p = QPainter(self)
  155.         p.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
  156.         p.drawPixmap(target, self.pixmap.scaled(target.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
  157.         p.end()
  158.  
  159.     current_pixmap_size = pyqtProperty('QSize', fget = (lambda self: self._current_pixmap_size), fset = setCurrentPixmapSize)
  160.  
  161.  
  162. class Label(QLabel):
  163.     mr = pyqtSignal(object)
  164.     link_clicked = pyqtSignal(object)
  165.     
  166.     def __init__(self):
  167.         QLabel.__init__(self)
  168.         self.setTextFormat(Qt.RichText)
  169.         self.setText('')
  170.         self.setWordWrap(True)
  171.         self.setAlignment(Qt.AlignTop)
  172.         self.linkActivated.connect(self.link_activated)
  173.         self._link_clicked = False
  174.         self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
  175.  
  176.     
  177.     def link_activated(self, link):
  178.         self._link_clicked = True
  179.         link = unicode(link)
  180.         self.link_clicked.emit(link)
  181.  
  182.     
  183.     def mouseReleaseEvent(self, ev):
  184.         QLabel.mouseReleaseEvent(self, ev)
  185.         if not self._link_clicked:
  186.             self.mr.emit(ev)
  187.         
  188.         self._link_clicked = False
  189.  
  190.  
  191.  
  192. class BookInfo(QScrollArea):
  193.     
  194.     def __init__(self, vertical, parent = None):
  195.         QScrollArea.__init__(self, parent)
  196.         self.vertical = vertical
  197.         self.setWidgetResizable(True)
  198.         self.label = Label()
  199.         self.setWidget(self.label)
  200.         self.link_clicked = self.label.link_clicked
  201.         self.mr = self.label.mr
  202.         self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
  203.  
  204.     
  205.     def show_data(self, data):
  206.         self.label.setText('')
  207.         rows = render_rows(data)
  208.         rows = []([ u'<tr><td valign="top"><b>%s:</b></td><td valign="top">%s</td></tr>' % (k, t) for k, t in rows ])
  209.         comments = ''
  210.  
  211.  
  212.  
  213. class BookDetails(QWidget):
  214.     resized = pyqtSignal(object)
  215.     show_book_info = pyqtSignal()
  216.     open_containing_folder = pyqtSignal(int)
  217.     view_specific_format = pyqtSignal(int, object)
  218.     DROPABBLE_EXTENSIONS = IMAGE_EXTENSIONS + BOOK_EXTENSIONS
  219.     files_dropped = pyqtSignal(object, object)
  220.     
  221.     def paths_from_event(cls, event):
  222.         if event.mimeData().hasFormat('text/uri-list'):
  223.             urls = [ unicode(u.toLocalFile()) for u in event.mimeData().urls() ]
  224.             urls = _[2]
  225.             return _[3]
  226.  
  227.     paths_from_event = classmethod(paths_from_event)
  228.     
  229.     def dragEnterEvent(self, event):
  230.         if int(event.possibleActions() & Qt.CopyAction) + int(event.possibleActions() & Qt.MoveAction) == 0:
  231.             return None
  232.         paths = self.paths_from_event(event)
  233.         if paths:
  234.             event.acceptProposedAction()
  235.         
  236.  
  237.     
  238.     def dropEvent(self, event):
  239.         paths = self.paths_from_event(event)
  240.         event.setDropAction(Qt.CopyAction)
  241.         self.files_dropped.emit(event, paths)
  242.  
  243.     
  244.     def dragMoveEvent(self, event):
  245.         event.acceptProposedAction()
  246.  
  247.     
  248.     def __init__(self, vertical, parent = None):
  249.         QWidget.__init__(self, parent)
  250.         self.setAcceptDrops(True)
  251.         self._layout = QVBoxLayout()
  252.         if not vertical:
  253.             self._layout.setDirection(self._layout.LeftToRight)
  254.         
  255.         self.setLayout(self._layout)
  256.         self.cover_view = CoverView(vertical, self)
  257.         self.cover_view.relayout(self.size())
  258.         self.resized.connect(self.cover_view.relayout, type = Qt.QueuedConnection)
  259.         self._layout.addWidget(self.cover_view)
  260.         self.book_info = BookInfo(vertical, self)
  261.         self._layout.addWidget(self.book_info)
  262.         self.book_info.link_clicked.connect(self._link_clicked)
  263.         self.book_info.mr.connect(self.mouseReleaseEvent)
  264.         if vertical:
  265.             self.setMinimumSize(QSize(190, 200))
  266.         else:
  267.             self.setMinimumSize(120, 120)
  268.         self.setCursor(Qt.PointingHandCursor)
  269.  
  270.     
  271.     def _link_clicked(self, link):
  272.         (typ, _, val) = link.partition(':')
  273.         if typ == 'path':
  274.             self.open_containing_folder.emit(int(val))
  275.         elif typ == 'format':
  276.             (id_, fmt) = val.split(':')
  277.             self.view_specific_format.emit(int(id_), fmt)
  278.         elif typ == 'devpath':
  279.             open_local_file(val)
  280.         
  281.  
  282.     
  283.     def mouseReleaseEvent(self, ev):
  284.         ev.accept()
  285.         self.show_book_info.emit()
  286.  
  287.     
  288.     def resizeEvent(self, ev):
  289.         self.resized.emit(self.size())
  290.  
  291.     
  292.     def show_data(self, data):
  293.         self.cover_view.show_data(data)
  294.         self.book_info.show_data(data)
  295.         self.setToolTip('<p>' + _('Click to open Book Details window') + '<br><br>' + _('Path') + ': ' + data.get(_('Path'), ''))
  296.  
  297.     
  298.     def reset_info(self):
  299.         self.show_data({ })
  300.  
  301.  
  302.