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

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-07-30 12:49:41 UTC
  • mto: This revision was merged to the branch mainline in revision 13.
  • Revision ID: james.westby@ubuntu.com-20090730124941-kviipg9ypwgppulc
Tags: upstream-0.6.3+dfsg
ImportĀ upstreamĀ versionĀ 0.6.3+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
from __future__ import with_statement
2
1
__license__   = 'GPL v3'
3
2
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
 
3
 
4
4
'''
5
5
The dialog used to edit meta information for a book as well as
6
6
add/remove formats
7
7
'''
8
 
import os, time, traceback
9
 
 
10
 
from PyQt4.QtCore import SIGNAL, QObject, QCoreApplication, Qt, QTimer, QThread
11
 
from PyQt4.QtGui import QPixmap, QListWidgetItem, QErrorMessage, QDialog, QCompleter
12
 
 
 
8
 
 
9
import os
 
10
import re
 
11
import time
 
12
import traceback
 
13
from datetime import datetime
 
14
 
 
15
from PyQt4.QtCore import SIGNAL, QObject, QCoreApplication, Qt, QTimer, QThread, QDate
 
16
from PyQt4.QtGui import QPixmap, QListWidgetItem, QErrorMessage, QDialog
13
17
 
14
18
from calibre.gui2 import qstring_to_unicode, error_dialog, file_icon_provider, \
15
 
                           choose_files, pixmap_to_data, choose_images, ResizableDialog
 
19
                           choose_files, choose_images, ResizableDialog
16
20
from calibre.gui2.dialogs.metadata_single_ui import Ui_MetadataSingleDialog
17
21
from calibre.gui2.dialogs.fetch_metadata import FetchMetadata
18
22
from calibre.gui2.dialogs.tag_editor import TagEditor
76
80
        QListWidgetItem.__init__(self, file_icon_provider().icon_from_ext(ext),
77
81
                                 text, parent, QListWidgetItem.UserType)
78
82
 
79
 
class AuthorCompleter(QCompleter):
80
 
 
81
 
    def __init__(self, db):
82
 
        all_authors = db.all_authors()
83
 
        all_authors.sort(cmp=lambda x, y : cmp(x[1], y[1]))
84
 
        QCompleter.__init__(self, [x[1] for x in all_authors])
85
 
 
86
83
class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
87
84
 
88
85
    COVER_FETCH_TIMEOUT = 240 # seconds
91
88
        pix = QPixmap(':/images/book.svg')
92
89
        self.cover.setPixmap(pix)
93
90
        self.cover_changed = True
 
91
        self.cover_data = None
94
92
 
95
93
    def select_cover(self, checked):
96
94
        files = choose_images(self, 'change cover dialog',
124
122
                    self.cover.setPixmap(pix)
125
123
                    self.cover_changed = True
126
124
                    self.cpixmap = pix
 
125
                    self.cover_data = cover
127
126
 
128
127
 
129
128
    def add_format(self, x):
159
158
        row = self.formats.currentRow()
160
159
        fmt = self.formats.item(row)
161
160
        if fmt is None:
162
 
            error_dialog(self, _('No format selected'),
 
161
            if self.formats.count() == 1:
 
162
                fmt = self.formats.item(0)
 
163
            if fmt is None:
 
164
                error_dialog(self, _('No format selected'),
163
165
                    _('No format selected')).exec_()
164
 
            return
 
166
                return
165
167
        ext = fmt.ext.lower()
166
168
        if fmt.path is None:
167
169
            stream = self.db.format(self.row, ext, as_file=True)
191
193
        self.cover.setPixmap(pix)
192
194
        self.cover_changed = True
193
195
        self.cpixmap = pix
 
196
        self.cover_data = cdata
194
197
 
195
198
    def sync_formats(self):
196
199
        old_extensions, new_extensions, paths = set(), set(), {}
226
229
        self.cover_changed = False
227
230
        self.cpixmap = None
228
231
        self.cover.setAcceptDrops(True)
229
 
        self._author_completer = AuthorCompleter(self.db)
230
 
        self.authors.setCompleter(self._author_completer)
231
 
        self.connect(self.cover, SIGNAL('cover_changed()'), self.cover_dropped)
 
232
        self.pubdate.setMinimumDate(QDate(100,1,1))
 
233
        self.connect(self.cover, SIGNAL('cover_changed(PyQt_PyObject)'), self.cover_dropped)
232
234
        QObject.connect(self.cover_button, SIGNAL("clicked(bool)"), \
233
235
                                                    self.select_cover)
234
236
        QObject.connect(self.add_format_button, SIGNAL("clicked(bool)"), \
246
248
                        self.remove_unused_series)
247
249
        QObject.connect(self.auto_author_sort, SIGNAL('clicked()'),
248
250
                        self.deduce_author_sort)
 
251
        self.connect(self.formats, SIGNAL('itemDoubleClicked(QListWidgetItem*)'),
 
252
                self.show_format)
249
253
        self.connect(self.button_set_cover, SIGNAL('clicked()'), self.set_cover)
250
254
        self.connect(self.reset_cover, SIGNAL('clicked()'), self.do_reset_cover)
251
255
        self.connect(self.swap_button, SIGNAL('clicked()'), self.swap_title_author)
255
259
        if not isbn:
256
260
            isbn = ''
257
261
        self.isbn.setText(isbn)
258
 
        au = self.db.authors(row)
259
 
        if au:
260
 
            au = [a.strip().replace('|', ',') for a in au.split(',')]
261
 
            self.authors.setText(authors_to_string(au))
262
 
        else:
263
 
            self.authors.setText('')
264
262
        aus = self.db.author_sort(row)
265
263
        self.author_sort.setText(aus if aus else '')
266
264
        tags = self.db.tags(row)
267
 
        self.tags.setText(tags if tags else '')
 
265
        self.tags.setText(', '.join(tags.split(',')) if tags else '')
 
266
        self.tags.update_tags_cache(self.db.all_tags())
268
267
        rating = self.db.rating(row)
269
268
        if rating > 0:
270
269
            self.rating.setValue(int(rating/2.))
271
270
        comments = self.db.comments(row)
272
271
        self.comments.setPlainText(comments if comments else '')
273
272
        cover = self.db.cover(row)
 
273
        pubdate = db.pubdate(self.id, index_is_id=True)
 
274
        self.pubdate.setDate(QDate(pubdate.year, pubdate.month,
 
275
            pubdate.day))
274
276
 
275
277
        exts = self.db.formats(row)
276
278
        if exts:
282
284
                Format(self.formats, ext, size)
283
285
 
284
286
 
285
 
        self.initialize_series_and_publisher()
286
 
 
287
 
        self.series_index.setValue(self.db.series_index(row))
 
287
        self.initialize_combos()
 
288
        si = self.db.series_index(row)
 
289
        if si is None:
 
290
            si = 1.0
 
291
        try:
 
292
            self.series_index.setValue(float(si))
 
293
        except:
 
294
            self.series_index.setValue(1.0)
288
295
        QObject.connect(self.series, SIGNAL('currentIndexChanged(int)'), self.enable_series_index)
289
296
        QObject.connect(self.series, SIGNAL('editTextChanged(QString)'), self.enable_series_index)
290
297
 
299
306
            pm.loadFromData(cover)
300
307
            if not pm.isNull():
301
308
                self.cover.setPixmap(pm)
 
309
            self.cover_data = cover
 
310
 
 
311
    def show_format(self, item, *args):
 
312
        fmt = item.ext
 
313
        self.emit(SIGNAL('view_format(PyQt_PyObject)'), fmt)
302
314
 
303
315
    def deduce_author_sort(self):
304
316
        au = unicode(self.authors.text())
 
317
        au = re.sub(r'\s+et al\.$', '', au)
305
318
        authors = string_to_authors(au)
306
319
        self.author_sort.setText(authors_to_sort_string(authors))
307
320
 
311
324
        self.authors.setText(title)
312
325
        self.author_sort.setText('')
313
326
 
314
 
    def cover_dropped(self):
 
327
    def cover_dropped(self, paths):
315
328
        self.cover_changed = True
 
329
        self.cover_data = self.cover.cover_data
 
330
 
 
331
    def initialize_combos(self):
 
332
        self.initalize_authors()
 
333
        self.initialize_series()
 
334
        self.initialize_publisher()
 
335
 
 
336
        self.layout().activate()
 
337
 
 
338
    def initalize_authors(self):
 
339
        all_authors = self.db.all_authors()
 
340
        all_authors.sort(cmp=lambda x, y : cmp(x[1], y[1]))
 
341
        for i in all_authors:
 
342
            id, name = i
 
343
            name = [name.strip().replace('|', ',') for n in name.split(',')]
 
344
            self.authors.addItem(authors_to_string(name))
 
345
 
 
346
        au = self.db.authors(self.row)
 
347
        if not au:
 
348
            au = _('Unknown')
 
349
        au = ' & '.join([a.strip().replace('|', ',') for a in au.split(',')])
 
350
        self.authors.setEditText(au)
316
351
 
317
352
    def initialize_series(self):
318
353
        self.series.setSizeAdjustPolicy(self.series.AdjustToContentsOnFirstShow)
332
367
            self.series.setCurrentIndex(idx)
333
368
            self.enable_series_index()
334
369
 
335
 
    def initialize_series_and_publisher(self):
336
 
        self.initialize_series()
 
370
    def initialize_publisher(self):
337
371
        all_publishers = self.db.all_publishers()
338
372
        all_publishers.sort(cmp=lambda x, y : cmp(x[1], y[1]))
339
373
        publisher_id = self.db.publisher_id(self.row)
349
383
        if idx is not None:
350
384
            self.publisher.setCurrentIndex(idx)
351
385
 
352
 
 
353
 
        self.layout().activate()
354
 
 
355
386
    def edit_tags(self):
356
387
        d = TagEditor(self, self.db, self.row)
357
388
        d.exec_()
358
389
        if d.result() == QDialog.Accepted:
359
390
            tag_string = ', '.join(d.tags)
360
391
            self.tags.setText(tag_string)
 
392
            self.tags.update_tags_cache(self.db.all_tags())
361
393
 
362
394
    def fetch_cover(self):
363
 
        isbn   = unicode(self.isbn.text()).strip()
 
395
        isbn   = re.sub(r'[^0-9a-zA-Z]', '', unicode(self.isbn.text())).strip()
364
396
        self.fetch_cover_button.setEnabled(False)
365
397
        self.setCursor(Qt.WaitCursor)
366
398
        title, author = map(unicode, (self.title.text(), self.authors.text()))
406
438
                self.cover.setPixmap(pix)
407
439
                self.cover_changed = True
408
440
                self.cpixmap = pix
 
441
                self.cover_data = self.cover_fetcher.cover_data
409
442
        finally:
410
443
            self.fetch_cover_button.setEnabled(True)
411
444
            self.unsetCursor()
413
446
 
414
447
 
415
448
    def fetch_metadata(self):
416
 
        isbn   = qstring_to_unicode(self.isbn.text())
 
449
        isbn   = re.sub(r'[^0-9a-zA-Z]', '', unicode(self.isbn.text()))
417
450
        title  = qstring_to_unicode(self.title.text())
418
451
        author = string_to_authors(unicode(self.authors.text()))[0]
419
452
        publisher = qstring_to_unicode(self.publisher.currentText())
429
462
                        if book.author_sort: self.author_sort.setText(book.author_sort)
430
463
                        if book.publisher: self.publisher.setEditText(book.publisher)
431
464
                        if book.isbn: self.isbn.setText(book.isbn)
 
465
                        if book.pubdate:
 
466
                            d = book.pubdate
 
467
                            self.pubdate.setDate(QDate(d.year, d.month, d.day))
432
468
                        summ = book.comments
433
469
                        if summ:
434
470
                            prefix = qstring_to_unicode(self.comments.toPlainText())
456
492
 
457
493
 
458
494
    def accept(self):
459
 
        if self.formats_changed:
460
 
            self.sync_formats()
461
 
        title = qstring_to_unicode(self.title.text())
 
495
        try:
 
496
            if self.formats_changed:
 
497
                self.sync_formats()
 
498
            title = unicode(self.title.text())
 
499
        except IOError, err:
 
500
            if err.errno == 13: # Permission denied
 
501
                fname = err.filename if err.filename else 'file'
 
502
                return error_dialog(self, _('Permission denied'),
 
503
                        _('Could not open %s. Is it being used by another'
 
504
                        ' program?')%fname, show=True)
 
505
            raise
462
506
        self.db.set_title(self.id, title, notify=False)
463
507
        au = unicode(self.authors.text())
464
508
        if au:
466
510
        aus = qstring_to_unicode(self.author_sort.text())
467
511
        if aus:
468
512
            self.db.set_author_sort(self.id, aus, notify=False)
469
 
        self.db.set_isbn(self.id, qstring_to_unicode(self.isbn.text()), notify=False)
 
513
        self.db.set_isbn(self.id,
 
514
                 re.sub(r'[^0-9a-zA-Z]', '', unicode(self.isbn.text())), notify=False)
470
515
        self.db.set_rating(self.id, 2*self.rating.value(), notify=False)
471
516
        self.db.set_publisher(self.id, qstring_to_unicode(self.publisher.currentText()), notify=False)
472
517
        self.db.set_tags(self.id, qstring_to_unicode(self.tags.text()).split(','), notify=False)
473
518
        self.db.set_series(self.id, qstring_to_unicode(self.series.currentText()), notify=False)
474
519
        self.db.set_series_index(self.id, self.series_index.value(), notify=False)
475
520
        self.db.set_comment(self.id, qstring_to_unicode(self.comments.toPlainText()), notify=False)
476
 
        if self.cover_changed:
477
 
            self.db.set_cover(self.id, pixmap_to_data(self.cover.pixmap()))
 
521
        d = self.pubdate.date()
 
522
        self.db.set_pubdate(self.id, datetime(d.year(), d.month(), d.day()))
 
523
 
 
524
        if self.cover_changed and self.cover_data is not None:
 
525
            self.db.set_cover(self.id, self.cover_data)
478
526
        QDialog.accept(self)
479
527
        if callable(self.accepted_callback):
480
528
            self.accepted_callback(self.id)
 
529
 
 
530
    def reject(self, *args):
 
531
        cf = getattr(self, 'cover_fetcher', None)
 
532
        if cf is not None and hasattr(cf, 'terminate'):
 
533
            cf.terminate()
 
534
            cf.wait()
 
535
 
 
536
        QDialog.reject(self, *args)