mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Synchronized with upstream.
This commit is contained in:
commit
1b8887894a
@ -6,13 +6,13 @@ __docformat__ = 'restructuredtext en'
|
|||||||
'''
|
'''
|
||||||
Freeze app into executable using py2exe.
|
Freeze app into executable using py2exe.
|
||||||
'''
|
'''
|
||||||
QT_DIR = 'C:\\Qt\\4.4.1'
|
QT_DIR = 'C:\\Qt\\4.4.3'
|
||||||
LIBUSB_DIR = 'C:\\libusb'
|
LIBUSB_DIR = 'C:\\libusb'
|
||||||
LIBUNRAR = 'C:\\Program Files\\UnrarDLL\\unrar.dll'
|
LIBUNRAR = 'C:\\Program Files\\UnrarDLL\\unrar.dll'
|
||||||
PDFTOHTML = 'C:\\pdftohtml\\pdftohtml.exe'
|
PDFTOHTML = 'C:\\pdftohtml\\pdftohtml.exe'
|
||||||
IMAGEMAGICK_DIR = 'C:\\ImageMagick'
|
IMAGEMAGICK_DIR = 'C:\\ImageMagick'
|
||||||
FONTCONFIG_DIR = 'C:\\fontconfig'
|
FONTCONFIG_DIR = 'C:\\fontconfig'
|
||||||
|
VC90 = r'C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.CRT'
|
||||||
|
|
||||||
import sys, os, py2exe, shutil, zipfile, glob, subprocess, re
|
import sys, os, py2exe, shutil, zipfile, glob, subprocess, re
|
||||||
from distutils.core import setup
|
from distutils.core import setup
|
||||||
@ -65,6 +65,8 @@ class BuildEXE(py2exe.build_exe.py2exe):
|
|||||||
shutil.copyfile(f, os.path.join(self.dist_dir, os.path.basename(f)))
|
shutil.copyfile(f, os.path.join(self.dist_dir, os.path.basename(f)))
|
||||||
for f in glob.glob(os.path.join(BASE_DIR, 'src', 'calibre', 'plugins', '*.pyd')):
|
for f in glob.glob(os.path.join(BASE_DIR, 'src', 'calibre', 'plugins', '*.pyd')):
|
||||||
shutil.copyfile(f, os.path.join(tgt, os.path.basename(f)))
|
shutil.copyfile(f, os.path.join(tgt, os.path.basename(f)))
|
||||||
|
for f in glob.glob(os.path.join(BASE_DIR, 'src', 'calibre', 'plugins', '*.manifest')):
|
||||||
|
shutil.copyfile(f, os.path.join(tgt, os.path.basename(f)))
|
||||||
shutil.copyfile('LICENSE', os.path.join(self.dist_dir, 'LICENSE'))
|
shutil.copyfile('LICENSE', os.path.join(self.dist_dir, 'LICENSE'))
|
||||||
print
|
print
|
||||||
print 'Adding QtXml4.dll'
|
print 'Adding QtXml4.dll'
|
||||||
@ -115,12 +117,17 @@ class BuildEXE(py2exe.build_exe.py2exe):
|
|||||||
shutil.copytree(f, tgt)
|
shutil.copytree(f, tgt)
|
||||||
else:
|
else:
|
||||||
shutil.copyfile(f, tgt)
|
shutil.copyfile(f, tgt)
|
||||||
|
|
||||||
print
|
print
|
||||||
print 'Doing DLL redirection' # See http://msdn.microsoft.com/en-us/library/ms682600(VS.85).aspx
|
print 'Doing DLL redirection' # See http://msdn.microsoft.com/en-us/library/ms682600(VS.85).aspx
|
||||||
for f in glob.glob(os.path.join(PY2EXE_DIR, '*.exe')):
|
for f in glob.glob(os.path.join(PY2EXE_DIR, '*.exe')):
|
||||||
open(f + '.local', 'w').write('\n')
|
open(f + '.local', 'w').write('\n')
|
||||||
|
|
||||||
|
print
|
||||||
|
print 'Adding Windows runtime dependencies...'
|
||||||
|
for f in glob.glob(os.path.join(VC90, '*')):
|
||||||
|
shutil.copyfile(f, os.path.join(PY2EXE_DIR, os.path.basename(f)))
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def manifest(cls, prog):
|
def manifest(cls, prog):
|
||||||
@ -142,17 +149,17 @@ def main(args=sys.argv):
|
|||||||
{'script' : scripts['gui'][0],
|
{'script' : scripts['gui'][0],
|
||||||
'dest_base' : APPNAME,
|
'dest_base' : APPNAME,
|
||||||
'icon_resources' : [(1, ICONS[0])],
|
'icon_resources' : [(1, ICONS[0])],
|
||||||
'other_resources' : [BuildEXE.manifest(APPNAME)],
|
#'other_resources' : [BuildEXE.manifest(APPNAME)],
|
||||||
},
|
},
|
||||||
{'script' : scripts['gui'][1],
|
{'script' : scripts['gui'][1],
|
||||||
'dest_base' : 'lrfviewer',
|
'dest_base' : 'lrfviewer',
|
||||||
'icon_resources' : [(1, ICONS[1])],
|
'icon_resources' : [(1, ICONS[1])],
|
||||||
'other_resources' : [BuildEXE.manifest('lrfviewer')],
|
#'other_resources' : [BuildEXE.manifest('lrfviewer')],
|
||||||
},
|
},
|
||||||
{'script' : scripts['gui'][2],
|
{'script' : scripts['gui'][2],
|
||||||
'dest_base' : 'ebook-viewer',
|
'dest_base' : 'ebook-viewer',
|
||||||
'icon_resources' : [(1, ICONS[1])],
|
'icon_resources' : [(1, ICONS[1])],
|
||||||
'other_resources' : [BuildEXE.manifest('ebook-viewer')],
|
#'other_resources' : [BuildEXE.manifest('ebook-viewer')],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
console = console,
|
console = console,
|
||||||
@ -162,12 +169,12 @@ def main(args=sys.argv):
|
|||||||
'includes' : [
|
'includes' : [
|
||||||
'sip', 'pkg_resources', 'PyQt4.QtSvg',
|
'sip', 'pkg_resources', 'PyQt4.QtSvg',
|
||||||
'mechanize', 'ClientForm', 'wmi',
|
'mechanize', 'ClientForm', 'wmi',
|
||||||
'win32file', 'pythoncom', 'rtf2xml',
|
'win32file', 'pythoncom',
|
||||||
'win32process', 'win32api', 'msvcrt',
|
'win32process', 'win32api', 'msvcrt',
|
||||||
'win32event', 'calibre.ebooks.lrf.any.*',
|
'win32event', 'calibre.ebooks.lrf.any.*',
|
||||||
'calibre.ebooks.lrf.feeds.*',
|
'calibre.ebooks.lrf.feeds.*',
|
||||||
'genshi', 'BeautifulSoup',
|
'BeautifulSoup', 'pyreadline',
|
||||||
'path', 'pydoc', 'IPython.Extensions.*',
|
'pydoc', 'IPython.Extensions.*',
|
||||||
'calibre.web.feeds.recipes.*',
|
'calibre.web.feeds.recipes.*',
|
||||||
'PyQt4.QtWebKit', 'PyQt4.QtNetwork',
|
'PyQt4.QtWebKit', 'PyQt4.QtNetwork',
|
||||||
],
|
],
|
||||||
|
@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en'
|
|||||||
'''
|
'''
|
||||||
Build PyQt extensions. Integrates with distutils (but uses the PyQt build system).
|
Build PyQt extensions. Integrates with distutils (but uses the PyQt build system).
|
||||||
'''
|
'''
|
||||||
from distutils.core import Extension
|
from distutils.core import Extension as _Extension
|
||||||
from distutils.command.build_ext import build_ext as _build_ext
|
from distutils.command.build_ext import build_ext as _build_ext
|
||||||
from distutils.dep_util import newer_group
|
from distutils.dep_util import newer_group
|
||||||
from distutils import log
|
from distutils import log
|
||||||
@ -15,12 +15,23 @@ import sipconfig, os, sys, string, glob, shutil
|
|||||||
from PyQt4 import pyqtconfig
|
from PyQt4 import pyqtconfig
|
||||||
iswindows = 'win32' in sys.platform
|
iswindows = 'win32' in sys.platform
|
||||||
QMAKE = os.path.expanduser('~/qt/bin/qmake') if 'darwin' in sys.platform else'qmake'
|
QMAKE = os.path.expanduser('~/qt/bin/qmake') if 'darwin' in sys.platform else'qmake'
|
||||||
WINDOWS_PYTHON = ['C:/Python25/libs']
|
WINDOWS_PYTHON = ['C:/Python26/libs']
|
||||||
OSX_SDK = '/Developer/SDKs/MacOSX10.4u.sdk'
|
OSX_SDK = '/Developer/SDKs/MacOSX10.4u.sdk'
|
||||||
|
|
||||||
def replace_suffix(path, new_suffix):
|
def replace_suffix(path, new_suffix):
|
||||||
return os.path.splitext(path)[0] + new_suffix
|
return os.path.splitext(path)[0] + new_suffix
|
||||||
|
|
||||||
|
class Extension(_Extension):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if iswindows:
|
||||||
|
from distutils import msvc9compiler
|
||||||
|
msvc = msvc9compiler.MSVCCompiler()
|
||||||
|
msvc.initialize()
|
||||||
|
nmake = msvc.find_exe('nmake.exe')
|
||||||
|
rc = msvc.find_exe('rc.exe')
|
||||||
|
|
||||||
|
|
||||||
class PyQtExtension(Extension):
|
class PyQtExtension(Extension):
|
||||||
|
|
||||||
def __init__(self, name, sources, sip_sources, **kw):
|
def __init__(self, name, sources, sip_sources, **kw):
|
||||||
@ -37,9 +48,7 @@ class PyQtExtension(Extension):
|
|||||||
class build_ext(_build_ext):
|
class build_ext(_build_ext):
|
||||||
|
|
||||||
def make(self, makefile):
|
def make(self, makefile):
|
||||||
make = 'make'
|
make = nmake if iswindows else 'make'
|
||||||
if iswindows:
|
|
||||||
make = 'mingw32-make'
|
|
||||||
self.spawn([make, '-f', makefile])
|
self.spawn([make, '-f', makefile])
|
||||||
|
|
||||||
def build_qt_objects(self, ext, bdir):
|
def build_qt_objects(self, ext, bdir):
|
||||||
@ -65,12 +74,13 @@ CONFIG += x86 ppc
|
|||||||
open(name+'.pro', 'wb').write(pro)
|
open(name+'.pro', 'wb').write(pro)
|
||||||
self.spawn([QMAKE, '-o', 'Makefile.qt', name+'.pro'])
|
self.spawn([QMAKE, '-o', 'Makefile.qt', name+'.pro'])
|
||||||
self.make('Makefile.qt')
|
self.make('Makefile.qt')
|
||||||
pat = 'release\\*.o' if iswindows else '*.o'
|
pat = 'release\\*.obj' if iswindows else '*.o'
|
||||||
return map(os.path.abspath, glob.glob(pat))
|
return map(os.path.abspath, glob.glob(pat))
|
||||||
finally:
|
finally:
|
||||||
os.chdir(cwd)
|
os.chdir(cwd)
|
||||||
|
|
||||||
def build_sbf(self, sip, sbf, bdir):
|
def build_sbf(self, sip, sbf, bdir):
|
||||||
|
print '\tBuilding spf...'
|
||||||
sip_bin = self.sipcfg.sip_bin
|
sip_bin = self.sipcfg.sip_bin
|
||||||
self.spawn([sip_bin,
|
self.spawn([sip_bin,
|
||||||
"-c", bdir,
|
"-c", bdir,
|
||||||
@ -100,9 +110,7 @@ CONFIG += x86 ppc
|
|||||||
|
|
||||||
def build_extension(self, ext):
|
def build_extension(self, ext):
|
||||||
self.inplace = True # Causes extensions to be built in the source tree
|
self.inplace = True # Causes extensions to be built in the source tree
|
||||||
if not isinstance(ext, PyQtExtension):
|
|
||||||
return _build_ext.build_extension(self, ext)
|
|
||||||
|
|
||||||
fullname = self.get_ext_fullname(ext.name)
|
fullname = self.get_ext_fullname(ext.name)
|
||||||
if self.inplace:
|
if self.inplace:
|
||||||
# ignore build-lib -- put the compiled extension into
|
# ignore build-lib -- put the compiled extension into
|
||||||
@ -119,7 +127,38 @@ CONFIG += x86 ppc
|
|||||||
else:
|
else:
|
||||||
ext_filename = os.path.join(self.build_lib,
|
ext_filename = os.path.join(self.build_lib,
|
||||||
self.get_ext_filename(fullname))
|
self.get_ext_filename(fullname))
|
||||||
bdir = os.path.abspath(os.path.join(self.build_temp, fullname))
|
bdir = os.path.abspath(os.path.join(self.build_temp, fullname))
|
||||||
|
if not os.path.exists(bdir):
|
||||||
|
os.makedirs(bdir)
|
||||||
|
|
||||||
|
if not isinstance(ext, PyQtExtension):
|
||||||
|
if not iswindows:
|
||||||
|
return _build_ext.build_extension(self, ext)
|
||||||
|
|
||||||
|
c_sources = [f for f in ext.sources if os.path.splitext(f)[1].lower() in ('.c', '.cpp', '.cxx')]
|
||||||
|
compile_args = '/c /nologo /Ox /MD /W3 /GX /DNDEBUG'.split()
|
||||||
|
compile_args += ext.extra_compile_args
|
||||||
|
self.swig_opts = ''
|
||||||
|
inc_dirs = self.include_dirs + [x.replace('/', '\\') for x in ext.include_dirs]
|
||||||
|
cc = [msvc.cc] + compile_args + ['-I%s'%x for x in list(set(inc_dirs))]
|
||||||
|
objects = []
|
||||||
|
for f in c_sources:
|
||||||
|
o = os.path.join(bdir, os.path.basename(f)+'.obj')
|
||||||
|
objects.append(o)
|
||||||
|
compiler = cc + ['/Tc'+f, '/Fo'+o]
|
||||||
|
self.spawn(compiler)
|
||||||
|
out = os.path.join(bdir, base+'.pyd')
|
||||||
|
linker = [msvc.linker] + '/DLL /nologo /INCREMENTAL:NO'.split()
|
||||||
|
linker += ['/LIBPATH:'+x for x in self.library_dirs]
|
||||||
|
linker += [x+'.lib' for x in ext.libraries]
|
||||||
|
linker += ['/EXPORT:init'+base] + objects + ['/OUT:'+out]
|
||||||
|
self.spawn(linker)
|
||||||
|
for src in (out, out+'.manifest'):
|
||||||
|
shutil.copyfile(src, os.path.join('src', 'calibre', 'plugins', os.path.basename(src)))
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if not os.path.exists(bdir):
|
if not os.path.exists(bdir):
|
||||||
os.makedirs(bdir)
|
os.makedirs(bdir)
|
||||||
ext.sources2 = map(os.path.abspath, ext.sources)
|
ext.sources2 = map(os.path.abspath, ext.sources)
|
||||||
|
10
setup.py
10
setup.py
@ -46,10 +46,10 @@ main_functions = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from setuptools import setup, find_packages, Extension
|
from setuptools import setup, find_packages
|
||||||
from distutils.command.build import build as _build
|
from distutils.command.build import build as _build
|
||||||
from distutils.core import Command as _Command
|
from distutils.core import Command as _Command
|
||||||
from pyqtdistutils import PyQtExtension, build_ext
|
from pyqtdistutils import PyQtExtension, build_ext, Extension
|
||||||
import subprocess, glob
|
import subprocess, glob
|
||||||
|
|
||||||
def newer(targets, sources):
|
def newer(targets, sources):
|
||||||
@ -394,8 +394,10 @@ if __name__ == '__main__':
|
|||||||
ext_modules.append(Extension('calibre.plugins.winutil',
|
ext_modules.append(Extension('calibre.plugins.winutil',
|
||||||
sources=['src/calibre/utils/windows/winutil.c'],
|
sources=['src/calibre/utils/windows/winutil.c'],
|
||||||
libraries=['shell32', 'setupapi'],
|
libraries=['shell32', 'setupapi'],
|
||||||
include_dirs=['C:/WinDDK/6001.18001/inc/api/'])
|
include_dirs=['C:/WinDDK/6001.18001/inc/api/',
|
||||||
)
|
'C:/WinDDK/6001.18001/inc/crt/'],
|
||||||
|
extra_compile_args=['/X']
|
||||||
|
))
|
||||||
if isosx:
|
if isosx:
|
||||||
ext_modules.append(Extension('calibre.plugins.usbobserver',
|
ext_modules.append(Extension('calibre.plugins.usbobserver',
|
||||||
sources=['src/calibre/devices/usbobserver/usbobserver.c'])
|
sources=['src/calibre/devices/usbobserver/usbobserver.c'])
|
||||||
|
@ -4,17 +4,20 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
This module provides a thin ctypes based wrapper around libusb.
|
This module provides a thin ctypes based wrapper around libusb.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from ctypes import cdll, POINTER, byref, pointer, Structure, \
|
from ctypes import cdll, POINTER, byref, pointer, Structure as _Structure, \
|
||||||
c_ubyte, c_ushort, c_int, c_char, c_void_p, c_byte, c_uint
|
c_ubyte, c_ushort, c_int, c_char, c_void_p, c_byte, c_uint
|
||||||
from errno import EBUSY, ENOMEM
|
from errno import EBUSY, ENOMEM
|
||||||
|
|
||||||
from calibre import iswindows, isosx, load_library, isfrozen
|
from calibre import iswindows, isosx, load_library
|
||||||
|
|
||||||
_libusb_name = 'libusb'
|
_libusb_name = 'libusb'
|
||||||
PATH_MAX = 511 if iswindows else 1024 if isosx else 4096
|
PATH_MAX = 511 if iswindows else 1024 if isosx else 4096
|
||||||
if iswindows:
|
if iswindows:
|
||||||
Structure._pack_ = 1
|
class Structure(_Structure):
|
||||||
|
_pack_ = 1
|
||||||
_libusb_name = 'libusb0'
|
_libusb_name = 'libusb0'
|
||||||
|
else:
|
||||||
|
Structure = _Structure
|
||||||
|
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
|
@ -46,8 +46,8 @@
|
|||||||
</property>
|
</property>
|
||||||
<property name="maximumSize" >
|
<property name="maximumSize" >
|
||||||
<size>
|
<size>
|
||||||
<width>10000</width>
|
<width>16777215</width>
|
||||||
<height>110</height>
|
<height>100</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="verticalScrollBarPolicy" >
|
<property name="verticalScrollBarPolicy" >
|
||||||
@ -74,14 +74,17 @@
|
|||||||
<property name="flow" >
|
<property name="flow" >
|
||||||
<enum>QListView::LeftToRight</enum>
|
<enum>QListView::LeftToRight</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="isWrapping" stdset="0" >
|
<property name="gridSize" >
|
||||||
<bool>false</bool>
|
<size>
|
||||||
</property>
|
<width>175</width>
|
||||||
<property name="spacing" >
|
<height>90</height>
|
||||||
<number>10</number>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="viewMode" >
|
<property name="viewMode" >
|
||||||
<enum>QListView::IconMode</enum>
|
<enum>QListView::ListMode</enum>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap" >
|
||||||
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -715,7 +715,7 @@ void PictureFlowPrivate::render()
|
|||||||
painter.setPen(Qt::white);
|
painter.setPen(Qt::white);
|
||||||
//painter.setPen(QColor(255,255,255,127));
|
//painter.setPen(QColor(255,255,255,127));
|
||||||
|
|
||||||
if (centerIndex < slideCount() and centerIndex > -1)
|
if (centerIndex < slideCount() && centerIndex > -1)
|
||||||
painter.drawText( QRect(0,0, buffer.width(), (buffer.height() - slideSize().height())/2),
|
painter.drawText( QRect(0,0, buffer.width(), (buffer.height() - slideSize().height())/2),
|
||||||
Qt::AlignCenter, slideImages->caption(centerIndex));
|
Qt::AlignCenter, slideImages->caption(centerIndex));
|
||||||
|
|
||||||
@ -767,12 +767,12 @@ void PictureFlowPrivate::render()
|
|||||||
int sc = slideCount();
|
int sc = slideCount();
|
||||||
|
|
||||||
painter.setPen(QColor(255,255,255, (255-fade) ));
|
painter.setPen(QColor(255,255,255, (255-fade) ));
|
||||||
if (leftTextIndex < sc and leftTextIndex > -1)
|
if (leftTextIndex < sc && leftTextIndex > -1)
|
||||||
painter.drawText( QRect(0,0, buffer.width(), (buffer.height() - slideSize().height())/2),
|
painter.drawText( QRect(0,0, buffer.width(), (buffer.height() - slideSize().height())/2),
|
||||||
Qt::AlignCenter, slideImages->caption(leftTextIndex));
|
Qt::AlignCenter, slideImages->caption(leftTextIndex));
|
||||||
|
|
||||||
painter.setPen(QColor(255,255,255, fade));
|
painter.setPen(QColor(255,255,255, fade));
|
||||||
if (leftTextIndex+1 < sc and leftTextIndex > -2)
|
if (leftTextIndex+1 < sc && leftTextIndex > -2)
|
||||||
painter.drawText( QRect(0,0, buffer.width(), (buffer.height() - slideSize().height())/2),
|
painter.drawText( QRect(0,0, buffer.width(), (buffer.height() - slideSize().height())/2),
|
||||||
Qt::AlignCenter, slideImages->caption(leftTextIndex+1));
|
Qt::AlignCenter, slideImages->caption(leftTextIndex+1));
|
||||||
|
|
||||||
|
@ -7,9 +7,9 @@ import re, os, traceback
|
|||||||
from PyQt4.QtGui import QListView, QIcon, QFont, QLabel, QListWidget, \
|
from PyQt4.QtGui import QListView, QIcon, QFont, QLabel, QListWidget, \
|
||||||
QListWidgetItem, QTextCharFormat, QApplication, \
|
QListWidgetItem, QTextCharFormat, QApplication, \
|
||||||
QSyntaxHighlighter, QCursor, QColor, QWidget, QDialog, \
|
QSyntaxHighlighter, QCursor, QColor, QWidget, QDialog, \
|
||||||
QAbstractItemDelegate, QPixmap, QStyle, QFontMetrics
|
QPixmap
|
||||||
from PyQt4.QtCore import QAbstractListModel, QVariant, Qt, SIGNAL, \
|
from PyQt4.QtCore import QAbstractListModel, QVariant, Qt, SIGNAL, \
|
||||||
QObject, QRegExp, QString, QSettings
|
QObject, QRegExp, QString, QSettings, QSize
|
||||||
|
|
||||||
from calibre.gui2.jobs2 import DetailView
|
from calibre.gui2.jobs2 import DetailView
|
||||||
from calibre.gui2 import human_readable, NONE, TableView, \
|
from calibre.gui2 import human_readable, NONE, TableView, \
|
||||||
@ -128,56 +128,17 @@ class ImageView(QLabel):
|
|||||||
self.setMaximumWidth(width)
|
self.setMaximumWidth(width)
|
||||||
self.setMaximumHeight(height)
|
self.setMaximumHeight(height)
|
||||||
|
|
||||||
class LocationDelegate(QAbstractItemDelegate):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
QAbstractItemDelegate.__init__(self)
|
|
||||||
self.pixmap = QPixmap(40, 40)
|
|
||||||
self.text = QString('Reader\n999.9 MB Available202')
|
|
||||||
|
|
||||||
def rects(self, option):
|
|
||||||
style = QApplication.style()
|
|
||||||
font = QFont(option.font)
|
|
||||||
font.setBold(True)
|
|
||||||
irect = style.itemPixmapRect(option.rect, Qt.AlignHCenter|Qt.AlignTop, self.pixmap)
|
|
||||||
trect = style.itemTextRect(QFontMetrics(font), option.rect,
|
|
||||||
Qt.AlignHCenter|Qt.AlignTop, True, self.text)
|
|
||||||
trect.moveTop(irect.bottom())
|
|
||||||
return irect, trect
|
|
||||||
|
|
||||||
def sizeHint(self, option, index):
|
|
||||||
irect, trect = self.rects(option)
|
|
||||||
return irect.united(trect).size()
|
|
||||||
|
|
||||||
def paint(self, painter, option, index):
|
|
||||||
style = QApplication.style()
|
|
||||||
painter.save()
|
|
||||||
if hasattr(QStyle, 'CE_ItemViewItem'):
|
|
||||||
QApplication.style().drawControl(QStyle.CE_ItemViewItem, option, painter)
|
|
||||||
highlight = getattr(index.model(), 'highlight_row', -1) == index.row()
|
|
||||||
mode = QIcon.Active if highlight else QIcon.Normal
|
|
||||||
pixmap = QIcon(index.model().data(index, Qt.DecorationRole)).pixmap(self.pixmap.size())
|
|
||||||
pixmap = style.generatedIconPixmap(mode, pixmap, option)
|
|
||||||
text = index.model().data(index, Qt.DisplayRole).toString()
|
|
||||||
irect, trect = self.rects(option)
|
|
||||||
style.drawItemPixmap(painter, irect, Qt.AlignHCenter|Qt.AlignTop, pixmap)
|
|
||||||
font = QFont(option.font)
|
|
||||||
font.setBold(highlight)
|
|
||||||
painter.setFont(font)
|
|
||||||
style.drawItemText(painter, trect, Qt.AlignHCenter|Qt.AlignBottom,
|
|
||||||
option.palette, True, text)
|
|
||||||
painter.restore()
|
|
||||||
|
|
||||||
|
|
||||||
class LocationModel(QAbstractListModel):
|
class LocationModel(QAbstractListModel):
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
QAbstractListModel.__init__(self, parent)
|
QAbstractListModel.__init__(self, parent)
|
||||||
self.icons = [QVariant(QIcon(':/library')),
|
self.icons = [QVariant(QIcon(':/library')),
|
||||||
QVariant(QIcon(':/images/reader.svg')),
|
QVariant(QIcon(':/images/reader.svg')),
|
||||||
QVariant(QIcon(':/images/sd.svg'))]
|
QVariant(QIcon(':/images/sd.svg'))]
|
||||||
self.text = [_('Library'),
|
self.text = [_('Library'),
|
||||||
_('Reader\n%s available'),
|
_('Reader\n%s\navailable'),
|
||||||
_('Card\n%s available')]
|
_('Card\n%s\navailable')]
|
||||||
self.free = [-1, -1]
|
self.free = [-1, -1]
|
||||||
self.highlight_row = 0
|
self.highlight_row = 0
|
||||||
self.tooltips = [
|
self.tooltips = [
|
||||||
@ -199,7 +160,13 @@ class LocationModel(QAbstractListModel):
|
|||||||
elif role == Qt.DecorationRole:
|
elif role == Qt.DecorationRole:
|
||||||
data = self.icons[row]
|
data = self.icons[row]
|
||||||
elif role == Qt.ToolTipRole:
|
elif role == Qt.ToolTipRole:
|
||||||
return QVariant(self.tooltips[row])
|
data = QVariant(self.tooltips[row])
|
||||||
|
elif role == Qt.SizeHintRole:
|
||||||
|
data = QVariant(QSize(155, 90))
|
||||||
|
elif role == Qt.FontRole:
|
||||||
|
font = QFont('monospace')
|
||||||
|
font.setBold(row == self.highlight_row)
|
||||||
|
data = QVariant(font)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
def headerData(self, section, orientation, role):
|
||||||
@ -223,8 +190,6 @@ class LocationView(QListView):
|
|||||||
self.setModel(LocationModel(self))
|
self.setModel(LocationModel(self))
|
||||||
self.reset()
|
self.reset()
|
||||||
QObject.connect(self.selectionModel(), SIGNAL('currentChanged(QModelIndex, QModelIndex)'), self.current_changed)
|
QObject.connect(self.selectionModel(), SIGNAL('currentChanged(QModelIndex, QModelIndex)'), self.current_changed)
|
||||||
self.delegate = LocationDelegate()
|
|
||||||
self.setItemDelegate(self.delegate)
|
|
||||||
self.setCursor(Qt.PointingHandCursor)
|
self.setCursor(Qt.PointingHandCursor)
|
||||||
|
|
||||||
def current_changed(self, current, previous):
|
def current_changed(self, current, previous):
|
||||||
@ -270,7 +235,6 @@ class FontFamilyModel(QAbstractListModel):
|
|||||||
try:
|
try:
|
||||||
family = self.families[index.row()]
|
family = self.families[index.row()]
|
||||||
except:
|
except:
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return NONE
|
return NONE
|
||||||
if role == Qt.DisplayRole:
|
if role == Qt.DisplayRole:
|
||||||
|
@ -7,7 +7,7 @@ This module provides a thin ctypes based wrapper around libunrar.
|
|||||||
See ftp://ftp.rarlabs.com/rar/unrarsrc-3.7.5.tar.gz
|
See ftp://ftp.rarlabs.com/rar/unrarsrc-3.7.5.tar.gz
|
||||||
"""
|
"""
|
||||||
import os, ctypes, sys, re
|
import os, ctypes, sys, re
|
||||||
from ctypes import Structure, c_char_p, c_uint, c_void_p, POINTER, \
|
from ctypes import Structure as _Structure, c_char_p, c_uint, c_void_p, POINTER, \
|
||||||
byref, c_wchar_p, c_int, c_char, c_wchar
|
byref, c_wchar_p, c_int, c_char, c_wchar
|
||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
@ -18,9 +18,12 @@ from calibre.ptempfile import TemporaryDirectory
|
|||||||
_librar_name = 'libunrar'
|
_librar_name = 'libunrar'
|
||||||
cdll = ctypes.cdll
|
cdll = ctypes.cdll
|
||||||
if iswindows:
|
if iswindows:
|
||||||
Structure._pack_ = 1
|
class Structure(_Structure):
|
||||||
|
_pack_ = 1
|
||||||
_librar_name = 'unrar'
|
_librar_name = 'unrar'
|
||||||
cdll = ctypes.windll
|
cdll = ctypes.windll
|
||||||
|
else:
|
||||||
|
Structure = _Structure
|
||||||
if hasattr(sys, 'frozen') and iswindows:
|
if hasattr(sys, 'frozen') and iswindows:
|
||||||
_libunrar = cdll.LoadLibrary(os.path.join(os.path.dirname(sys.executable), 'unrar.dll'))
|
_libunrar = cdll.LoadLibrary(os.path.join(os.path.dirname(sys.executable), 'unrar.dll'))
|
||||||
_libunrar = load_library(_librar_name, cdll)
|
_libunrar = load_library(_librar_name, cdll)
|
||||||
|
@ -9,6 +9,7 @@ import time, logging, traceback, copy
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from calibre.web.feeds.feedparser import parse
|
from calibre.web.feeds.feedparser import parse
|
||||||
|
from lxml import html
|
||||||
|
|
||||||
class Article(object):
|
class Article(object):
|
||||||
|
|
||||||
@ -19,6 +20,17 @@ class Article(object):
|
|||||||
self.id = id
|
self.id = id
|
||||||
self.title = title.strip() if title else title
|
self.title = title.strip() if title else title
|
||||||
self.url = url
|
self.url = url
|
||||||
|
if summary and not isinstance(summary, unicode):
|
||||||
|
summary = summary.decode('utf-8', 'replace')
|
||||||
|
if summary and '<' in summary:
|
||||||
|
try:
|
||||||
|
s = html.fragment_fromstring(summary, create_parent=True)
|
||||||
|
summary = html.tostring(s, method='text', encoding=unicode)
|
||||||
|
except:
|
||||||
|
print 'Failed to process article summary, deleting:'
|
||||||
|
print summary.encode('utf-8')
|
||||||
|
traceback.print_exc()
|
||||||
|
summary = u''
|
||||||
self.summary = summary
|
self.summary = summary
|
||||||
self.content = content
|
self.content = content
|
||||||
self.date = published
|
self.date = published
|
||||||
|
@ -586,9 +586,9 @@ class BasicNewsRecipe(object, LoggingInterface):
|
|||||||
if npos < 0:
|
if npos < 0:
|
||||||
npos = pos
|
npos = pos
|
||||||
ans = src[:npos+1]
|
ans = src[:npos+1]
|
||||||
if isinstance(ans, unicode):
|
if len(ans) < len(src):
|
||||||
return ans
|
return ans+u'\u2026' if isinstance(ans, unicode) else ans + '...'
|
||||||
return ans+u'\u2026' if isinstance(ans, unicode) else ans + '...'
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ recipe_modules = [
|
|||||||
'blic', 'novosti', 'danas', 'vreme', 'times_online', 'the_scotsman',
|
'blic', 'novosti', 'danas', 'vreme', 'times_online', 'the_scotsman',
|
||||||
'nytimes_sub', 'security_watch', 'cyberpresse', 'st_petersburg_times',
|
'nytimes_sub', 'security_watch', 'cyberpresse', 'st_petersburg_times',
|
||||||
'clarin', 'financial_times', 'heise', 'le_monde', 'harpers', 'science_aas',
|
'clarin', 'financial_times', 'heise', 'le_monde', 'harpers', 'science_aas',
|
||||||
'science_news', 'the_nation', 'lrb'
|
'science_news', 'the_nation', 'lrb', 'harpers_full'
|
||||||
]
|
]
|
||||||
|
|
||||||
import re, imp, inspect, time, os
|
import re, imp, inspect, time, os
|
||||||
|
61
src/calibre/web/feeds/recipes/harpers_full.py
Normal file
61
src/calibre/web/feeds/recipes/harpers_full.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
|
'''
|
||||||
|
harpers.org - paid subscription/ printed issue articles
|
||||||
|
This recipe only get's article's published in text format
|
||||||
|
images and pdf's are ignored
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre import strftime
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class Harpers_full(BasicNewsRecipe):
|
||||||
|
title = u"Harper's Magazine - articles from printed edition"
|
||||||
|
__author__ = u'Darko Miletic'
|
||||||
|
description = u"Harper's Magazine: Founded June 1850."
|
||||||
|
oldest_article = 30
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
no_stylesheets = True
|
||||||
|
use_embedded_content = False
|
||||||
|
simultaneous_downloads = 1
|
||||||
|
delay = 1
|
||||||
|
needs_subscription = True
|
||||||
|
INDEX = strftime('http://www.harpers.org/archive/%Y/%m')
|
||||||
|
LOGIN = 'http://www.harpers.org'
|
||||||
|
cover_url = strftime('http://www.harpers.org/media/pages/%Y/%m/gif/0001.gif')
|
||||||
|
|
||||||
|
keep_only_tags = [ dict(name='div', attrs={'id':'cached'}) ]
|
||||||
|
remove_tags = [
|
||||||
|
dict(name='table', attrs={'class':'rcnt'})
|
||||||
|
,dict(name='table', attrs={'class':'rcnt topline'})
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_browser(self):
|
||||||
|
br = BasicNewsRecipe.get_browser()
|
||||||
|
if self.username is not None and self.password is not None:
|
||||||
|
br.open(self.LOGIN)
|
||||||
|
br.select_form(nr=1)
|
||||||
|
br['handle' ] = self.username
|
||||||
|
br['password'] = self.password
|
||||||
|
br.submit()
|
||||||
|
return br
|
||||||
|
|
||||||
|
def parse_index(self):
|
||||||
|
articles = []
|
||||||
|
print 'Processing ' + self.INDEX
|
||||||
|
soup = self.index_to_soup(self.INDEX)
|
||||||
|
for item in soup.findAll('div', attrs={'class':'title'}):
|
||||||
|
text_link = item.parent.find('img',attrs={'alt':'Text'})
|
||||||
|
if text_link:
|
||||||
|
url = self.LOGIN + item.a['href']
|
||||||
|
title = item.a.contents[0]
|
||||||
|
date = strftime(' %B %Y')
|
||||||
|
articles.append({
|
||||||
|
'title' :title
|
||||||
|
,'date' :date
|
||||||
|
,'url' :url
|
||||||
|
,'description':''
|
||||||
|
})
|
||||||
|
return [(soup.head.title.string, articles)]
|
@ -141,12 +141,12 @@ class FeedTemplate(Template):
|
|||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<py:for each="i, article in enumerate(feed.articles)">
|
<py:for each="i, article in enumerate(feed.articles)">
|
||||||
<li id="${'article_%d'%i}" py:if="getattr(article, 'downloaded', False)">
|
<li id="${'article_%d'%i}" py:if="getattr(article, 'downloaded', False)" style="padding-bottom:0.5em">
|
||||||
<a class="article" href="${article.url}">${article.title}</a>
|
<a class="article" href="${article.url}">${article.title}</a>
|
||||||
<span class="article_date">${article.localtime.strftime(" [%a, %d %b %H:%M]")}</span>
|
<span class="article_date">${article.localtime.strftime(" [%a, %d %b %H:%M]")}</span>
|
||||||
<p class="article_decription" py:if="article.summary">
|
<div class="article_decription" py:if="article.summary">
|
||||||
${Markup(cutoff(article.summary))}
|
${Markup(cutoff(article.summary))}
|
||||||
</p>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</py:for>
|
</py:for>
|
||||||
</ul>
|
</ul>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user