~ubuntu-branches/ubuntu/karmic/calibre/karmic

« back to all changes in this revision

Viewing changes to src/calibre/gui2/dialogs/config.py

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-07-30 12:49:41 UTC
  • mfrom: (1.3.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20090730124941-qjdsmri25zt8zocn
Tags: 0.6.3+dfsg-0ubuntu1
* New upstream release. Please see http://calibre.kovidgoyal.net/new_in_6/
  for the list of new features and changes.
* remove_postinstall.patch: Update for new version.
* build_debug.patch: Does not apply any more, disable for now. Might not be
  necessary any more.
* debian/copyright: Fix reference to versionless GPL.
* debian/rules: Drop obsolete dh_desktop call.
* debian/rules: Add workaround for weird Python 2.6 setuptools behaviour of
  putting compiled .so files into src/calibre/plugins/calibre/plugins
  instead of src/calibre/plugins.
* debian/rules: Drop hal fdi moving, new upstream version does not use hal
  any more. Drop hal dependency, too.
* debian/rules: Install udev rules into /lib/udev/rules.d.
* Add debian/calibre.preinst: Remove unmodified
  /etc/udev/rules.d/95-calibre.rules on upgrade.
* debian/control: Bump Python dependencies to 2.6, since upstream needs
  it now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
__license__   = 'GPL v3'
2
2
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
3
 
import os, re, time, textwrap, sys, cStringIO
4
 
from binascii import hexlify, unhexlify
 
3
import os, re, time, textwrap
5
4
 
6
5
from PyQt4.Qt import    QDialog, QMessageBox, QListWidgetItem, QIcon, \
7
6
                        QDesktopServices, QVBoxLayout, QLabel, QPlainTextEdit, \
8
7
                        QStringListModel, QAbstractItemModel, QFont, \
9
8
                        SIGNAL, QTimer, Qt, QSize, QVariant, QUrl, \
10
 
                        QModelIndex, QInputDialog, QAbstractTableModel
 
9
                        QModelIndex, QInputDialog, QAbstractTableModel, \
 
10
                        QDialogButtonBox, QTabWidget, QBrush, QLineEdit
11
11
 
12
12
from calibre.constants import islinux, iswindows
13
13
from calibre.gui2.dialogs.config_ui import Ui_Dialog
14
 
from calibre.gui2.dialogs.test_email_ui import Ui_Dialog as TE_Dialog
15
14
from calibre.gui2 import qstring_to_unicode, choose_dir, error_dialog, config, \
16
15
                         ALL_COLUMNS, NONE, info_dialog, choose_files
17
16
from calibre.utils.config import prefs
18
17
from calibre.gui2.widgets import FilenamePattern
19
18
from calibre.gui2.library import BooksModel
20
19
from calibre.ebooks import BOOK_EXTENSIONS
21
 
from calibre.ebooks.epub.iterator import is_supported
 
20
from calibre.ebooks.oeb.iterator import is_supported
22
21
from calibre.library import server_config
23
22
from calibre.customize.ui import initialized_plugins, is_disabled, enable_plugin, \
24
23
                                 disable_plugin, customize_plugin, \
25
 
                                 plugin_customization, add_plugin, remove_plugin
 
24
                                 plugin_customization, add_plugin, \
 
25
                                 remove_plugin, all_input_formats, \
 
26
                                 input_format_plugins, \
 
27
                                 output_format_plugins, available_output_formats
26
28
from calibre.utils.smtp import config as smtp_prefs
 
29
from calibre.gui2.convert.look_and_feel import LookAndFeelWidget
 
30
from calibre.gui2.convert.page_setup import PageSetupWidget
 
31
from calibre.gui2.convert.structure_detection import StructureDetectionWidget
 
32
from calibre.ebooks.conversion.plumber import Plumber
 
33
from calibre.utils.logging import Log
 
34
from calibre.gui2.convert.toc import TOCWidget
 
35
 
 
36
class ConfigTabs(QTabWidget):
 
37
 
 
38
    def __init__(self, parent):
 
39
        QTabWidget.__init__(self, parent)
 
40
        log = Log()
 
41
        log.outputs = []
 
42
 
 
43
        self.plumber = Plumber('dummy.epub', 'dummy.epub', log, dummy=True)
 
44
 
 
45
        def widget_factory(cls):
 
46
            return cls(self, self.plumber.get_option_by_name,
 
47
                self.plumber.get_option_help, None, None)
 
48
 
 
49
        lf = widget_factory(LookAndFeelWidget)
 
50
        ps = widget_factory(PageSetupWidget)
 
51
        sd = widget_factory(StructureDetectionWidget)
 
52
        toc = widget_factory(TOCWidget)
 
53
 
 
54
        self.widgets = [lf, ps, sd, toc]
 
55
 
 
56
        for plugin in input_format_plugins():
 
57
            name = plugin.name.lower().replace(' ', '_')
 
58
            try:
 
59
                input_widget = __import__('calibre.gui2.convert.'+name,
 
60
                        fromlist=[1])
 
61
                pw = input_widget.PluginWidget
 
62
                pw.ICON = ':/images/forward.svg'
 
63
                self.widgets.append(widget_factory(pw))
 
64
            except ImportError:
 
65
                continue
 
66
 
 
67
        for plugin in output_format_plugins():
 
68
            name = plugin.name.lower().replace(' ', '_')
 
69
            try:
 
70
                output_widget = __import__('calibre.gui2.convert.'+name,
 
71
                        fromlist=[1])
 
72
                pw = output_widget.PluginWidget
 
73
                pw.ICON = ':/images/forward.svg'
 
74
                self.widgets.append(widget_factory(pw))
 
75
            except ImportError:
 
76
                continue
 
77
 
 
78
        for i, widget in enumerate(self.widgets):
 
79
            self.addTab(widget, widget.TITLE.replace('\n', ' ').replace('&',
 
80
            '&&'))
 
81
            self.setTabToolTip(i, widget.HELP if widget.HELP else widget.TITLE)
 
82
        self.setUsesScrollButtons(True)
 
83
 
 
84
    def commit(self):
 
85
        for widget in self.widgets:
 
86
            if not widget.pre_commit_check():
 
87
                return False
 
88
            widget.commit(save_defaults=True)
 
89
        return True
 
90
 
27
91
 
28
92
class PluginModel(QAbstractItemModel):
29
93
 
30
94
    def __init__(self, *args):
31
95
        QAbstractItemModel.__init__(self, *args)
32
96
        self.icon = QVariant(QIcon(':/images/plugins.svg'))
 
97
        p = QIcon(self.icon).pixmap(32, 32, QIcon.Disabled, QIcon.On)
 
98
        self.disabled_icon = QVariant(QIcon(p))
 
99
        self._p = p
33
100
        self.populate()
34
101
 
35
102
    def populate(self):
46
113
            return QModelIndex()
47
114
 
48
115
        if parent.isValid():
49
 
            return self.createIndex(row, column, parent.row())
 
116
            return self.createIndex(row, column, 1+parent.row())
50
117
        else:
51
 
            return self.createIndex(row, column, -1)
 
118
            return self.createIndex(row, column, 0)
52
119
 
53
120
    def parent(self, index):
54
 
        if not index.isValid() or index.internalId() == -1:
 
121
        if not index.isValid() or index.internalId() == 0:
55
122
            return QModelIndex()
56
 
        return self.createIndex(index.internalId(), 0, -1)
 
123
        return self.createIndex(index.internalId()-1, 0, 0)
57
124
 
58
125
    def rowCount(self, parent):
59
126
        if not parent.isValid():
60
127
            return len(self.categories)
61
 
        if parent.internalId() == -1:
 
128
        if parent.internalId() == 0:
62
129
            category = self.categories[parent.row()]
63
130
            return len(self._data[category])
64
131
        return 0
87
154
    def flags(self, index):
88
155
        if not index.isValid():
89
156
            return 0
90
 
        if index.internalId() == -1:
 
157
        if index.internalId() == 0:
91
158
            return Qt.ItemIsEnabled
92
 
        flags = Qt.ItemIsSelectable
93
 
        if not is_disabled(self.data(index, Qt.UserRole)):
94
 
            flags |= Qt.ItemIsEnabled
 
159
        flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled
95
160
        return flags
96
161
 
97
162
    def data(self, index, role):
98
163
        if not index.isValid():
99
164
            return NONE
100
 
        if index.internalId() == -1:
 
165
        if index.internalId() == 0:
101
166
            if role == Qt.DisplayRole:
102
167
                category = self.categories[index.row()]
103
168
                return QVariant(category + _(' plugins'))
112
177
                    ans += '\nCustomization: '+c
113
178
                return QVariant(ans)
114
179
            if role == Qt.DecorationRole:
115
 
                return self.icon
 
180
                return self.disabled_icon if is_disabled(plugin) else self.icon
 
181
            if role == Qt.ForegroundRole and is_disabled(plugin):
 
182
                return QVariant(QBrush(Qt.gray))
116
183
            if role == Qt.UserRole:
117
184
                return plugin
118
185
        return NONE
123
190
 
124
191
    def __init__(self, *args):
125
192
        QStringListModel.__init__(self, *args)
126
 
        self.setStringList([_('General'), _('Interface'), _('Email\nDelivery'),
 
193
        self.setStringList([_('General'), _('Interface'), _('Conversion'),
 
194
                            _('Email\nDelivery'),
127
195
                            _('Advanced'), _('Content\nServer'), _('Plugins')])
128
196
        self.icons = list(map(QVariant, map(QIcon,
129
197
            [':/images/dialog_information.svg', ':/images/lookfeel.svg',
 
198
                ':/images/convert.svg',
130
199
             ':/images/mail.svg', ':/images/view.svg',
131
200
             ':/images/network-server.svg', ':/images/plugins.svg'])))
132
201
 
135
204
            return self.icons[index.row()]
136
205
        return QStringListModel.data(self, index, role)
137
206
 
138
 
class TestEmail(QDialog, TE_Dialog):
139
 
 
140
 
    def __init__(self, accounts, parent):
141
 
        QDialog.__init__(self, parent)
142
 
        TE_Dialog.__init__(self)
143
 
        self.setupUi(self)
144
 
        opts = smtp_prefs().parse()
145
 
        self.test_func = parent.test_email_settings
146
 
        self.connect(self.test_button, SIGNAL('clicked(bool)'), self.test)
147
 
        self.from_.setText(unicode(self.from_.text())%opts.from_)
148
 
        if accounts:
149
 
            self.to.setText(list(accounts.keys())[0])
150
 
        if opts.relay_host:
151
 
            self.label.setText(_('Using: %s:%s@%s:%s and %s encryption')%
152
 
                    (opts.relay_username, unhexlify(opts.relay_password),
153
 
                        opts.relay_host, opts.relay_port, opts.encryption))
154
 
 
155
 
    def test(self):
156
 
        self.log.setPlainText(_('Sending...'))
157
 
        self.test_button.setEnabled(False)
158
 
        try:
159
 
            tb = self.test_func(unicode(self.to.text()))
160
 
            if not tb:
161
 
                tb = _('Mail successfully sent')
162
 
            self.log.setPlainText(tb)
163
 
        finally:
164
 
            self.test_button.setEnabled(True)
165
 
 
166
207
class EmailAccounts(QAbstractTableModel):
167
208
 
168
209
    def __init__(self, accounts):
297
338
        self.connect(self.browse_button, SIGNAL('clicked(bool)'), self.browse)
298
339
        self.connect(self.compact_button, SIGNAL('clicked(bool)'), self.compact)
299
340
 
 
341
        input_map = prefs['input_format_order']
 
342
        all_formats = set()
 
343
        for fmt in all_input_formats():
 
344
            all_formats.add(fmt.upper())
 
345
        for format in input_map + list(all_formats.difference(input_map)):
 
346
            item = QListWidgetItem(format, self.input_order)
 
347
            item.setData(Qt.UserRole, QVariant(format))
 
348
            item.setFlags(Qt.ItemIsEnabled|Qt.ItemIsSelectable)
 
349
 
 
350
        self.connect(self.input_up, SIGNAL('clicked()'), self.up_input)
 
351
        self.connect(self.input_down, SIGNAL('clicked()'), self.down_input)
 
352
 
300
353
        dirs = config['frequently_used_directories']
301
354
        rn = config['use_roman_numerals_for_series_number']
302
355
        self.timeout.setValue(prefs['network_timeout'])
325
378
        self.toolbar_button_size.setCurrentIndex(0 if icons == self.ICON_SIZES[0] else 1 if icons == self.ICON_SIZES[1] else 2)
326
379
        self.show_toolbar_text.setChecked(config['show_text_in_toolbar'])
327
380
 
328
 
        self.book_exts = sorted(BOOK_EXTENSIONS)
329
 
        for ext in self.book_exts:
330
 
            self.single_format.addItem(ext.upper(), QVariant(ext))
331
 
 
332
 
        single_format = config['save_to_disk_single_format']
333
 
        self.single_format.setCurrentIndex(self.book_exts.index(single_format))
 
381
        output_formats = sorted(available_output_formats())
 
382
        output_formats.remove('oeb')
 
383
        for f in output_formats:
 
384
            self.output_format.addItem(f.upper())
 
385
        default_index = \
 
386
            self.output_format.findText(prefs['output_format'].upper())
 
387
        self.output_format.setCurrentIndex(default_index if default_index != -1 else 0)
 
388
 
 
389
 
334
390
        self.cover_browse.setValue(config['cover_flow_queue_length'])
335
391
        self.systray_notifications.setChecked(not config['disable_tray_notification'])
336
392
        from calibre.translations.compiled import translations
352
408
 
353
409
        self.pdf_metadata.setChecked(prefs['read_file_metadata'])
354
410
 
355
 
        added_html = False
356
 
        for ext in self.book_exts:
 
411
        exts = set([])
 
412
        for ext in BOOK_EXTENSIONS:
357
413
            ext = ext.lower()
358
414
            ext = re.sub(r'(x{0,1})htm(l{0,1})', 'html', ext)
359
415
            if ext == 'lrf' or is_supported('book.'+ext):
360
 
                if ext == 'html' and added_html:
361
 
                    continue
362
 
                self.viewer.addItem(ext.upper())
363
 
                self.viewer.item(self.viewer.count()-1).setFlags(Qt.ItemIsEnabled|Qt.ItemIsUserCheckable)
364
 
                self.viewer.item(self.viewer.count()-1).setCheckState(Qt.Checked if ext.upper() in config['internally_viewed_formats'] else Qt.Unchecked)
365
 
                added_html = ext == 'html'
 
416
                exts.add(ext)
 
417
 
 
418
        for ext in sorted(exts):
 
419
            self.viewer.addItem(ext.upper())
 
420
            self.viewer.item(self.viewer.count()-1).setFlags(Qt.ItemIsEnabled|Qt.ItemIsUserCheckable)
 
421
            self.viewer.item(self.viewer.count()-1).setCheckState(Qt.Checked if ext.upper() in config['internally_viewed_formats'] else Qt.Unchecked)
366
422
        self.viewer.sortItems()
367
423
        self.start.setEnabled(not getattr(self.server, 'is_running', False))
368
424
        self.test.setEnabled(not self.start.isEnabled())
381
437
        self.password.setText(opts.password if opts.password else '')
382
438
        self.auto_launch.setChecked(config['autolaunch_server'])
383
439
        self.systray_icon.setChecked(config['systray_icon'])
 
440
        self.search_as_you_type.setChecked(config['search_as_you_type'])
384
441
        self.sync_news.setChecked(config['upload_news_to_device'])
385
442
        self.delete_news.setChecked(config['delete_news_from_library_on_upload'])
386
443
        p = {'normal':0, 'high':1, 'low':2}[prefs['worker_process_priority']]
400
457
        self.delete_news.setEnabled(bool(self.sync_news.isChecked()))
401
458
        self.connect(self.sync_news, SIGNAL('toggled(bool)'),
402
459
                self.delete_news.setEnabled)
 
460
        self.setup_conversion_options()
 
461
 
 
462
    def setup_conversion_options(self):
 
463
        self.conversion_options = ConfigTabs(self)
 
464
        self.stackedWidget.insertWidget(2, self.conversion_options)
403
465
 
404
466
    def setup_email_page(self):
405
 
        opts = smtp_prefs().parse()
406
 
        if opts.from_:
407
 
            self.email_from.setText(opts.from_)
 
467
        def x():
 
468
            if self._email_accounts.account_order:
 
469
                return self._email_accounts.account_order[0]
 
470
        self.send_email_widget.initialize(x)
 
471
        opts = self.send_email_widget.smtp_opts
408
472
        self._email_accounts = EmailAccounts(opts.accounts)
409
473
        self.email_view.setModel(self._email_accounts)
410
 
        if opts.relay_host:
411
 
            self.relay_host.setText(opts.relay_host)
412
 
        self.relay_port.setValue(opts.relay_port)
413
 
        if opts.relay_username:
414
 
            self.relay_username.setText(opts.relay_username)
415
 
        if opts.relay_password:
416
 
            self.relay_password.setText(unhexlify(opts.relay_password))
417
 
        (self.relay_tls if opts.encryption == 'TLS' else self.relay_ssl).setChecked(True)
418
 
        self.connect(self.relay_use_gmail, SIGNAL('clicked(bool)'),
419
 
                     self.create_gmail_relay)
420
 
        self.connect(self.relay_show_password, SIGNAL('stateChanged(int)'),
421
 
         lambda
422
 
         state:self.relay_password.setEchoMode(self.relay_password.Password if
423
 
             state == 0 else self.relay_password.Normal))
 
474
 
424
475
        self.connect(self.email_add, SIGNAL('clicked(bool)'),
425
476
                     self.add_email_account)
426
477
        self.connect(self.email_make_default, SIGNAL('clicked(bool)'),
427
478
             lambda c: self._email_accounts.make_default(self.email_view.currentIndex()))
428
479
        self.email_view.resizeColumnsToContents()
429
 
        self.connect(self.test_email_button, SIGNAL('clicked(bool)'),
430
 
                self.test_email)
431
480
        self.connect(self.email_remove, SIGNAL('clicked()'),
432
481
                self.remove_email_account)
433
482
 
441
490
        idx = self.email_view.currentIndex()
442
491
        self._email_accounts.remove(idx)
443
492
 
444
 
    def create_gmail_relay(self, *args):
445
 
        self.relay_username.setText('@gmail.com')
446
 
        self.relay_password.setText('')
447
 
        self.relay_host.setText('smtp.gmail.com')
448
 
        self.relay_port.setValue(587)
449
 
        self.relay_tls.setChecked(True)
450
 
 
451
 
        info_dialog(self, _('Finish gmail setup'),
452
 
            _('Dont forget to enter your gmail username and password')).exec_()
453
 
        self.relay_username.setFocus(Qt.OtherFocusReason)
454
 
        self.relay_username.setCursorPosition(0)
455
 
 
456
493
    def set_email_settings(self):
457
 
        from_ = unicode(self.email_from.text()).strip()
458
 
        if self._email_accounts.accounts and not from_:
459
 
            error_dialog(self, _('Bad configuration'),
460
 
                         _('You must set the From email address')).exec_()
461
 
            return False
462
 
        username = unicode(self.relay_username.text()).strip()
463
 
        password = unicode(self.relay_password.text()).strip()
464
 
        host = unicode(self.relay_host.text()).strip()
465
 
        if host and not (username and password):
466
 
            error_dialog(self, _('Bad configuration'),
467
 
                         _('You must set the username and password for '
468
 
                           'the mail server.')).exec_()
 
494
        to_set = bool(self._email_accounts.accounts)
 
495
        if not self.send_email_widget.set_email_settings(to_set):
469
496
            return False
470
497
        conf = smtp_prefs()
471
 
        conf.set('from_', from_)
472
498
        conf.set('accounts', self._email_accounts.accounts)
473
 
        conf.set('relay_host', host if host else None)
474
 
        conf.set('relay_port', self.relay_port.value())
475
 
        conf.set('relay_username', username if username else None)
476
 
        conf.set('relay_password', hexlify(password))
477
 
        conf.set('encryption', 'TLS' if self.relay_tls.isChecked() else 'SSL')
478
499
        return True
479
500
 
480
 
    def test_email(self, *args):
481
 
        if self.set_email_settings():
482
 
          TestEmail(self._email_accounts.accounts, self).exec_()
483
 
 
484
 
    def test_email_settings(self, to):
485
 
        opts = smtp_prefs().parse()
486
 
        from calibre.utils.smtp import sendmail, create_mail
487
 
        buf = cStringIO.StringIO()
488
 
        oout, oerr = sys.stdout, sys.stderr
489
 
        sys.stdout = sys.stderr = buf
490
 
        tb = None
491
 
        try:
492
 
            msg = create_mail(opts.from_, to, 'Test mail from calibre',
493
 
                    'Test mail from calibre')
494
 
            sendmail(msg, from_=opts.from_, to=[to],
495
 
                verbose=3, timeout=30, relay=opts.relay_host,
496
 
                username=opts.relay_username,
497
 
                password=unhexlify(opts.relay_password),
498
 
                encryption=opts.encryption, port=opts.relay_port)
499
 
        except:
500
 
            import traceback
501
 
            tb = traceback.format_exc()
502
 
            tb += '\n\nLog:\n' + buf.getvalue()
503
 
        finally:
504
 
            sys.stdout, sys.stderr = oout, oerr
505
 
        return tb
506
501
 
507
502
    def add_plugin(self):
508
503
        path = unicode(self.plugin_path.text())
525
520
        index = self.plugin_view.currentIndex()
526
521
        if index.isValid():
527
522
            plugin = self._plugin_model.index_to_plugin(index)
528
 
            if not plugin.can_be_disabled:
529
 
                error_dialog(self,_('Plugin cannot be disabled'),
530
 
                             _('The plugin: %s cannot be disabled')%plugin.name).exec_()
531
 
                return
532
523
            if op == 'toggle':
 
524
                if not plugin.can_be_disabled:
 
525
                    error_dialog(self,_('Plugin cannot be disabled'),
 
526
                                 _('The plugin: %s cannot be disabled')%plugin.name).exec_()
 
527
                    return
533
528
                if is_disabled(plugin):
534
529
                    enable_plugin(plugin)
535
530
                else:
540
535
                    info_dialog(self, _('Plugin not customizable'),
541
536
                        _('Plugin: %s does not need customization')%plugin.name).exec_()
542
537
                    return
543
 
                help = plugin.customization_help()
544
 
                text, ok = QInputDialog.getText(self, _('Customize %s')%plugin.name,
545
 
                                                help)
546
 
                if ok:
547
 
                    customize_plugin(plugin, unicode(text))
 
538
                if hasattr(plugin, 'config_widget'):
 
539
                    config_dialog = QDialog(self)
 
540
                    button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
 
541
 
 
542
                    config_dialog.connect(button_box, SIGNAL('accepted()'), config_dialog.accept)
 
543
                    config_dialog.connect(button_box, SIGNAL('rejected()'), config_dialog.reject)
 
544
 
 
545
                    config_widget = plugin.config_widget()
 
546
                    v = QVBoxLayout(config_dialog)
 
547
                    v.addWidget(config_widget)
 
548
                    v.addWidget(button_box)
 
549
                    config_dialog.exec_()
 
550
 
 
551
                    if config_dialog.result() == QDialog.Accepted:
 
552
                        plugin.save_settings(config_widget)
 
553
                        self._plugin_model.refresh_plugin(plugin)
 
554
                else:
 
555
                    help = plugin.customization_help()
 
556
                    sc = plugin_customization(plugin)
 
557
                    if not sc:
 
558
                        sc = ''
 
559
                    sc = sc.strip()
 
560
                    text, ok = QInputDialog.getText(self, _('Customize %s')%plugin.name,
 
561
                                                    help, QLineEdit.Normal, sc)
 
562
                    if ok:
 
563
                        customize_plugin(plugin, unicode(text).strip())
548
564
                    self._plugin_model.refresh_plugin(plugin)
549
565
            if op == 'remove':
550
566
                if remove_plugin(plugin):
555
571
                         plugin.name + _(' cannot be removed. It is a '
556
572
                         'builtin plugin. Try disabling it instead.')).exec_()
557
573
 
 
574
    def up_input(self):
 
575
        idx = self.input_order.currentRow()
 
576
        if idx > 0:
 
577
            self.input_order.insertItem(idx-1, self.input_order.takeItem(idx))
 
578
            self.input_order.setCurrentRow(idx-1)
 
579
 
 
580
    def down_input(self):
 
581
        idx = self.input_order.currentRow()
 
582
        if idx < self.input_order.count()-1:
 
583
            self.input_order.insertItem(idx+1, self.input_order.takeItem(idx))
 
584
            self.input_order.setCurrentRow(idx+1)
558
585
 
559
586
    def up_column(self):
560
587
        idx = self.columns.currentRow()
630
657
 
631
658
    def browse(self):
632
659
        dir = choose_dir(self, 'database location dialog',
633
 
                         _('Select database location'))
 
660
                         _('Select location for books'))
634
661
        if dir:
635
662
            self.location.setText(dir)
636
663
 
652
679
            return
653
680
        if not self.set_email_settings():
654
681
            return
 
682
        if not self.conversion_options.commit():
 
683
            return
655
684
        config['use_roman_numerals_for_series_number'] = bool(self.roman_numerals.isChecked())
656
685
        config['new_version_notification'] = bool(self.new_version_notification.isChecked())
657
686
        prefs['network_timeout'] = int(self.timeout.value())
658
687
        path = qstring_to_unicode(self.location.text())
 
688
        input_cols = [unicode(self.input_order.item(i).data(Qt.UserRole).toString()) for i in range(self.input_order.count())]
 
689
        prefs['input_format_order'] = input_cols
659
690
        cols = [unicode(self.columns.item(i).data(Qt.UserRole).toString()) for i in range(self.columns.count()) if self.columns.item(i).checkState()==Qt.Checked]
660
691
        if not cols:
661
692
            cols = ['title']
669
700
        p = {0:'normal', 1:'high', 2:'low'}[self.priority.currentIndex()]
670
701
        prefs['worker_process_priority'] = p
671
702
        prefs['read_file_metadata'] = bool(self.pdf_metadata.isChecked())
672
 
        config['save_to_disk_single_format'] = self.book_exts[self.single_format.currentIndex()]
 
703
        prefs['output_format'] = unicode(self.output_format.currentText()).upper()
673
704
        config['cover_flow_queue_length'] = self.cover_browse.value()
674
705
        prefs['language'] = str(self.language.itemData(self.language.currentIndex()).toString())
675
706
        config['systray_icon'] = self.systray_icon.checkState() == Qt.Checked
681
712
        sc.set('max_cover', mcs)
682
713
        config['delete_news_from_library_on_upload'] = self.delete_news.isChecked()
683
714
        config['upload_news_to_device'] = self.sync_news.isChecked()
 
715
        config['search_as_you_type'] = self.search_as_you_type.isChecked()
684
716
        fmts = []
685
717
        for i in range(self.viewer.count()):
686
718
            if self.viewer.item(i).checkState() == Qt.Checked: