Rationalize settings system. Unfortunately, this means you will lose most of your stored settings (Except the conversion defaults and the database location). Please spend a moment restoring them.

This commit is contained in:
Kovid Goyal 2008-06-14 12:21:47 -07:00
parent 8ead30992e
commit 65972716d4
15 changed files with 114 additions and 204 deletions

View File

@ -15,7 +15,7 @@ from optparse import OptionParser as _OptionParser
from optparse import IndentedHelpFormatter from optparse import IndentedHelpFormatter
from logging import Formatter from logging import Formatter
from PyQt4.QtCore import QSettings, QVariant, QUrl, QByteArray from PyQt4.QtCore import QSettings, QVariant, QUrl, QByteArray, QString
from PyQt4.QtGui import QDesktopServices from PyQt4.QtGui import QDesktopServices
from calibre.translations.msgfmt import make from calibre.translations.msgfmt import make
@ -429,13 +429,9 @@ def singleinstance(name):
class Settings(QSettings): class Settings(QSettings):
def __init__(self): def __init__(self, name='calibre2'):
QSettings.__init__(self, QSettings.IniFormat, QSettings.UserScope, QSettings.__init__(self, QSettings.IniFormat, QSettings.UserScope,
'kovidgoyal.net', 'calibre') 'kovidgoyal.net', name)
def migrate(self, settings):
for key in settings.allKeys():
self.setValue(key, settings.value(key, QVariant()))
def get(self, key, default=None): def get(self, key, default=None):
key = str(key) key = str(key)
@ -451,10 +447,23 @@ class Settings(QSettings):
self.setValue(str(key), QVariant(QByteArray(val))) self.setValue(str(key), QVariant(QByteArray(val)))
_settings = Settings() _settings = Settings()
if not _settings.get('migrated from QSettings'): if not _settings.get('rationalized'):
_settings.migrate(QSettings('KovidsBrain', 'libprs500')) __settings = Settings(name='calibre')
_settings.set('migrated from QSettings', True) dbpath = os.path.join(os.path.expanduser('~'), 'library1.db').decode(sys.getfilesystemencoding())
_settings.sync() dbpath = unicode(__settings.value('database path',
QVariant(QString.fromUtf8(dbpath.encode('utf-8')))).toString())
cmdline = __settings.value('LRF conversion defaults', QVariant(QByteArray(''))).toByteArray().data()
_settings.set('database path', dbpath)
if cmdline:
cmdline = cPickle.loads(cmdline)
_settings.set('LRF conversion defaults', cmdline)
_settings.set('rationalized', True)
try:
os.unlink(unicode(__settings.fileName()))
except:
pass
_spat = re.compile(r'^the\s+|^a\s+|^an\s+', re.IGNORECASE) _spat = re.compile(r'^the\s+|^a\s+|^an\s+', re.IGNORECASE)
def english_sort(x, y): def english_sort(x, y):

View File

@ -83,17 +83,12 @@ class TableView(QTableView):
def read_settings(self): def read_settings(self):
self.cw = str(Settings().value(self.__class__.__name__ + ' column widths', QVariant('')).toString()) self.cw = Settings().get(self.__class__.__name__ + ' column widths')
try:
self.cw = tuple(int(i) for i in self.cw.split(','))
except ValueError:
self.cw = None
def write_settings(self): def write_settings(self):
settings = Settings() settings = Settings()
settings.setValue(self.__class__.__name__ + ' column widths', settings.set(self.__class__.__name__ + ' column widths',
QVariant(','.join(str(self.columnWidth(i)) tuple([int(self.columnWidth(i)) for i in range(self.model().columnCount(None))]))
for i in range(self.model().columnCount(None)))))
def restore_column_widths(self): def restore_column_widths(self):
if self.cw and len(self.cw): if self.cw and len(self.cw):
@ -107,14 +102,10 @@ class TableView(QTableView):
is hidden, if True it is shown. is hidden, if True it is shown.
''' '''
if cols: if cols:
Settings().setValue(self.__class__.__name__ + ' visible columns', Settings().set(self.__class__.__name__ + ' visible columns', cols)
QVariant(repr(cols)))
else: else:
cols = qstring_to_unicode(Settings().value(self.__class__.__name__ + ' visible columns', cols = Settings().get(self.__class__.__name__ + ' visible columns')
QVariant('')).toString()) if not cols:
if cols:
cols = eval(cols)
else:
cols = [True for i in range(self.model().columnCount(self))] cols = [True for i in range(self.model().columnCount(self))]
for i in range(len(cols)): for i in range(len(cols)):
@ -217,7 +208,7 @@ _sidebar_directories = []
def set_sidebar_directories(dirs): def set_sidebar_directories(dirs):
global _sidebar_directories global _sidebar_directories
if dirs is None: if dirs is None:
dirs = Settings().value('frequently used directories', QVariant([])).toStringList() dirs = Settings().get('frequently used directories', [])
_sidebar_directories = [QUrl.fromLocalFile(i) for i in dirs] _sidebar_directories = [QUrl.fromLocalFile(i) for i in dirs]
class FileDialog(QObject): class FileDialog(QObject):
@ -251,7 +242,7 @@ class FileDialog(QObject):
self.fd.setModal(modal) self.fd.setModal(modal)
self.fd.setFilter(ftext) self.fd.setFilter(ftext)
self.fd.setWindowTitle(title) self.fd.setWindowTitle(title)
state = settings.value(name, QVariant()).toByteArray() state = settings.get(self.dialog_name, QByteArray())
if not self.fd.restoreState(state): if not self.fd.restoreState(state):
self.fd.setDirectory(os.path.expanduser('~')) self.fd.setDirectory(os.path.expanduser('~'))
osu = [i for i in self.fd.sidebarUrls()] osu = [i for i in self.fd.sidebarUrls()]
@ -259,7 +250,7 @@ class FileDialog(QObject):
QObject.connect(self.fd, SIGNAL('accepted()'), self.save_dir) QObject.connect(self.fd, SIGNAL('accepted()'), self.save_dir)
self.accepted = self.fd.exec_() == QFileDialog.Accepted self.accepted = self.fd.exec_() == QFileDialog.Accepted
else: else:
dir = settings.value(self.dialog_name, QVariant(os.path.expanduser('~'))).toString() dir = settings.get(self.dialog_name, os.path.expanduser('~'))
self.selected_files = [] self.selected_files = []
if mode == QFileDialog.AnyFile: if mode == QFileDialog.AnyFile:
f = qstring_to_unicode( f = qstring_to_unicode(
@ -284,7 +275,7 @@ class FileDialog(QObject):
self.selected_files.append(f) self.selected_files.append(f)
if self.selected_files: if self.selected_files:
self.selected_files = [qstring_to_unicode(q) for q in self.selected_files] self.selected_files = [qstring_to_unicode(q) for q in self.selected_files]
settings.setValue(self.dialog_name, QVariant(os.path.dirname(self.selected_files[0]))) settings.set(self.dialog_name, os.path.dirname(self.selected_files[0]))
self.accepted = bool(self.selected_files) self.accepted = bool(self.selected_files)
@ -299,7 +290,7 @@ class FileDialog(QObject):
def save_dir(self): def save_dir(self):
if self.fd: if self.fd:
settings = Settings() settings = Settings()
settings.setValue(self.dialog_name, QVariant(self.fd.saveState())) settings.set(self.dialog_name, self.fd.saveState())
def choose_dir(window, name, title): def choose_dir(window, name, title):

View File

@ -3,7 +3,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import os import os
from PyQt4.QtGui import QDialog, QMessageBox, QListWidgetItem, QIcon from PyQt4.QtGui import QDialog, QMessageBox, QListWidgetItem, QIcon
from PyQt4.QtCore import QVariant, SIGNAL, QStringList, QTimer, Qt, QSize from PyQt4.QtCore import SIGNAL, QTimer, Qt, QSize
from calibre import islinux, Settings from calibre import islinux, Settings
from calibre.gui2.dialogs.config_ui import Ui_Dialog from calibre.gui2.dialogs.config_ui import Ui_Dialog
@ -24,18 +24,15 @@ class ConfigDialog(QDialog, Ui_Dialog):
self.db = db self.db = db
self.current_cols = columns self.current_cols = columns
settings = Settings() settings = Settings()
path = qstring_to_unicode(\ path = settings.get('database path')
settings.value("database path",
QVariant(os.path.join(os.path.expanduser('~'),'library1.db'))).toString())
self.location.setText(os.path.dirname(path)) self.location.setText(os.path.dirname(path))
self.connect(self.browse_button, SIGNAL('clicked(bool)'), self.browse) self.connect(self.browse_button, SIGNAL('clicked(bool)'), self.browse)
self.connect(self.compact_button, SIGNAL('clicked(bool)'), self.compact) self.connect(self.compact_button, SIGNAL('clicked(bool)'), self.compact)
dirs = settings.value('frequently used directories', QVariant(QStringList())).toStringList() dirs = settings.get('frequently used directories', [])
rn = bool(settings.value('use roman numerals for series number', rn = settings.get('use roman numerals for series number', True)
QVariant(True)).toBool()) self.timeout.setValue(settings.get('network timeout', 5))
self.timeout.setValue(settings.value('network timeout', QVariant(5)).toInt()[0])
self.roman_numerals.setChecked(rn) self.roman_numerals.setChecked(rn)
self.directory_list.addItems(dirs) self.directory_list.addItems(dirs)
self.connect(self.add_button, SIGNAL('clicked(bool)'), self.add_dir) self.connect(self.add_button, SIGNAL('clicked(bool)'), self.add_dir)
@ -58,7 +55,7 @@ class ConfigDialog(QDialog, Ui_Dialog):
self.filename_pattern = FilenamePattern(self) self.filename_pattern = FilenamePattern(self)
self.metadata_box.layout().insertWidget(0, self.filename_pattern) self.metadata_box.layout().insertWidget(0, self.filename_pattern)
icons = settings.value('toolbar icon size', QVariant(self.ICON_SIZES[0])).toSize() icons = settings.get('toolbar icon size', self.ICON_SIZES[0])
self.toolbar_button_size.setCurrentIndex(0 if icons == self.ICON_SIZES[0] else 1 if icons == self.ICON_SIZES[1] else 2) self.toolbar_button_size.setCurrentIndex(0 if icons == self.ICON_SIZES[0] else 1 if icons == self.ICON_SIZES[1] else 2)
self.show_toolbar_text.setChecked(settings.get('show text in toolbar', True)) self.show_toolbar_text.setChecked(settings.get('show text in toolbar', True))
@ -84,14 +81,14 @@ class ConfigDialog(QDialog, Ui_Dialog):
def accept(self): def accept(self):
settings = Settings() settings = Settings()
settings.setValue('use roman numerals for series number', QVariant(self.roman_numerals.isChecked())) settings.set('use roman numerals for series number', bool(self.roman_numerals.isChecked()))
settings.setValue('network timeout', QVariant(self.timeout.value())) settings.set('network timeout', int(self.timeout.value()))
path = qstring_to_unicode(self.location.text()) path = qstring_to_unicode(self.location.text())
self.final_columns = [self.columns.item(i).checkState() == Qt.Checked for i in range(self.columns.count())] self.final_columns = [self.columns.item(i).checkState() == Qt.Checked for i in range(self.columns.count())]
settings.setValue('toolbar icon size', QVariant(self.ICON_SIZES[self.toolbar_button_size.currentIndex()])) settings.set('toolbar icon size', self.ICON_SIZES[self.toolbar_button_size.currentIndex()])
settings.set('show text in toolbar', bool(self.show_toolbar_text.isChecked())) settings.set('show text in toolbar', bool(self.show_toolbar_text.isChecked()))
pattern = self.filename_pattern.commit() pattern = self.filename_pattern.commit()
settings.setValue('filename pattern', QVariant(pattern)) settings.set('filename pattern', pattern)
if not path or not os.path.exists(path) or not os.path.isdir(path): if not path or not os.path.exists(path) or not os.path.isdir(path):
d = error_dialog(self, _('Invalid database location'), _('Invalid database location ')+path+_('<br>Must be a directory.')) d = error_dialog(self, _('Invalid database location'), _('Invalid database location ')+path+_('<br>Must be a directory.'))
@ -102,7 +99,7 @@ class ConfigDialog(QDialog, Ui_Dialog):
else: else:
self.database_location = os.path.abspath(path) self.database_location = os.path.abspath(path)
self.directories = [qstring_to_unicode(self.directory_list.item(i).text()) for i in range(self.directory_list.count())] self.directories = [qstring_to_unicode(self.directory_list.item(i).text()) for i in range(self.directory_list.count())]
settings.setValue('frequently used directories', QVariant(self.directories)) settings.set('frequently used directories', self.directories)
QDialog.accept(self) QDialog.accept(self)
class Vacuum(QMessageBox): class Vacuum(QMessageBox):

View File

@ -76,7 +76,7 @@ class FetchMetadata(QDialog, Ui_FetchMetadata):
self.timeout = timeout self.timeout = timeout
QObject.connect(self.fetch, SIGNAL('clicked()'), self.fetch_metadata) QObject.connect(self.fetch, SIGNAL('clicked()'), self.fetch_metadata)
self.key.setText(Settings().value('isbndb.com key', QVariant('')).toString()) self.key.setText(Settings().get('isbndb.com key', ''))
self.setWindowTitle(title if title else 'Unknown') self.setWindowTitle(title if title else 'Unknown')
self.tlabel.setText(self.tlabel.text().arg(title if title else 'Unknown')) self.tlabel.setText(self.tlabel.text().arg(title if title else 'Unknown'))
@ -106,7 +106,7 @@ class FetchMetadata(QDialog, Ui_FetchMetadata):
_('You must specify a valid access key for isbndb.com')) _('You must specify a valid access key for isbndb.com'))
return return
else: else:
Settings().setValue('isbndb.com key', QVariant(self.key.text())) Settings().set('isbndb.com key', str(self.key.text()))
args = ['isbndb'] args = ['isbndb']
if self.isbn: if self.isbn:

View File

@ -106,9 +106,8 @@ class LRFSingleDialog(QDialog, Ui_LRFSingleDialog):
def load_saved_global_defaults(self): def load_saved_global_defaults(self):
cmdline = Settings().value('LRF conversion defaults', QVariant(QByteArray(''))).toByteArray().data() cmdline = Settings().get('LRF conversion defaults')
if cmdline: if cmdline:
cmdline = cPickle.loads(cmdline)
self.set_options_from_cmdline(cmdline) self.set_options_from_cmdline(cmdline)
def set_options_from_cmdline(self, cmdline): def set_options_from_cmdline(self, cmdline):
@ -382,7 +381,7 @@ class LRFSingleDialog(QDialog, Ui_LRFSingleDialog):
cmdline.extend([u'--cover', self.cover_file.name]) cmdline.extend([u'--cover', self.cover_file.name])
self.cmdline = [unicode(i) for i in cmdline] self.cmdline = [unicode(i) for i in cmdline]
else: else:
Settings().setValue('LRF conversion defaults', QVariant(QByteArray(cPickle.dumps(cmdline)))) Settings().set('LRF conversion defaults', cmdline)
QDialog.accept(self) QDialog.accept(self)
class LRFBulkDialog(LRFSingleDialog): class LRFBulkDialog(LRFSingleDialog):

View File

@ -122,8 +122,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>622</width> <width>642</width>
<height>454</height> <height>458</height>
</rect> </rect>
</property> </property>
<layout class="QHBoxLayout" > <layout class="QHBoxLayout" >
@ -435,8 +435,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>622</width> <width>642</width>
<height>454</height> <height>458</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" > <layout class="QGridLayout" >
@ -701,8 +701,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>622</width> <width>642</width>
<height>454</height> <height>458</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" > <layout class="QGridLayout" >
@ -825,8 +825,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>622</width> <width>642</width>
<height>454</height> <height>458</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" > <layout class="QVBoxLayout" >
@ -923,16 +923,6 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="page_5" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>100</width>
<height>30</height>
</rect>
</property>
</widget>
</widget> </widget>
</item> </item>
<item row="1" column="0" > <item row="1" column="0" >
@ -981,7 +971,7 @@
<string>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <string>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css"> &lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
p, li { white-space: pre-wrap; } p, li { white-space: pre-wrap; }
&lt;/style>&lt;/head>&lt;body style=" font-family:'DejaVu Sans'; font-size:10pt; font-weight:400; font-style:normal;"> &lt;/style>&lt;/head>&lt;body style=" font-family:'Candara'; font-size:11pt; font-weight:400; font-style:normal;">
&lt;p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;">&lt;/p>&lt;/body>&lt;/html></string> &lt;p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;">&lt;/p>&lt;/body>&lt;/html></string>
</property> </property>
</widget> </widget>

View File

@ -144,7 +144,7 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
self.edit_tags) self.edit_tags)
QObject.connect(self.remove_series_button, SIGNAL('clicked()'), QObject.connect(self.remove_series_button, SIGNAL('clicked()'),
self.remove_unused_series) self.remove_unused_series)
self.timeout = float(Settings().value('network timeout', QVariant(5)).toInt()[0]) self.timeout = float(Settings().get('network timeout', 5))
self.title.setText(db.title(row)) self.title.setText(db.title(row))
isbn = db.isbn(self.id, index_is_id=True) isbn = db.isbn(self.id, index_is_id=True)
if not isbn: if not isbn:

View File

@ -16,8 +16,8 @@ class PasswordDialog(QDialog, Ui_Dialog):
self.setupUi(self) self.setupUi(self)
settings = Settings() settings = Settings()
un = settings.value(name+': un', QVariant('')).toString() un = settings.get(name+': un', u'')
pw = settings.value(name+': pw', QVariant('')).toString() pw = settings.get(name+': pw', u'')
self.gui_username.setText(un) self.gui_username.setText(un)
self.gui_password.setText(pw) self.gui_password.setText(pw)
self.sname = name self.sname = name
@ -38,6 +38,6 @@ class PasswordDialog(QDialog, Ui_Dialog):
def accept(self): def accept(self):
settings = Settings() settings = Settings()
settings.setValue(self.sname+': un', QVariant(self.gui_username.text())) settings.set(self.sname+': un', unicode(self.gui_username.text()))
settings.setValue(self.sname+': pw', QVariant(self.gui_password.text())) settings.set(self.sname+': pw', unicode(self.gui_password.text()))
QDialog.accept(self) QDialog.accept(self)

View File

@ -258,8 +258,7 @@ class JobManager(QAbstractTableModel):
desc = kwargs.pop('job_description', '') desc = kwargs.pop('job_description', '')
if args and hasattr(args[0], 'append') and '--verbose' not in args[0]: if args and hasattr(args[0], 'append') and '--verbose' not in args[0]:
args[0].append('--verbose') args[0].append('--verbose')
priority = self.PRIORITY[str(Settings().value('conversion job priority', priority = self.PRIORITY[Settings().get('conversion job priority', 'Normal')]
QVariant('Normal')).toString())]
job = self.create_job(ConversionJob, desc, slot, priority, job = self.create_job(ConversionJob, desc, slot, priority,
callable, *args, **kwargs) callable, *args, **kwargs)
return job.id return job.id

View File

@ -5,6 +5,7 @@ from datetime import timedelta, datetime
from operator import attrgetter from operator import attrgetter
from collections import deque from collections import deque
from math import cos, sin, pi from math import cos, sin, pi
from itertools import repeat
from PyQt4.QtGui import QTableView, QProgressDialog, QAbstractItemView, QColor, \ from PyQt4.QtGui import QTableView, QProgressDialog, QAbstractItemView, QColor, \
QItemDelegate, QPainterPath, QLinearGradient, QBrush, \ QItemDelegate, QPainterPath, QLinearGradient, QBrush, \
QPen, QStyle, QPainter, QLineEdit, QApplication, \ QPen, QStyle, QPainter, QLineEdit, QApplication, \
@ -114,8 +115,7 @@ class BooksModel(QAbstractTableModel):
self.load_queue = deque() self.load_queue = deque()
def read_config(self): def read_config(self):
self.use_roman_numbers = bool(Settings().value('use roman numerals for series number', self.use_roman_numbers = Settings().get('use roman numerals for series number', True)
QVariant(True)).toBool())
def set_database(self, db): def set_database(self, db):
@ -594,7 +594,7 @@ class DeviceBooksModel(BooksModel):
base = self.map if refinement else self.sorted_map base = self.map if refinement else self.sorted_map
result = [] result = []
for i in base: for i in base:
q = ['', self.db[i].title, self.db[i].authors, '', ', '.join(self.db[i].tags)] + ['' for j in range(10)] q = ['', self.db[i].title, self.db[i].authors, '', ', '.join(self.db[i].tags)] + list(repeat('', 10))
if OR: if OR:
add = False add = False
for token in tokens: for token in tokens:

View File

@ -103,13 +103,13 @@ class Main(MainWindow, Ui_MainWindow):
def configure(self, triggered): def configure(self, triggered):
opts = cPickle.loads(str(Settings().value('ebook viewer options', QVariant(cPickle.dumps(self.opts))).toString())) opts = Settings().get('LRF ebook viewer options', self.opts)
d = Config(self, opts) d = Config(self, opts)
d.exec_() d.exec_()
if d.result() == QDialog.Accepted: if d.result() == QDialog.Accepted:
opts.white_background = bool(d.white_background.isChecked()) opts.white_background = bool(d.white_background.isChecked())
opts.hyphenate = bool(d.hyphenate.isChecked()) opts.hyphenate = bool(d.hyphenate.isChecked())
Settings().setValue('ebook viewer options', QVariant(cPickle.dumps(opts))) Settings().set('LRF ebook viewer options', opts)
def set_ebook(self, stream): def set_ebook(self, stream):
self.progress_bar.setMinimum(0) self.progress_bar.setMinimum(0)
@ -279,8 +279,7 @@ def option_parser():
return parser return parser
def normalize_settings(parser, opts): def normalize_settings(parser, opts):
settings = Settings() saved_opts = Settings().get('LRF ebook viewer options', opts)
saved_opts = cPickle.loads(str(settings.value('ebook viewer options', QVariant(cPickle.dumps(opts))).toString()))
for opt in parser.option_list: for opt in parser.option_list:
if not opt.dest: if not opt.dest:
continue continue

View File

@ -4,7 +4,7 @@ import os, sys, textwrap, collections, traceback, shutil, time
from xml.parsers.expat import ExpatError from xml.parsers.expat import ExpatError
from functools import partial from functools import partial
from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, \ from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, \
QVariant, QThread, QString, QSize, QUrl QVariant, QThread, QSize, QUrl
from PyQt4.QtGui import QPixmap, QColor, QPainter, QMenu, QIcon, QMessageBox, \ from PyQt4.QtGui import QPixmap, QColor, QPainter, QMenu, QIcon, QMessageBox, \
QToolButton, QDialog, QDesktopServices QToolButton, QDialog, QDesktopServices
from PyQt4.QtSvg import QSvgRenderer from PyQt4.QtSvg import QSvgRenderer
@ -18,7 +18,7 @@ from calibre.devices.interface import Device
from calibre.gui2 import APP_UID, warning_dialog, choose_files, error_dialog, \ from calibre.gui2 import APP_UID, warning_dialog, choose_files, error_dialog, \
initialize_file_icon_provider, question_dialog,\ initialize_file_icon_provider, question_dialog,\
pixmap_to_data, choose_dir, ORG_NAME, \ pixmap_to_data, choose_dir, ORG_NAME, \
qstring_to_unicode, set_sidebar_directories, \ set_sidebar_directories, \
SingleApplication, Application, available_height SingleApplication, Application, available_height
from calibre.gui2.cover_flow import CoverFlow, DatabaseImages from calibre.gui2.cover_flow import CoverFlow, DatabaseImages
from calibre.library.database import LibraryDatabase from calibre.library.database import LibraryDatabase
@ -979,7 +979,7 @@ class Main(MainWindow, Ui_MainWindow):
newloc = self.database_path newloc = self.database_path
self.database_path = newloc self.database_path = newloc
settings = Settings() settings = Settings()
settings.setValue("database path", QVariant(self.database_path)) settings.set('database path', self.database_path)
except Exception, err: except Exception, err:
traceback.print_exc() traceback.print_exc()
d = error_dialog(self, _('Could not move database'), unicode(err)) d = error_dialog(self, _('Could not move database'), unicode(err))
@ -1087,13 +1087,11 @@ class Main(MainWindow, Ui_MainWindow):
def read_settings(self): def read_settings(self):
settings = Settings() settings = Settings()
settings.beginGroup("Main Window") settings.beginGroup('Main Window')
geometry = settings.value('main window geometry', QVariant()).toByteArray() geometry = settings.value('main window geometry', QVariant()).toByteArray()
self.restoreGeometry(geometry) self.restoreGeometry(geometry)
settings.endGroup() settings.endGroup()
dbpath = os.path.join(os.path.expanduser('~'), 'library1.db').decode(sys.getfilesystemencoding()) self.database_path = settings.get('database path')
self.database_path = qstring_to_unicode(settings.value("database path",
QVariant(QString.fromUtf8(dbpath.encode('utf-8')))).toString())
if not os.access(os.path.dirname(self.database_path), os.W_OK): if not os.access(os.path.dirname(self.database_path), os.W_OK):
error_dialog(self, _('Database does not exist'), _('The directory in which the database should be: %s no longer exists. Please choose a new database location.')%self.database_path).exec_() error_dialog(self, _('Database does not exist'), _('The directory in which the database should be: %s no longer exists. Please choose a new database location.')%self.database_path).exec_()
self.database_path = choose_dir(self, 'database path dialog', 'Choose new location for database') self.database_path = choose_dir(self, 'database path dialog', 'Choose new location for database')
@ -1102,10 +1100,10 @@ class Main(MainWindow, Ui_MainWindow):
if not os.path.exists(self.database_path): if not os.path.exists(self.database_path):
os.makedirs(self.database_path) os.makedirs(self.database_path)
self.database_path = os.path.join(self.database_path, 'library1.db') self.database_path = os.path.join(self.database_path, 'library1.db')
settings.setValue('database path', QVariant(QString.fromUtf8(self.database_path.encode('utf-8')))) settings.set('database path', self.database_path)
set_sidebar_directories(None) set_sidebar_directories(None)
set_filename_pat(qstring_to_unicode(settings.value('filename pattern', QVariant(get_filename_pat())).toString())) set_filename_pat(settings.get('filename pattern', get_filename_pat()))
self.tool_bar.setIconSize(settings.value('toolbar icon size', QVariant(QSize(48, 48))).toSize()) self.tool_bar.setIconSize(settings.get('toolbar icon size', QSize(48, 48)))
self.tool_bar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon if settings.get('show text in toolbar', True) else Qt.ToolButtonIconOnly) self.tool_bar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon if settings.get('show text in toolbar', True) else Qt.ToolButtonIconOnly)

View File

@ -330,7 +330,7 @@ For help on an individual command: %%prog command --help
return 1 return 1
command = eval('command_'+args[1]) command = eval('command_'+args[1])
dbpath = unicode(Settings().value('database path', QVariant(os.path.expanduser('~/library1.db'))).toString()) dbpath = Settings().get('database path')
return command(args[2:], dbpath) return command(args[2:], dbpath)

View File

@ -1,11 +1,14 @@
#!/usr/bin/python #!/usr/bin/python
import tempfile import sys, os, shutil, time, tempfile, socket
import sys, os, shutil, time
sys.path.append('src') sys.path.append('src')
import subprocess import subprocess
from subprocess import check_call as _check_call from subprocess import check_call as _check_call
from functools import partial from functools import partial
#from pyvix.vix import Host, VIX_SERVICEPROVIDER_VMWARE_WORKSTATION #from pyvix.vix import Host, VIX_SERVICEPROVIDER_VMWARE_WORKSTATION
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('google.com', 0))
HOST=s.getsockname()[0]
PROJECT=os.path.basename(os.getcwd())
from calibre import __version__, __appname__ from calibre import __version__, __appname__
@ -15,6 +18,15 @@ DOCS = PREFIX+"/htdocs/apidocs"
USER_MANUAL = PREFIX+'/htdocs/user_manual' USER_MANUAL = PREFIX+'/htdocs/user_manual'
HTML2LRF = "src/calibre/ebooks/lrf/html/demo" HTML2LRF = "src/calibre/ebooks/lrf/html/demo"
TXT2LRF = "src/calibre/ebooks/lrf/txt/demo" TXT2LRF = "src/calibre/ebooks/lrf/txt/demo"
BUILD_SCRIPT ='''\
#!/bin/bash
cd ~/build && \
rsync -avz --exclude docs --exclude .bzr --exclude .build --exclude build --exclude dist --exclude "*.pyc" --exclude "*.pyo" rsync://%(host)s/work/%(project)s . && \
cd %(project)s && \
mkdir -p build dist && \
rm -rf build/* dist/* && \
python %%s
'''%dict(host=HOST, project=PROJECT)
check_call = partial(_check_call, shell=True) check_call = partial(_check_call, shell=True)
#h = Host(hostType=VIX_SERVICEPROVIDER_VMWARE_WORKSTATION) #h = Host(hostType=VIX_SERVICEPROVIDER_VMWARE_WORKSTATION)
@ -29,15 +41,23 @@ def installer_name(ext):
return 'dist/%s-%s.%s'%(__appname__, __version__, ext) return 'dist/%s-%s.%s'%(__appname__, __version__, ext)
return 'dist/%s-%s-i686.%s'%(__appname__, __version__, ext) return 'dist/%s-%s-i686.%s'%(__appname__, __version__, ext)
def start_vm(vm, ssh_host, build_script, sleep):
vmware = ('vmware', '-q', '-x', '-n', vm)
subprocess.Popen(vmware)
t = tempfile.NamedTemporaryFile(suffix='.sh')
t.write(build_script)
t.flush()
print 'Waiting for VM to startup'
time.sleep(sleep)
print 'Trying to SSH into VM'
subprocess.check_call(('scp', t.name, ssh_host+':build-'+PROJECT))
def build_windows(): def build_windows():
installer = installer_name('exe') installer = installer_name('exe')
vm = '/vmware/Windows XP/Windows XP Professional.vmx' vm = '/vmware/Windows XP/Windows XP Professional.vmx'
vmware = ('vmware', '-q', '-x', '-n', vm) start_vm(vm, 'windows', BUILD_SCRIPT%'windows_installer.py', 75)
subprocess.Popen(vmware) subprocess.check_call(('ssh', 'windows', '/bin/bash', '~/build-'+PROJECT))
print 'Waiting for Windows to boot up...' subprocess.check_call(('scp', 'windows:build/%s/dist/*.exe'%PROJECT, 'dist'))
time.sleep(75)
print 'Trying to ssh into the Windows SSH server'
subprocess.check_call(('ssh', 'windows', '/usr/local/bin/build-calibre', os.path.basename(os.getcwd())))
if not os.path.exists(installer): if not os.path.exists(installer):
raise Exception('Failed to build installer '+installer) raise Exception('Failed to build installer '+installer)
subprocess.Popen(('ssh', 'windows', 'shutdown', '-s', '-t', '0')) subprocess.Popen(('ssh', 'windows', 'shutdown', '-s', '-t', '0'))
@ -47,11 +67,9 @@ def build_osx():
installer = installer_name('dmg') installer = installer_name('dmg')
vm = '/vmware/Mac OSX/Mac OSX.vmx' vm = '/vmware/Mac OSX/Mac OSX.vmx'
vmware = ('vmware', '-q', '-x', '-n', vm) vmware = ('vmware', '-q', '-x', '-n', vm)
subprocess.Popen(vmware) start_vm(vm, 'osx', BUILD_SCRIPT%'osx_installer.py', 120)
print 'Waiting for OS X to boot up...' subprocess.check_call(('ssh', 'osx', '/bin/bash', '~/build-'+PROJECT))
time.sleep(120) subprocess.check_call(('scp', 'windows:build/%s/dist/*.dmg'%PROJECT, 'dist'))
print 'Trying to ssh into the OS X SSH server'
subprocess.check_call(('ssh', 'osx', '/Users/kovid/bin/build-calibre', os.path.basename(os.getcwd())))
if not os.path.exists(installer): if not os.path.exists(installer):
raise Exception('Failed to build installer '+installer) raise Exception('Failed to build installer '+installer)
subprocess.Popen(('ssh', 'osx', 'sudo', '/sbin/shutdown', '-h', 'now')) subprocess.Popen(('ssh', 'osx', 'sudo', '/sbin/shutdown', '-h', 'now'))
@ -62,9 +80,9 @@ def _build_linux():
tbz2 = os.path.join(cwd, installer_name('tar.bz2')) tbz2 = os.path.join(cwd, installer_name('tar.bz2'))
SPEC="""\ SPEC="""\
import os import os
HOME = '%s' HOME = '%(home)s'
PYINSTALLER = os.path.expanduser('~/build/pyinstaller') PYINSTALLER = os.path.expanduser('~/build/pyinstaller')
CALIBREPREFIX = HOME+'/work/calibre' CALIBREPREFIX = HOME+'/work/%(project)s'
CLIT = '/usr/bin/clit' CLIT = '/usr/bin/clit'
PDFTOHTML = '/usr/bin/pdftohtml' PDFTOHTML = '/usr/bin/pdftohtml'
LIBUNRAR = '/usr/lib/libunrar.so' LIBUNRAR = '/usr/lib/libunrar.so'
@ -180,12 +198,12 @@ for folder in EXTRAS:
subprocess.check_call('cp -rf %%s .'%%folder, shell=True) subprocess.check_call('cp -rf %%s .'%%folder, shell=True)
print 'Building tarball...' print 'Building tarball...'
tf = tarfile.open('%s', 'w:bz2') tf = tarfile.open('%(tarfile)s', 'w:bz2')
for f in os.listdir('.'): for f in os.listdir('.'):
tf.add(f) tf.add(f)
"""%('/mnt/hgfs/giskard/', tbz2) """%dict(home='/mnt/hgfs/giskard/', tarfile=tbz2, project=PROJECT)
os.chdir(os.path.expanduser('~/build/pyinstaller')) os.chdir(os.path.expanduser('~/build/pyinstaller'))
open('calibre/calibre.spec', 'wb').write(SPEC) open('calibre/calibre.spec', 'wb').write(SPEC)
try: try:
@ -200,7 +218,7 @@ def build_linux():
subprocess.Popen(vmware) subprocess.Popen(vmware)
print 'Waiting for linux to boot up...' print 'Waiting for linux to boot up...'
time.sleep(75) time.sleep(75)
check_call('ssh linux make -C /mnt/hgfs/giskard/work/calibre all egg linux_binary') check_call('ssh linux make -C /mnt/hgfs/giskard/work/%s all egg linux_binary'%PROJECT)
check_call('ssh linux sudo poweroff') check_call('ssh linux sudo poweroff')
def build_installers(): def build_installers():

View File

@ -424,96 +424,6 @@ SectionEnd
else: else:
os.remove(path) os.remove(path)
class WixInstaller(object):
'''
Make a .msi installer. Can't get the driver installation to play well with
an existing installation of the connect USB driver. Pick this up again when
libusb1.dll is released based on winusb.
'''
TEMPLATE=\
r'''<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2003/01/wi'>
<Product Name='%(appname)s' Id='955DF7A2-8861-46A9-8710-56A4BDEA8E29'
Language='1033' Codepage='1252' Version='%(version)s' Manufacturer='Kovid Goyal'>
<Package Id='????????-????-????-????-????????????' Keywords='Installer'
Description="Ebook management software"
Manufacturer='Kovid Goyal'
InstallerVersion='100' Languages='1033' Compressed='yes' SummaryCodepage='1252' />
<Icon Id="appicon.ico" SourceFile="icons\library.ico" />
<Binary Id="devcon" SourceFile="C:\devcon\i386\devcon.exe" />
<Condition Message="You need to be an administrator to install this product.">
Privileged
</Condition>
<Property Id='ARPNOMODIFY'>1</Property>
<Property Id='ARPURLINFOABOUT'>http://calibre.kovidgoyal.net</Property>
<Property Id='ARPPRODUCTICON'>appicon.ico</Property>
<Media Id='1' Cabinet='%(appname)s.cab' EmbedCab='yes' />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder' Name='PFiles'>
<Directory Id='INSTALLDIR' Name='libprs' LongName='%(appname)s'>
%(py2exefiles)s
<Directory Id='driver' Name='driver' FileSource="C:\libusb-prs500">
<Component Id="usbdriver" DriverSequence="0" Guid="1169D502-DE59-4153-BC0D-712894C37FEF">
<File Id='libusb0.dll' Name='libusb0.dll' Vital='yes' Compressed='yes' DiskId="1" />
<File Id='libusb0.sys' Name='libusb0.sys' Vital='yes' Compressed='yes' DiskId="1" />
<File Id='libusb0_x64.dll' Name='a' LongName='libusb0_x64.dll' Vital='yes' Compressed='yes' DiskId="1" />
<File Id='libusb0_x64.sys' Name='b' LongName='libusb0_x64.sys' Vital='yes' Compressed='yes' DiskId="1" />
<File Id='prs500.inf' Name='prs500.inf' Vital='yes' Compressed='yes' DiskId="1" />
</Component>
</Directory>
</Directory>
</Directory>
<Component Id='misc' Guid=''>
<Environment Id='UpdatePath' Name='PATH' Action='create' System='yes'
Part='last' Value='[INSTALLDIR]' Permanent="no"/>
</Component>
</Directory>
<Feature Id='Complete' Title="%(appname)s" Description="The complete package">
<ComponentRef Id='py2exe' />
<ComponentRef Id='usbdriver' />
<ComponentRef Id='misc' />
</Feature>
</Product>
</Wix>
'''
CANDLE=r'C:\wix\candle.exe '
LIGHT=r'C:\wix\light.exe -out %s -loc C:\wix\WixUI_en-us.wxl %s c:\wix\wixui.wixlib "C:\Program Files\Driver Installation Tools 2.01\DIFxApp\English-US\WiXLib\x86\DIFxApp.wixlib"'
def __init__(self, py2exe_dir, dest_dir='dist'):
self.py2exe_dir = py2exe_dir
self.dest_dir = dest_dir
filelist = []
print self.py2exe_dir
for root, dirs, files in os.walk(self.py2exe_dir):
for name in files:
path = os.path.abspath(os.path.join(root, name))
filelist.append(path)
component = "<Component Id='py2exe' DiskId='1' Guid='0248CACF-FDF5-4E68-B898-227C16F1C7B8'>\n"
counter = 0
for path in filelist:
entry = '<File Id="file%d" Name="fn%d" Compressed="yes" Vital="yes" Source="%s" LongName="%s" />'%\
(counter, counter, path, os.path.basename(path))
component += entry + "\n"
counter += 1
component += '</Component>'
self.installer = self.TEMPLATE%dict(appname=APPNAME, version=VERSION,
py2exefiles=component)
def build(self):
f = open('installer.wxs', 'w')
f.write(self.installer)
f.close()
subprocess.check_call(self.CANDLE + ' ' + f.name, shell=True)
subprocess.check_call(self.LIGHT%(os.path.join(self.dest_dir, APPNAME + '-' + VERSION + '.msi'),
' installer.wixobj'), shell=True)
os.remove('installer.wxs')
os.remove('installer.wixobj')
class BuildEXE(build_exe): class BuildEXE(build_exe):
manifest_resource_id = 0 manifest_resource_id = 0
@ -559,9 +469,9 @@ class BuildEXE(build_exe):
subprocess.check_call(['mingw32-make', '-f', 'Makefile']) subprocess.check_call(['mingw32-make', '-f', 'Makefile'])
shutil.copyfile('pictureflow.pyd', os.path.join(dd, 'pictureflow.pyd')) shutil.copyfile('pictureflow.pyd', os.path.join(dd, 'pictureflow.pyd'))
os.chdir('..') os.chdir('..')
shutil.rmtree('.build') shutil.rmtree('.build', True)
os.chdir('..') os.chdir('..')
shutil.rmtree('.build') shutil.rmtree('.build', True)
finally: finally:
os.chdir(cwd) os.chdir(cwd)